diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..4d8fc4c --- /dev/null +++ b/ChangeLog @@ -0,0 +1,80 @@ +Version 1.1.2 : 2008-12-23 +- First public release +Version 1.1.3 : 2009-01-18 +- Added CoE, RxPDO and TxPDO (still Beta) +- Added FoE, Read and Write (still Beta) +- Fixed BigEndian conversion missing in ethercatconfig.c (credit:Serge Bloch) +- Fixed segmented transfer bug in ethercatcoe.c +Version 1.1.4 : 2009-04-22 +- Changed FMMU configuration algorithm +- Changed ec_slave structure around SM and FMMU storage +- Added SYNC1 configuration +- Fixed bug in FoE write +Version 1.2.0 : 2009-09-12 +- Changed the license to GPLv2 only +- Added note to usage terms (please read carefully) +- Eeprom acces is released to slave after preop +- Fixed linux-64 define bug (uint32 and int32) +- Fixed maximum frame size +Version 1.2.2 : 2010-02-22 +- Fixed bugs in ec_adddatagram. +- Fixed several bugs in CoE object dictionary read functions. +- Fixed bug in PDO mapping read function. +- Changed ec_slave structure around topology and delay variables. +- Added several constants in ethercattype.c +Version 1.2.3 : 2010-03-07 +- Clear SM enable if size is 0, even if enable is set in SII. +- Fixed bug in DC propagation delay calculation. Branches with only non DC slaves now correctly close root port. +- Fixed bug in ec_receive_processdata(), wkc now checks for EC_NOFRAME instead of 0. +- Fixed bug in makefile +Version 1.2.4 : 2010-04-10 +- Added SoE, servo over EtherCAT support. +- Added SoE read request and write request. +- Added SoE segmented transfers. +- Added SoE error response. +- Added SoE errors to print module. +- Added Auto config of SoE process data. +Version 1.2.5 : 2011-06-13 +- Added eepromtool, it can read and write the ESC eeprom of a designated slave. +- Rewrite of eeprom read/write functions. +- Added infrastructure change to allow slave groups. +- Added recovery and reconfiguration of slaves after connection loss. +- Improved CoE PDO assignment read from slaves, no longer assume assign indexes as functionally fixed. +- Fixed bugs in ec_config_map(). +- Added EC_STATE_BOOT constant. +- Fixed mailbox size bug, In and Out mailbox can now be of different size. +- Fixed SM type bug. +- Fixed FoE bugs. +- Fixed siigetbyte() unaligned copy. +- Fixed bug in nicdrv.c, socket handles are 0 included. +- Fixed bug in ethercatconfig.c causing memory corruption. +Version 1.2.8 : 2012-06-14 +- Changed directory structure. +- Changed make file. +- Moved hardware / OS dependend part in separate directories. +- Added firm_update tool to upload firmware to slaves in Boot state, use with care. +- Added DC for LRD/LWR case. +- Separated expectedWKC to inputsWKC and outputsWKC. +- Added PreOP->SafeOP hooks in configuration functions. +- With CoE use expedited download if mailbox size is very small and object <= 4 bytes. +- Fixed NetX mailbox configuration behaviour. +- Fixed FoE write bug. +- Added mailbox error handling. +- Fixed SII string read bug. +- Fixed bug in table lookup for printing +- Rewrite of ec_recover_slave() and ec_reconfigure_slave() +- Added -map option in slaveinfo, shows SOEM IO mapping of all slaves found. +Version 1.3.0 : 2013-02-24 +- Added win32 target. +- Added rtk target. +- Compiles under gcc / visual-c / borland-c. +- Multiple port support. One master can run concurrent stacks on multiple network ports. +- All global vars are encapsulated in context struct. +- All timing abstracted in osal.c. +- Linux timing converted to get_clock(CLOCK_MONOTONIC). +- Error messages updated to latest ETG1020 document. +- FoE transfers now support busy response. +- Fixed NetX100 configuration behaviour. +- Fixed linux gettimeofday() to get_clock(). +- Fixed eeprom cache flush on reinit. +- Fixed make for new gcc linker version. \ No newline at end of file diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..4a2ff76 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1849 @@ +# Doxyfile 1.8.1.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or 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 = SOEM + +# 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 = v1.3.0 + +# 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 = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful 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 = 8 + +# 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 = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, 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 + +# 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 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 = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE 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 and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +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. + +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 = 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 (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +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 (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = 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 = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# 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 sectionname ... \endif. + +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 = 60 + +# 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 = 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 is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. 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. + +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 = doc/tutorial.txt \ + doc/soem.dox \ + soem \ + test/linux/ebox \ + test/linux/eepromtool \ + test/linux/red_test \ + test/linux/simple_test \ + test/linux/slaveinfo + +# 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 = *.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 \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL \ + *.inc + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should 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 = doc/images + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty 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 = + +#--------------------------------------------------------------------------- +# 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 = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. 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 the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_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 = NO + +# 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 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://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# 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 = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# 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 a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# 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 = + +# 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 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 + +# 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 = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the 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 +# managable. 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 = 1000 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# 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/LICENSE b/LICENSE deleted file mode 100644 index d7f1051..0000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6496ee3 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +#***************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +include $(PRJ_ROOT)/make/subdir.mk diff --git a/README b/README new file mode 100644 index 0000000..8829df4 --- /dev/null +++ b/README @@ -0,0 +1,27 @@ +To compile for linux: + +go to project directory + +source ./setup.sh linux + +make all + +Please read the doxygen documentation in doc/html/index.html + +-------------------------------------------------------------- + +To complie for windows: + +go to project directory + +Build soem libary make_libsoem_lib.bat + +Ex: make_libsoem_lib.bat "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC" x86 + +Build test folder make_test_win32.bat + +Ex: make_test_win32.bat "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC" x86 + +Test: slavinfo.exe . slaveinfo.exe will print the \Device\NPF_{xxxxxx}'s +Ex. slaveinfo.exe \Device\NPF_{735D4B45-68D6-47A6-B826-E0DA26AC761A} + diff --git a/README.md b/README.md deleted file mode 100644 index 45a946a..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -soem - -Be patient, there will soon be lots of information, code and other stuff to download! diff --git a/TODO.tasks b/TODO.tasks new file mode 100644 index 0000000..d1fa282 --- /dev/null +++ b/TODO.tasks @@ -0,0 +1,6 @@ + + + + + + diff --git a/clean_libsoem_lib.bat b/clean_libsoem_lib.bat new file mode 100644 index 0000000..07900a1 --- /dev/null +++ b/clean_libsoem_lib.bat @@ -0,0 +1,10 @@ +@echo off + +if NOT EXIST obj goto skip_obj +RMDIR /S /Q obj +:skip_obj +if NOT EXIST lib\win32 goto skip_lib +RMDIR /S /Q lib\win32 +:skip_lib + +echo clean done \ No newline at end of file diff --git a/clean_test_win32.bat b/clean_test_win32.bat new file mode 100644 index 0000000..5aeb0db --- /dev/null +++ b/clean_test_win32.bat @@ -0,0 +1,54 @@ +@echo off + +REM Build slave info +if NOT EXIST test\win32\slaveinfo\obj goto skip_obj +RMDIR /S /Q test\win32\slaveinfo\obj +:skip_obj +if NOT EXIST test\win32\slaveinfo\*.exe goto skip_exe +DEL /Q test\win32\slaveinfo\*.exe +:skip_exe +if NOT EXIST test\win32\slaveinfo\*.ilk goto skip_ilk +DEL /Q test\win32\slaveinfo\*.ilk +:skip_ilk +if NOT EXIST test\win32\slaveinfo\*.pdb goto skip_pdb +DEL /Q test\win32\slaveinfo\*.pdb +:skip_pdb +if NOT EXIST test\win32\slaveinfo\*.idb goto skip_idb +DEL /Q test\win32\slaveinfo\*.idb +:skip_idb + +REM Simple_test info +if NOT EXIST test\win32\simple_test\obj goto skip_obj2 +RMDIR /S /Q test\win32\simple_test\obj +:skip_obj2 +if NOT EXIST test\win32\simple_test\*.exe goto skip_exe2 +DEL /Q test\win32\simple_test\*.exe +:skip_exe2 +if NOT EXIST test\win32\simple_test\*.ilk goto skip_ilk2 +DEL /Q test\win32\simple_test\*.ilk +:skip_ilk2 +if NOT EXIST test\win32\simple_test\*.pdb goto skip_pdb2 +DEL /Q test\win32\simple_test\*.pdb +:skip_pdb2 +if NOT EXIST test\win32\simple_test\*.idb goto skip_idb2 +DEL /Q test\win32\simple_test\*.idb +:skip_idb2 + +REM eepromtool info +if NOT EXIST test\win32\eepromtool\obj goto skip_obj3 +RMDIR /S /Q test\win32\eepromtool\obj +:skip_obj3 +if NOT EXIST test\win32\eepromtool\*.exe goto skip_exe3 +DEL /Q test\win32\eepromtool\*.exe +:skip_exe3 +if NOT EXIST test\win32\eepromtool\*.ilk goto skip_ilk3 +DEL /Q test\win32\eepromtool\*.ilk +:skip_ilk3 +if NOT EXIST test\win32\eepromtool\*.pdb goto skip_pdb3 +DEL /Q test\win32\eepromtool\*.pdb +:skip_pdb3 +if NOT EXIST test\win32\eepromtool\*.idb goto skip_idb3 +DEL /Q test\win32\eepromtool\*.idb +:skip_idb3 + +echo clean done \ No newline at end of file diff --git a/doc/html/annotated.html b/doc/html/annotated.html new file mode 100644 index 0000000..cdc347e --- /dev/null +++ b/doc/html/annotated.html @@ -0,0 +1,103 @@ + + + + + + +SOEM: Data Structures + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+
+
Data Structures
+
+ + + + + diff --git a/doc/html/bc_s.png b/doc/html/bc_s.png new file mode 100644 index 0000000..224b29a Binary files /dev/null and b/doc/html/bc_s.png differ diff --git a/doc/html/bdwn.png b/doc/html/bdwn.png new file mode 100644 index 0000000..940a0b9 Binary files /dev/null and b/doc/html/bdwn.png differ diff --git a/doc/html/classes.html b/doc/html/classes.html new file mode 100644 index 0000000..bd19542 --- /dev/null +++ b/doc/html/classes.html @@ -0,0 +1,75 @@ + + + + + + +SOEM: Data Structure Index + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+
+
Data Structure Index
+
+
+
E | I | O
+ + + + + + + + + + + + +
  E  
+
ec_eepromt   ec_mbxerrort   ec_SMcommtypet   
  I  
+
ec_emcyt   ec_mbxheadert   ec_smt   
ec_adapter   ec_eringt   ec_ODlistt   ec_SoEattributet   in_EBOX_streamt   
ec_ALstatuscodelist_t   ec_errort   ec_OElistt   ec_soeerrorlist_t   in_EBOXt   
ec_alstatust   ec_etherheadert   ec_PDOassignt   ec_SoElistt   
  O  
+
ec_comt   ec_fmmut   ec_PDOdesct   ec_SoEmappingt   
ec_configlist_t   ec_FOEt   ec_sdoerrorlist_t   ec_SoEnamet   out_EBOX_streamt   
ec_eepromFMMUt   ec_groupt   ec_SDOservicet   ec_SoEt   out_EBOXt   
ec_eepromPDOt   ec_idxstackT   ec_SDOt   ec_state_status   
ec_eepromSMt   ec_mbxerrorlist_t   ec_slavet   ecx_contextt   
+
E | I | O
+
+ + + + diff --git a/doc/html/closed.png b/doc/html/closed.png new file mode 100644 index 0000000..98cc2c9 Binary files /dev/null and b/doc/html/closed.png differ diff --git a/doc/html/doxygen.css b/doc/html/doxygen.css new file mode 100644 index 0000000..dabaff2 --- /dev/null +++ b/doc/html/doxygen.css @@ -0,0 +1,1184 @@ +/* The standard CSS for doxygen 1.8.3.1 */ + +body, table, div, p, dl { + font: 400 14px/19px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + 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, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +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; + margin: 4px; + 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.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 { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 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 when not used as main index */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + 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; +} + +.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; +} + +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 { + 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: 5px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 2px; +} + +.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; +} + +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; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 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; +} + +@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/html/doxygen.png b/doc/html/doxygen.png new file mode 100644 index 0000000..3ff17d8 Binary files /dev/null and b/doc/html/doxygen.png differ diff --git a/doc/html/dynsections.js b/doc/html/dynsections.js new file mode 100644 index 0000000..ed092c7 --- /dev/null +++ b/doc/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 + + + + + +SOEM: ebox.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ebox.c File Reference
+
+
+ +

Example code for Simple Open EtherCAT master. +More...

+
#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sched.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <math.h>
+#include "ethercattype.h"
+#include "nicdrv.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatcoe.h"
+#include "ethercatconfig.h"
+#include "ethercatdc.h"
+
+ + + + + + + + + +

+Data Structures

struct  in_EBOXt
 
struct  in_EBOX_streamt
 
struct  out_EBOXt
 
struct  out_EBOX_streamt
 
+ + + + + + + +

+Macros

#define NSEC_PER_SEC   1000000000
 
#define MAXSTREAM   200000
 
#define SYNC0TIME   8000
 
+ + + + + + + + + + + + + +

+Functions

int output_cvs (char *fname, int length)
 
void eboxtest (char *ifname)
 
void add_timespec (struct timespec *ts, int64 addtime)
 
void ec_sync (int64 reftime, int64 cycletime, int64 *offsettime)
 
void ecatthread (void *ptr)
 
int main (int argc, char *argv[])
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Variables

struct sched_param schedp
 
char IOmap [4096]
 
pthread_t thread1
 
struct timeval tv t1 t2
 
int dorun = 0
 
int deltat
 
int tmax =0
 
int64 toff
 
int DCdiff
 
int os
 
uint32 ob
 
int16 ob2
 
uint8 ob3
 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER
 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
 
int64 integral =0
 
uint32 cyclecount
 
in_EBOX_streamtin_EBOX
 
out_EBOX_streamtout_EBOX
 
double ain [2]
 
int ainc
 
int streampos
 
int16 stream1 [MAXSTREAM]
 
int16 stream2 [MAXSTREAM]
 
+

Detailed Description

+

Example code for Simple Open EtherCAT master.

+

Usage : ebox [ifname] [cycletime] ifname is NIC interface, f.e. eth0 cycletime in us, f.e. 500

+

This test is specifically build for the E/BOX.

+

(c)Arthur Ketels 2011

+

Macro Definition Documentation

+ +
+
+ + + + +
#define MAXSTREAM   200000
+
+ +
+
+ +
+
+ + + + +
#define NSEC_PER_SEC   1000000000
+
+ +
+
+ +
+
+ + + + +
#define SYNC0TIME   8000
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void add_timespec (struct timespec * ts,
int64 addtime 
)
+
+ +
+
+ +
+
+ + + + + + + + +
void eboxtest (char * ifname)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ec_sync (int64 reftime,
int64 cycletime,
int64 * offsettime 
)
+
+ +
+
+ +
+
+ + + + + + + + +
void ecatthread (void * ptr)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int output_cvs (char * fname,
int length 
)
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
double ain[2]
+
+ +
+
+ +
+
+ + + + +
int ainc
+
+ +
+
+ +
+
+ + + + +
pthread_cond_t cond = PTHREAD_COND_INITIALIZER
+
+ +
+
+ +
+
+ + + + +
uint32 cyclecount
+
+ +
+
+ +
+
+ + + + +
int DCdiff
+
+ +
+
+ +
+
+ + + + +
int deltat
+
+ +
+
+ +
+
+ + + + +
int dorun = 0
+
+ +
+
+ +
+
+ + + + +
in_EBOX_streamt* in_EBOX
+
+ +
+
+ +
+
+ + + + +
int64 integral =0
+
+ +
+
+ +
+
+ + + + +
char IOmap[4096]
+
+ +
+
+ +
+
+ + + + +
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
+
+ +
+
+ +
+
+ + + + +
uint32 ob
+
+ +
+
+ +
+
+ + + + +
int16 ob2
+
+ +
+
+ +
+
+ + + + +
uint8 ob3
+
+ +
+
+ +
+
+ + + + +
int os
+
+ +
+
+ +
+
+ + + + +
out_EBOX_streamt* out_EBOX
+
+ +
+
+ +
+
+ + + + +
struct sched_param schedp
+
+ +
+
+ +
+
+ + + + +
int16 stream1[MAXSTREAM]
+
+ +
+
+ +
+
+ + + + +
int16 stream2[MAXSTREAM]
+
+ +
+
+ +
+
+ + + + +
int streampos
+
+ +
+
+ +
+
+ + + + +
struct timeval tv t1 t2
+
+ +
+
+ +
+
+ + + + +
pthread_t thread1
+
+ +
+
+ +
+
+ + + + +
int tmax =0
+
+ +
+
+ +
+
+ + + + +
int64 toff
+
+ +
+
+
+ + + + diff --git a/doc/html/eepromtool_8c.html b/doc/html/eepromtool_8c.html new file mode 100644 index 0000000..8c274c7 --- /dev/null +++ b/doc/html/eepromtool_8c.html @@ -0,0 +1,752 @@ + + + + + + +SOEM: eepromtool.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
eepromtool.c File Reference
+
+
+ +

EEprom tool for Simple Open EtherCAT master. +More...

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+#include "ethercattype.h"
+#include "nicdrv.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatcoe.h"
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

#define MAXBUF   32768
 
#define STDBUF   2048
 
#define MINBUF   128
 
#define CRCBUF   14
 
#define MODE_NONE   0
 
#define MODE_READBIN   1
 
#define MODE_READINTEL   2
 
#define MODE_WRITEBIN   3
 
#define MODE_WRITEINTEL   4
 
#define MODE_WRITEALIAS   5
 
#define MODE_INFO   6
 
#define MAXSLENGTH   256
 
#define IHEXLENGTH   0x20
 
+ + + + + + + + + + + + + + + + + + + + + + + +

+Functions

void calc_crc (uint8 *crc, uint8 b)
 
uint16 SIIcrc (uint8 *buf)
 
int input_bin (char *fname, int *length)
 
int input_intelhex (char *fname, int *start, int *length)
 
int output_bin (char *fname, int length)
 
int output_intelhex (char *fname, int length)
 
int eeprom_read (int slave, int start, int length)
 
int eeprom_write (int slave, int start, int length)
 
int eeprom_writealias (int slave, int alias, uint16 crc)
 
void eepromtool (char *ifname, int slave, int mode, char *fname)
 
int main (int argc, char *argv[])
 
+ + + + + + + + + + + + + + + + + + + + + +

+Variables

uint8 ebuf [MAXBUF]
 
uint8 ob
 
uint16 ow
 
int os
 
int slave
 
int alias
 
struct timeval tstart tend tdif
 
int wkc
 
int mode
 
char sline [MAXSLENGTH]
 
+

Detailed Description

+

EEprom tool for Simple Open EtherCAT master.

+

Usage : eepromtool ifname slave OPTION fname|alias ifname is NIC interface, f.e. eth0 slave = slave number in EtherCAT order 1..n -r read EEPROM, output binary format -ri read EEPROM, output Intel Hex format -w write EEPROM, input binary format -wi write EEPROM, input Intel Hex format -i display EEPROM information -walias write slave alias in EEPROM

+

(c)Arthur Ketels 2010-2012

+

Macro Definition Documentation

+ +
+
+ + + + +
#define CRCBUF   14
+
+ +
+
+ +
+
+ + + + +
#define IHEXLENGTH   0x20
+
+ +
+
+ +
+
+ + + + +
#define MAXBUF   32768
+
+ +
+
+ +
+
+ + + + +
#define MAXSLENGTH   256
+
+ +
+
+ +
+
+ + + + +
#define MINBUF   128
+
+ +
+
+ +
+
+ + + + +
#define MODE_INFO   6
+
+ +
+
+ +
+
+ + + + +
#define MODE_NONE   0
+
+ +
+
+ +
+
+ + + + +
#define MODE_READBIN   1
+
+ +
+
+ +
+
+ + + + +
#define MODE_READINTEL   2
+
+ +
+
+ +
+
+ + + + +
#define MODE_WRITEALIAS   5
+
+ +
+
+ +
+
+ + + + +
#define MODE_WRITEBIN   3
+
+ +
+
+ +
+
+ + + + +
#define MODE_WRITEINTEL   4
+
+ +
+
+ +
+
+ + + + +
#define STDBUF   2048
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void calc_crc (uint8 * crc,
uint8 b 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int eeprom_read (int slave,
int start,
int length 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int eeprom_write (int slave,
int start,
int length 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int eeprom_writealias (int slave,
int alias,
uint16 crc 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void eepromtool (char * ifname,
int slave,
int mode,
char * fname 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int input_bin (char * fname,
int * length 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int input_intelhex (char * fname,
int * start,
int * length 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int output_bin (char * fname,
int length 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int output_intelhex (char * fname,
int length 
)
+
+ +
+
+ +
+
+ + + + + + + + +
uint16 SIIcrc (uint8 * buf)
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
int alias
+
+ +
+
+ +
+
+ + + + +
uint8 ebuf[MAXBUF]
+
+ +
+
+ +
+
+ + + + +
int mode
+
+ +
+
+ +
+
+ + + + +
uint8 ob
+
+ +
+
+ +
+
+ + + + +
int os
+
+ +
+
+ +
+
+ + + + +
uint16 ow
+
+ +
+
+ +
+
+ + + + +
int slave
+
+ +
+
+ +
+
+ + + + +
char sline[MAXSLENGTH]
+
+ +
+
+ +
+
+ + + + +
struct timeval tstart tend tdif
+
+ +
+
+ +
+
+ + + + +
int wkc
+
+ +
+
+
+ + + + diff --git a/doc/html/ethercatbase_8c.html b/doc/html/ethercatbase_8c.html new file mode 100644 index 0000000..7c9e636 --- /dev/null +++ b/doc/html/ethercatbase_8c.html @@ -0,0 +1,2039 @@ + + + + + + +SOEM: ethercatbase.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatbase.c File Reference
+
+
+ +

Base EtherCAT functions. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "oshw.h"
+#include "osal.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

int ecx_setupdatagram (ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ecx_adddatagram (ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ecx_BWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_BRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_APRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_ARMW (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_FRMW (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ecx_APRDw (ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
 
int ecx_FPRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ecx_FPRDw (ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
 
int ecx_APWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_APWRw (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ecx_FPWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_FPWRw (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ecx_LRW (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LRD (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LWR (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LRWDC (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
 
int ec_setupdatagram (void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ec_adddatagram (void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ec_BWR (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_BRD (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_APRD (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_ARMW (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_FRMW (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ec_APRDw (uint16 ADP, uint16 ADO, int timeout)
 
int ec_FPRD (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ec_FPRDw (uint16 ADP, uint16 ADO, int timeout)
 
int ec_APWR (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_APWRw (uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ec_FPWR (uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ec_FPWRw (uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ec_LRW (uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ec_LRD (uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ec_LWR (uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ec_LRWDC (uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
 
+

Detailed Description

+

Base EtherCAT functions.

+

Setting up a datagram in an ethernet frame. EtherCAT datagram primitives, broadcast, auto increment, configured and logical addressed data transfers. All base transfers are blocking, so wait for the frame to be returned to the master or timeout. If this is not acceptable build your own datagrams and use the functions from nicdrv.c.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_adddatagram (void * frame,
uint8 com,
uint8 idx,
boolean more,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_APRD (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_APRDw (uint16 ADP,
uint16 ADO,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_APWR (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_APWRw (uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_ARMW (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_BRD (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_BWR (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FPRD (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_FPRDw (uint16 ADP,
uint16 ADO,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FPWR (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FPWRw (uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FRMW (uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_LRD (uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_LRW (uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_LRWDC (uint32 LogAdr,
uint16 length,
void * data,
uint16 DCrs,
int64 * DCtime,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_LWR (uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_setupdatagram (void * frame,
uint8 com,
uint8 idx,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_adddatagram (ecx_portt * port,
void * frame,
uint8 com,
uint8 idx,
boolean more,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+

Add EtherCAT datagram to a standard ethernet frame with existing datagram(s).

+
Parameters
+ + + + + + + + + + +
[in]port= port context struct
[out]frame= framebuffer
[in]com= command
[in]idx= index used for TX and RX buffers
[in]more= TRUE if still more datagrams to follow
[in]ADP= Address Position
[in]ADO= Address Offset
[in]length= length of datagram excluding EtherCAT header
[in]data= databuffer to be copied in datagram
+
+
+
Returns
Offset to data in rx frame, usefull to retrieve data after RX.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APRD "auto increment address read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 excecutes
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_APRDw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
int timeout 
)
+
+

APRDw "auto increment address read" word return primitive. Blocking.

+
Parameters
+ + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 reads.
[in]ADO= Address Offset, slave memory address
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
word data from slave
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APWR "auto increment address write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 writes.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APWRw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+

APWRw "auto increment address write" word primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 writes.
[in]ADO= Address Offset, slave memory address
[in]data= word data to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_ARMW (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APRMW "auto increment address read, multiple write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 reads, following slaves write.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_BRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

BRD "broadcast read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, normally 0
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_BWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

BRW "broadcast write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, normally 0
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to be written to slaves
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPRD "configured address read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_FPRDw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
int timeout 
)
+
+

FPRDw "configured address read" word return primitive. Blocking.

+
Parameters
+ + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads.
[in]ADO= Address Offset, slave memory address
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
word data from slave
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPWR "configured address write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address writes.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPWRw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+

FPWR "configured address write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address writes.
[in]ADO= Address Offset, slave memory address
[in]data= word to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FRMW (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPRMW "configured address read, multiple write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads, following slaves write.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRD (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LRD "logical memory read" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of bytes to read from slave.
[out]data= databuffer to read from slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRW (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LRW "logical memory read / write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in,out]data= databuffer to write to and read from slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRWDC (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
uint16 DCrs,
int64 * DCtime,
int timeout 
)
+
+

LRW "logical memory read / write" primitive plus Clock Distribution. Blocking. Frame consists of two datagrams, one LRW and one FPRMW.

+
Parameters
+ + + + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in,out]data= databuffer to write to and read from slave.
[in]DCrs= Distributed Clock reference slave address.
[out]DCtime= DC time read from reference slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LWR (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LWR "logical memory write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_setupdatagram (ecx_portt * port,
void * frame,
uint8 com,
uint8 idx,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+

Generate and set EtherCAT datagram in a standard ethernet frame.

+
Parameters
+ + + + + + + + + +
[in]port= port context struct
[out]frame= framebuffer
[in]com= command
[in]idx= index used for TX and RX buffers
[in]ADP= Address Position
[in]ADO= Address Offset
[in]length= length of datagram excluding EtherCAT header
[in]data= databuffer to be copied in datagram
+
+
+
Returns
always 0
+ +
+
+
+ + + + diff --git a/doc/html/ethercatbase_8h.html b/doc/html/ethercatbase_8h.html new file mode 100644 index 0000000..4a4a486 --- /dev/null +++ b/doc/html/ethercatbase_8h.html @@ -0,0 +1,1222 @@ + + + + + + +SOEM: ethercatbase.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatbase.h File Reference
+
+
+ +

Headerfile for ethercatbase.c. +More...

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

+Functions

int ecx_setupdatagram (ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ecx_adddatagram (ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
 
int ecx_BWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_BRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_APRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_ARMW (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_FRMW (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ecx_APRDw (ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
 
int ecx_FPRD (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
uint16 ecx_FPRDw (ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
 
int ecx_APWRw (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ecx_APWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_FPWRw (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
 
int ecx_FPWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
 
int ecx_LRW (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LRD (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LWR (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
 
int ecx_LRWDC (ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
 
+

Detailed Description

+

Headerfile for ethercatbase.c.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_adddatagram (ecx_portt * port,
void * frame,
uint8 com,
uint8 idx,
boolean more,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+

Add EtherCAT datagram to a standard ethernet frame with existing datagram(s).

+
Parameters
+ + + + + + + + + + +
[in]port= port context struct
[out]frame= framebuffer
[in]com= command
[in]idx= index used for TX and RX buffers
[in]more= TRUE if still more datagrams to follow
[in]ADP= Address Position
[in]ADO= Address Offset
[in]length= length of datagram excluding EtherCAT header
[in]data= databuffer to be copied in datagram
+
+
+
Returns
Offset to data in rx frame, usefull to retrieve data after RX.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APRD "auto increment address read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 excecutes
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_APRDw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
int timeout 
)
+
+

APRDw "auto increment address read" word return primitive. Blocking.

+
Parameters
+ + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 reads.
[in]ADO= Address Offset, slave memory address
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
word data from slave
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APWR "auto increment address write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 writes.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_APWRw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+

APWRw "auto increment address write" word primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 writes.
[in]ADO= Address Offset, slave memory address
[in]data= word data to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_ARMW (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

APRMW "auto increment address read, multiple write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, each slave ++, slave that has 0 reads, following slaves write.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_BRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

BRD "broadcast read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, normally 0
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_BWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

BRW "broadcast write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, normally 0
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to be written to slaves
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPRD (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPRD "configured address read" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_FPRDw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
int timeout 
)
+
+

FPRDw "configured address read" word return primitive. Blocking.

+
Parameters
+ + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads.
[in]ADO= Address Offset, slave memory address
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
word data from slave
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPWR (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPWR "configured address write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address writes.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FPWRw (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 data,
int timeout 
)
+
+

FPWR "configured address write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address writes.
[in]ADO= Address Offset, slave memory address
[in]data= word to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FRMW (ecx_portt * port,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data,
int timeout 
)
+
+

FPRMW "configured address read, multiple write" primitive. Blocking.

+
Parameters
+ + + + + + + +
[in]port= port context struct
[in]ADP= Address Position, slave that has address reads, following slaves write.
[in]ADO= Address Offset, slave memory address
[in]length= length of databuffer
[out]data= databuffer to put slave data in
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRD (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LRD "logical memory read" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of bytes to read from slave.
[out]data= databuffer to read from slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRW (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LRW "logical memory read / write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in,out]data= databuffer to write to and read from slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LRWDC (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
uint16 DCrs,
int64 * DCtime,
int timeout 
)
+
+

LRW "logical memory read / write" primitive plus Clock Distribution. Blocking. Frame consists of two datagrams, one LRW and one FPRMW.

+
Parameters
+ + + + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in,out]data= databuffer to write to and read from slave.
[in]DCrs= Distributed Clock reference slave address.
[out]DCtime= DC time read from reference slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_LWR (ecx_portt * port,
uint32 LogAdr,
uint16 length,
void * data,
int timeout 
)
+
+

LWR "logical memory write" primitive. Blocking.

+
Parameters
+ + + + + + +
[in]port= port context struct
[in]LogAdr= Logical memory address
[in]length= length of databuffer
[in]data= databuffer to write to slave.
[in]timeout= timeout in us, standard is EC_TIMEOUTRET
+
+
+
Returns
Workcounter or EC_NOFRAME
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_setupdatagram (ecx_portt * port,
void * frame,
uint8 com,
uint8 idx,
uint16 ADP,
uint16 ADO,
uint16 length,
void * data 
)
+
+

Generate and set EtherCAT datagram in a standard ethernet frame.

+
Parameters
+ + + + + + + + + +
[in]port= port context struct
[out]frame= framebuffer
[in]com= command
[in]idx= index used for TX and RX buffers
[in]ADP= Address Position
[in]ADO= Address Offset
[in]length= length of datagram excluding EtherCAT header
[in]data= databuffer to be copied in datagram
+
+
+
Returns
always 0
+ +
+
+
+ + + + diff --git a/doc/html/ethercatcoe_8c.html b/doc/html/ethercatcoe_8c.html new file mode 100644 index 0000000..e003618 --- /dev/null +++ b/doc/html/ethercatcoe_8c.html @@ -0,0 +1,1396 @@ + + + + + + +SOEM: ethercatcoe.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatcoe.c File Reference
+
+
+ +

CAN over EtherCAT (CoE) module. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "osal.h"
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatcoe.h"
+
+ + + + + +

+Data Structures

struct  ec_SDOt
 
struct  ec_SDOservicet
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

PACKED_END void ecx_SDOerror (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode)
 
static void ecx_SDOinfoerror (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode)
 
int ecx_SDOread (ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, boolean CA, int *psize, void *p, int timeout)
 
int ecx_SDOwrite (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex, boolean CA, int psize, void *p, int Timeout)
 
int ecx_RxPDO (ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize, void *p)
 
int ecx_TxPDO (ecx_contextt *context, uint16 slave, uint16 TxPDOnumber, int *psize, void *p, int timeout)
 
int ecx_readPDOassign (ecx_contextt *context, uint16 Slave, uint16 PDOassign)
 
int ecx_readPDOassignCA (ecx_contextt *context, uint16 Slave, uint16 PDOassign)
 
int ecx_readPDOmap (ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
 
int ecx_readPDOmapCA (ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
 
int ecx_readODlist (ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
 
int ecx_readODdescription (ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist)
 
int ecx_readOEsingle (ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
int ecx_readOE (ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
void ec_SDOerror (uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode)
 
int ec_SDOread (uint16 slave, uint16 index, uint8 subindex, boolean CA, int *psize, void *p, int timeout)
 
int ec_SDOwrite (uint16 Slave, uint16 Index, uint8 SubIndex, boolean CA, int psize, void *p, int Timeout)
 
int ec_RxPDO (uint16 Slave, uint16 RxPDOnumber, int psize, void *p)
 
int ec_TxPDO (uint16 slave, uint16 TxPDOnumber, int *psize, void *p, int timeout)
 
int ec_readPDOassign (uint16 Slave, uint16 PDOassign)
 
int ec_readPDOassignCA (uint16 Slave, uint16 PDOassign)
 
int ec_readPDOmap (uint16 Slave, int *Osize, int *Isize)
 
int ec_readPDOmapCA (uint16 Slave, int *Osize, int *Isize)
 
int ec_readODlist (uint16 Slave, ec_ODlistt *pODlist)
 
int ec_readODdescription (uint16 Item, ec_ODlistt *pODlist)
 
int ec_readOEsingle (uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
int ec_readOE (uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
+

Detailed Description

+

CAN over EtherCAT (CoE) module.

+

SDO read / write and SDO service functions

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_readODdescription (uint16 Item,
ec_ODlisttpODlist 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_readODlist (uint16 Slave,
ec_ODlisttpODlist 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_readOE (uint16 Item,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_readOEsingle (uint16 Item,
uint8 SubI,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_readPDOassign (uint16 Slave,
uint16 PDOassign 
)
+
+

Read PDO assign structure

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_readPDOassignCA (uint16 Slave,
uint16 PDOassign 
)
+
+

Read PDO assign structure in Complete Access mode

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_readPDOmap (uint16 Slave,
int * Osize,
int * Isize 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_readPDOmapCA (uint16 Slave,
int * Osize,
int * Isize 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_RxPDO (uint16 Slave,
uint16 RxPDOnumber,
int psize,
void * p 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ec_SDOerror (uint16 Slave,
uint16 Index,
uint8 SubIdx,
int32 AbortCode 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_SDOread (uint16 slave,
uint16 index,
uint8 subindex,
boolean CA,
int * psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_SDOwrite (uint16 Slave,
uint16 Index,
uint8 SubIndex,
boolean CA,
int psize,
void * p,
int Timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_TxPDO (uint16 slave,
uint16 TxPDOnumber,
int * psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readODdescription (ecx_contexttcontext,
uint16 Item,
ec_ODlisttpODlist 
)
+
+

CoE read Object Description. Adds textual description to object indexes.

+
Parameters
+ + + + +
[in]context= context struct
[in]Item= Item number in ODlist.
[in,out]pODlist= referencing Object Description list.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readODlist (ecx_contexttcontext,
uint16 Slave,
ec_ODlisttpODlist 
)
+
+

CoE read Object Description List.

+
Parameters
+ + + + +
[in]context= context struct
[in]Slave= Slave number.
[out]pODlist= resulting Object Description list.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readOE (ecx_contexttcontext,
uint16 Item,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+

CoE read SDO service object entry.

+
Parameters
+ + + + + +
[in]context= context struct
[in]Item= Item in ODlist.
[in]pODlist= Object description list for reference.
[out]pOElist= resulting object entry structure.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readOEsingle (ecx_contexttcontext,
uint16 Item,
uint8 SubI,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+

CoE read SDO service object entry, single subindex. Used in ec_readOE().

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Item= Item in ODlist.
[in]SubI= Subindex of item in ODlist.
[in]pODlist= Object description list for reference.
[out]pOElist= resulting object entry structure.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOassign (ecx_contexttcontext,
uint16 Slave,
uint16 PDOassign 
)
+
+

Read PDO assign structure

+
Parameters
+ + + + +
[in]context= context struct
[in]Slave= Slave number
[in]PDOassign= PDO assign object
+
+
+
Returns
total bitlength of PDO assign
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOassignCA (ecx_contexttcontext,
uint16 Slave,
uint16 PDOassign 
)
+
+

Read PDO assign structure in Complete Access mode

+
Parameters
+ + + + +
[in]context= context struct
[in]Slave= Slave number
[in]PDOassign= PDO assign object
+
+
+
Returns
total bitlength of PDO assign
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOmap (ecx_contexttcontext,
uint16 Slave,
int * Osize,
int * Isize 
)
+
+

CoE read PDO mapping.

+

CANopen has standard indexes defined for PDO mapping. This function tries to read them and collect a full input and output mapping size of designated slave.

+

Principal structure in slave:
+ 1C00:00 is number of SM defined
+ 1C00:01 SM0 type -> 1C10
+ 1C00:02 SM1 type -> 1C11
+ 1C00:03 SM2 type -> 1C12
+ 1C00:04 SM4 type -> 1C13
+ Type 0 = unused, 1 = mailbox in, 2 = mailbox out, 3 = outputs (RxPDO), 4 = inputs (TxPDO).

+

1C12:00 is number of PDO's defined for SM2
+ 1C12:01 PDO assign SDO #1 -> f.e. 1A00
+ 1C12:02 PDO assign SDO #2 -> f.e. 1A04\

+

1A00:00 is number of object defined for this PDO
+ 1A00:01 object mapping #1, f.e. 60100710 (SDO 6010 SI 07 bitlength 0x10)

+
Parameters
+ + + + + +
[in]context= context struct
[in]Slave= Slave number
[out]Osize= Size in bits of output mapping (rxPDO) found
[out]Isize= Size in bits of input mapping (txPDO) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOmapCA (ecx_contexttcontext,
uint16 Slave,
int * Osize,
int * Isize 
)
+
+

CoE read PDO mapping in Complete Access mode (CA).

+

CANopen has standard indexes defined for PDO mapping. This function tries to read them and collect a full input and output mapping size of designated slave. Slave has to support CA, otherwise use ec_readPDOmap().

+
Parameters
+ + + + + +
[in]context= context struct
[in]Slave= Slave number
[out]Osize= Size in bits of output mapping (rxPDO) found
[out]Isize= Size in bits of input mapping (txPDO) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_RxPDO (ecx_contexttcontext,
uint16 Slave,
uint16 RxPDOnumber,
int psize,
void * p 
)
+
+

CoE RxPDO write, blocking.

+

A RxPDO download request is issued.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]RxPDOnumber= Related RxPDO number
[in]psize= Size in bytes of PDO buffer.
[out]p= Pointer to PDO buffer
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PACKED_END void ecx_SDOerror (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIdx,
int32 AbortCode 
)
+
+

Report SDO error.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index that generated error
[in]SubIdx= Subindex that generated error
[in]AbortCode= Abortcode, see EtherCAT documentation for list
+
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void ecx_SDOinfoerror (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIdx,
int32 AbortCode 
)
+
+static
+
+

Report SDO info error

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index that generated error
[in]SubIdx= Subindex that generated error
[in]AbortCode= Abortcode, see EtherCAT documentation for list
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SDOread (ecx_contexttcontext,
uint16 slave,
uint16 index,
uint8 subindex,
boolean CA,
int * psize,
void * p,
int timeout 
)
+
+

CoE SDO read, blocking. Single subindex or Complete Access.

+

Only a "normal" upload request is issued. If the requested parameter is <= 4bytes then a "expedited" response is returned, otherwise a "normal" response. If a "normal" response is larger than the mailbox size then the response is segmented. The function will combine all segments and copy them to the parameter buffer.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]index= Index to read
[in]subindex= Subindex to read, must be 0 or 1 if CA is used.
[in]CA= FALSE = single subindex. TRUE = Complete Access, all subindexes read.
[in,out]psize= Size in bytes of parameter buffer, returns bytes read from SDO.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SDOwrite (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIndex,
boolean CA,
int psize,
void * p,
int Timeout 
)
+
+

CoE SDO write, blocking. Single subindex or Complete Access.

+

A "normal" download request is issued, unless we have small data, then a "expedited" transfer is used. If the parameter is larger than the mailbox size then the download is segmented. The function will split the parameter data in segments and send them to the slave one by one.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index to write
[in]SubIndex= Subindex to write, must be 0 or 1 if CA is used.
[in]CA= FALSE = single subindex. TRUE = Complete Access, all subindexes written.
[in]psize= Size in bytes of parameter buffer.
[out]p= Pointer to parameter buffer
[in]Timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_TxPDO (ecx_contexttcontext,
uint16 slave,
uint16 TxPDOnumber,
int * psize,
void * p,
int timeout 
)
+
+

CoE TxPDO read remote request, blocking.

+

A RxPDO download request is issued.

+
Parameters
+ + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]TxPDOnumber= Related TxPDO number
[in,out]psize= Size in bytes of PDO buffer, returns bytes read from PDO.
[out]p= Pointer to PDO buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercatcoe_8h.html b/doc/html/ethercatcoe_8h.html new file mode 100644 index 0000000..783e236 --- /dev/null +++ b/doc/html/ethercatcoe_8h.html @@ -0,0 +1,771 @@ + + + + + + +SOEM: ethercatcoe.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatcoe.h File Reference
+
+
+ +

Headerfile for ethercatcoe.c. +More...

+ + + + + + +

+Data Structures

struct  ec_ODlistt
 
struct  ec_OElistt
 
+ + + + + +

+Macros

#define EC_MAXODLIST   1024
 
#define EC_MAXOELIST   256
 
+ + + + + + + + + + + + + + + + + + + + + + + +

+Functions

void ecx_SDOerror (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode)
 
int ecx_SDOread (ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, boolean CA, int *psize, void *p, int timeout)
 
int ecx_SDOwrite (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex, boolean CA, int psize, void *p, int Timeout)
 
int ecx_RxPDO (ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize, void *p)
 
int ecx_TxPDO (ecx_contextt *context, uint16 slave, uint16 TxPDOnumber, int *psize, void *p, int timeout)
 
int ecx_readPDOmap (ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
 
int ecx_readPDOmapCA (ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
 
int ecx_readODlist (ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist)
 
int ecx_readODdescription (ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist)
 
int ecx_readOEsingle (ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
int ecx_readOE (ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist)
 
+

Detailed Description

+

Headerfile for ethercatcoe.c.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_MAXODLIST   1024
+
+

max entries in Object Description list

+ +
+
+ +
+
+ + + + +
#define EC_MAXOELIST   256
+
+

max entries in Object Entry list

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readODdescription (ecx_contexttcontext,
uint16 Item,
ec_ODlisttpODlist 
)
+
+

CoE read Object Description. Adds textual description to object indexes.

+
Parameters
+ + + + +
[in]context= context struct
[in]Item= Item number in ODlist.
[in,out]pODlist= referencing Object Description list.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readODlist (ecx_contexttcontext,
uint16 Slave,
ec_ODlisttpODlist 
)
+
+

CoE read Object Description List.

+
Parameters
+ + + + +
[in]context= context struct
[in]Slave= Slave number.
[out]pODlist= resulting Object Description list.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readOE (ecx_contexttcontext,
uint16 Item,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+

CoE read SDO service object entry.

+
Parameters
+ + + + + +
[in]context= context struct
[in]Item= Item in ODlist.
[in]pODlist= Object description list for reference.
[out]pOElist= resulting object entry structure.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readOEsingle (ecx_contexttcontext,
uint16 Item,
uint8 SubI,
ec_ODlisttpODlist,
ec_OElisttpOElist 
)
+
+

CoE read SDO service object entry, single subindex. Used in ec_readOE().

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Item= Item in ODlist.
[in]SubI= Subindex of item in ODlist.
[in]pODlist= Object description list for reference.
[out]pOElist= resulting object entry structure.
+
+
+
Returns
Workcounter of slave response.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOmap (ecx_contexttcontext,
uint16 Slave,
int * Osize,
int * Isize 
)
+
+

CoE read PDO mapping.

+

CANopen has standard indexes defined for PDO mapping. This function tries to read them and collect a full input and output mapping size of designated slave.

+

Principal structure in slave:
+ 1C00:00 is number of SM defined
+ 1C00:01 SM0 type -> 1C10
+ 1C00:02 SM1 type -> 1C11
+ 1C00:03 SM2 type -> 1C12
+ 1C00:04 SM4 type -> 1C13
+ Type 0 = unused, 1 = mailbox in, 2 = mailbox out, 3 = outputs (RxPDO), 4 = inputs (TxPDO).

+

1C12:00 is number of PDO's defined for SM2
+ 1C12:01 PDO assign SDO #1 -> f.e. 1A00
+ 1C12:02 PDO assign SDO #2 -> f.e. 1A04\

+

1A00:00 is number of object defined for this PDO
+ 1A00:01 object mapping #1, f.e. 60100710 (SDO 6010 SI 07 bitlength 0x10)

+
Parameters
+ + + + + +
[in]context= context struct
[in]Slave= Slave number
[out]Osize= Size in bits of output mapping (rxPDO) found
[out]Isize= Size in bits of input mapping (txPDO) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readPDOmapCA (ecx_contexttcontext,
uint16 Slave,
int * Osize,
int * Isize 
)
+
+

CoE read PDO mapping in Complete Access mode (CA).

+

CANopen has standard indexes defined for PDO mapping. This function tries to read them and collect a full input and output mapping size of designated slave. Slave has to support CA, otherwise use ec_readPDOmap().

+
Parameters
+ + + + + +
[in]context= context struct
[in]Slave= Slave number
[out]Osize= Size in bits of output mapping (rxPDO) found
[out]Isize= Size in bits of input mapping (txPDO) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_RxPDO (ecx_contexttcontext,
uint16 Slave,
uint16 RxPDOnumber,
int psize,
void * p 
)
+
+

CoE RxPDO write, blocking.

+

A RxPDO download request is issued.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]RxPDOnumber= Related RxPDO number
[in]psize= Size in bytes of PDO buffer.
[out]p= Pointer to PDO buffer
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_SDOerror (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIdx,
int32 AbortCode 
)
+
+

Report SDO error.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index that generated error
[in]SubIdx= Subindex that generated error
[in]AbortCode= Abortcode, see EtherCAT documentation for list
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SDOread (ecx_contexttcontext,
uint16 slave,
uint16 index,
uint8 subindex,
boolean CA,
int * psize,
void * p,
int timeout 
)
+
+

CoE SDO read, blocking. Single subindex or Complete Access.

+

Only a "normal" upload request is issued. If the requested parameter is <= 4bytes then a "expedited" response is returned, otherwise a "normal" response. If a "normal" response is larger than the mailbox size then the response is segmented. The function will combine all segments and copy them to the parameter buffer.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]index= Index to read
[in]subindex= Subindex to read, must be 0 or 1 if CA is used.
[in]CA= FALSE = single subindex. TRUE = Complete Access, all subindexes read.
[in,out]psize= Size in bytes of parameter buffer, returns bytes read from SDO.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SDOwrite (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIndex,
boolean CA,
int psize,
void * p,
int Timeout 
)
+
+

CoE SDO write, blocking. Single subindex or Complete Access.

+

A "normal" download request is issued, unless we have small data, then a "expedited" transfer is used. If the parameter is larger than the mailbox size then the download is segmented. The function will split the parameter data in segments and send them to the slave one by one.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index to write
[in]SubIndex= Subindex to write, must be 0 or 1 if CA is used.
[in]CA= FALSE = single subindex. TRUE = Complete Access, all subindexes written.
[in]psize= Size in bytes of parameter buffer.
[out]p= Pointer to parameter buffer
[in]Timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_TxPDO (ecx_contexttcontext,
uint16 slave,
uint16 TxPDOnumber,
int * psize,
void * p,
int timeout 
)
+
+

CoE TxPDO read remote request, blocking.

+

A RxPDO download request is issued.

+
Parameters
+ + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]TxPDOnumber= Related TxPDO number
[in,out]psize= Size in bytes of PDO buffer, returns bytes read from PDO.
[out]p= Pointer to PDO buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercatconfig_8c.html b/doc/html/ethercatconfig_8c.html new file mode 100644 index 0000000..205f5fd --- /dev/null +++ b/doc/html/ethercatconfig_8c.html @@ -0,0 +1,530 @@ + + + + + + +SOEM: ethercatconfig.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatconfig.c File Reference
+
+
+ +

Configuration module for EtherCAT master. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "osal.h"
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatcoe.h"
+#include "ethercatsoe.h"
+#include "ethercatconfig.h"
+#include "ethercatconfiglist.h"
+
+ + + +

+Data Structures

struct  ec_configlist_t
 
+ + + + + + + + + +

+Macros

#define EC_PRINT(...)   do {} while (0)
 
#define EC_DEFAULTMBXSM0   0x00010026
 
#define EC_DEFAULTMBXSM1   0x00010022
 
#define EC_DEFAULTDOSM0   0x00010044
 
+ + + + + + + + + + + + + + + + + + + + + + + +

+Functions

int ec_findconfig (uint32 man, uint32 id)
 
int ecx_config_init (ecx_contextt *context, uint8 usetable)
 
int ecx_config_map_group (ecx_contextt *context, void *pIOmap, uint8 group)
 
int ecx_recover_slave (ecx_contextt *context, uint16 slave, int timeout)
 
int ecx_reconfig_slave (ecx_contextt *context, uint16 slave, int timeout)
 
int ec_config_init (uint8 usetable)
 
int ec_config_map_group (void *pIOmap, uint8 group)
 
int ec_config_map (void *pIOmap)
 
int ec_config (uint8 usetable, void *pIOmap)
 
int ec_recover_slave (uint16 slave, int timeout)
 
int ec_reconfig_slave (uint16 slave, int timeout)
 
+

Detailed Description

+

Configuration module for EtherCAT master.

+

After successful initialisation with ec_init() or ec_init_redundant() the slaves can be auto configured with this module.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_DEFAULTDOSM0   0x00010044
+
+

standard SM0 flags configuration for digital output slaves

+ +
+
+ +
+
+ + + + +
#define EC_DEFAULTMBXSM0   0x00010026
+
+

standard SM0 flags configuration for mailbox slaves

+ +
+
+ +
+
+ + + + +
#define EC_DEFAULTMBXSM1   0x00010022
+
+

standard SM1 flags configuration for mailbox slaves

+ +
+
+ +
+
+ + + + + + + + +
#define EC_PRINT( ...)   do {} while (0)
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_config (uint8 usetable,
void * pIOmap 
)
+
+

Enumerate / map and init all slaves.

+
Parameters
+ + + +
[in]usetable= TRUE when using configtable to init slaves, FALSE otherwise
[out]pIOmap= pointer to IOmap
+
+
+
Returns
Workcounter of slave discover datagram = number of slaves found
+ +
+
+ +
+
+ + + + + + + + +
int ec_config_init (uint8 usetable)
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_config_map (void * pIOmap)
+
+

Map all PDOs from slaves to IOmap.

+
Parameters
+ + +
[out]pIOmap= pointer to IOmap
+
+
+
Returns
IOmap size
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_config_map_group (void * pIOmap,
uint8 group 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_findconfig (uint32 man,
uint32 id 
)
+
+

Find slave in standard configuration list ec_configlist[]

+
Parameters
+ + + +
[in]man= manufacturer
[in]id= ID
+
+
+
Returns
index in ec_configlist[] when found, otherwise 0
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_reconfig_slave (uint16 slave,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_recover_slave (uint16 slave,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_config_init (ecx_contexttcontext,
uint8 usetable 
)
+
+

Enumerate and init all slaves.

+
Parameters
+ + + +
[in]context= context struct
[in]usetable= TRUE when using configtable to init slaves, FALSE otherwise
+
+
+
Returns
Workcounter of slave discover datagram = number of slaves found
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_config_map_group (ecx_contexttcontext,
void * pIOmap,
uint8 group 
)
+
+

Map all PDOs in one group of slaves to IOmap.

+
Parameters
+ + + + +
[in]context= context struct
[out]pIOmap= pointer to IOmap
[in]group= group to map, 0 = all groups
+
+
+
Returns
IOmap size
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_reconfig_slave (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Reconfigure slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave to reconfigure
[in]timeout= local timeout f.e. EC_TIMEOUTRET3
+
+
+
Returns
Slave state
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_recover_slave (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Recover slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave to recover
[in]timeout= local timeout f.e. EC_TIMEOUTRET3
+
+
+
Returns
>0 if successful
+ +
+
+
+ + + + diff --git a/doc/html/ethercatconfig_8h.html b/doc/html/ethercatconfig_8h.html new file mode 100644 index 0000000..725151e --- /dev/null +++ b/doc/html/ethercatconfig_8h.html @@ -0,0 +1,275 @@ + + + + + + +SOEM: ethercatconfig.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatconfig.h File Reference
+
+
+ +

Headerfile for ethercatconfig.c. +More...

+ + + + + + +

+Macros

#define EC_NODEOFFSET   0x1000
 
#define EC_TEMPNODE   0xffff
 
+ + + + + + + + + +

+Functions

int ecx_config_init (ecx_contextt *context, uint8 usetable)
 
int ecx_config_map_group (ecx_contextt *context, void *pIOmap, uint8 group)
 
int ecx_recover_slave (ecx_contextt *context, uint16 slave, int timeout)
 
int ecx_reconfig_slave (ecx_contextt *context, uint16 slave, int timeout)
 
+

Detailed Description

+

Headerfile for ethercatconfig.c.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_NODEOFFSET   0x1000
+
+ +
+
+ +
+
+ + + + +
#define EC_TEMPNODE   0xffff
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_config_init (ecx_contexttcontext,
uint8 usetable 
)
+
+

Enumerate and init all slaves.

+
Parameters
+ + + +
[in]context= context struct
[in]usetable= TRUE when using configtable to init slaves, FALSE otherwise
+
+
+
Returns
Workcounter of slave discover datagram = number of slaves found
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_config_map_group (ecx_contexttcontext,
void * pIOmap,
uint8 group 
)
+
+

Map all PDOs in one group of slaves to IOmap.

+
Parameters
+ + + + +
[in]context= context struct
[out]pIOmap= pointer to IOmap
[in]group= group to map, 0 = all groups
+
+
+
Returns
IOmap size
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_reconfig_slave (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Reconfigure slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave to reconfigure
[in]timeout= local timeout f.e. EC_TIMEOUTRET3
+
+
+
Returns
Slave state
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_recover_slave (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Recover slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave to recover
[in]timeout= local timeout f.e. EC_TIMEOUTRET3
+
+
+
Returns
>0 if successful
+ +
+
+
+ + + + diff --git a/doc/html/ethercatconfiglist_8h.html b/doc/html/ethercatconfiglist_8h.html new file mode 100644 index 0000000..6edbf86 --- /dev/null +++ b/doc/html/ethercatconfiglist_8h.html @@ -0,0 +1,133 @@ + + + + + + +SOEM: ethercatconfiglist.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatconfiglist.h File Reference
+
+
+ +

DEPRICATED Configuration list of known EtherCAT slave devices. +More...

+ + + + +

+Macros

#define EC_CONFIGEND   0xffffffff
 
+ + + +

+Variables

ec_configlist_t ec_configlist []
 
+

Detailed Description

+

DEPRICATED Configuration list of known EtherCAT slave devices.

+

If a slave is found in this list it is configured according to the parameters in the list. Otherwise the configuration info is read directly from the slave EEPROM (SII or Slave Information Interface).

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_CONFIGEND   0xffffffff
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
ec_configlist_t ec_configlist[]
+
+Initial value:
= {
+
{0x00000000,0x00000000,"" ,0, 0, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x044c2c52,"EK1100" ,1, 0, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x03ea3052,"EL1002" ,2, 2, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x03ec3052,"EL1004" ,2, 4, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x03f43052,"EL1012" ,2, 2, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x03f63052,"EL1014" ,2, 4, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x03fa3052,"EL1018" ,2, 8, 0, 0, 0, 0, 0,0,0},
+
{0x00000002,0x07d23052,"EL2002" ,3, 0, 2, 0, 0, 0, 0,0,0},
+
{0x00000002,0x07d43052,"EL2004" ,3, 0, 4, 0, 0, 0, 0,0,0},
+
{0x00000002,0x07d83052,"EL2008" ,3, 0, 8, 0, 0, 0, 0,0,0},
+
{0x00000002,0x07f03052,"EL2032" ,6, 2, 2, 0, 0, 0, 0,0,0},
+
{0x00000002,0x0c1e3052,"EL3102" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0c283052,"EL3112" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0c323052,"EL3122" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0c463052,"EL3142" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0c503052,"EL3152" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0c5a3052,"EL3162" ,4,48, 0,0x1000,0x00000024,0x1100,0x00010020,0,1},
+
{0x00000002,0x0fc03052,"EL4032" ,5, 0,32,0x1100,0x00010024,0x1180,0x00000022,1,0},
+
{0x00000002,0x10063052,"EL4102" ,5, 0,32,0x1000,0x00010024,0x1100,0x00000022,1,0},
+
{0x00000002,0x10103052,"EL4112" ,5, 0,32,0x1000,0x00010024,0x1100,0x00000022,1,0},
+
{0x00000002,0x101a3052,"EL4122" ,5, 0,32,0x1000,0x00010024,0x1100,0x00000022,1,0},
+
{0x00000002,0x10243052,"EL4132" ,5, 0,32,0x1000,0x00010024,0x1100,0x00000022,1,0},
+
{0x00000002,0x13ed3052,"EL5101" ,7,40,24,0x1000,0x00010024,0x1100,0x00010020,1,1},
+
{EC_CONFIGEND,0x00000000,"" ,0, 0, 0, 0, 0, 0, 0,0,0}
+
}
+
+
+
+
+ + + + diff --git a/doc/html/ethercatdc_8c.html b/doc/html/ethercatdc_8c.html new file mode 100644 index 0000000..5b313e1 --- /dev/null +++ b/doc/html/ethercatdc_8c.html @@ -0,0 +1,526 @@ + + + + + + +SOEM: ethercatdc.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatdc.c File Reference
+
+
+ +

Distributed Clock EtherCAT functions. +More...

+
#include "oshw.h"
+#include "osal.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatdc.h"
+
+ + + + + + + + + + + +

+Macros

#define PORTM0   0x01
 
#define PORTM1   0x02
 
#define PORTM2   0x04
 
#define PORTM3   0x08
 
#define SyncDelay   ((int32)100000000)
 
+ + + + + + + + + + + + + + + + + + + +

+Functions

void ecx_dcsync0 (ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift)
 
void ecx_dcsync01 (ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift)
 
static int32 ecx_porttime (ecx_contextt *context, uint16 slave, uint8 port)
 
static uint8 ecx_prevport (ecx_contextt *context, uint16 slave, uint8 port)
 
static uint8 ecx_parentport (ecx_contextt *context, uint16 parent)
 
boolean ecx_configdc (ecx_contextt *context)
 
void ec_dcsync0 (uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift)
 
void ec_dcsync01 (uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift)
 
boolean ec_configdc (void)
 
+

Detailed Description

+

Distributed Clock EtherCAT functions.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define PORTM0   0x01
+
+ +
+
+ +
+
+ + + + +
#define PORTM1   0x02
+
+ +
+
+ +
+
+ + + + +
#define PORTM2   0x04
+
+ +
+
+ +
+
+ + + + +
#define PORTM3   0x08
+
+ +
+
+ +
+
+ + + + +
#define SyncDelay   ((int32)100000000)
+
+

1st sync pulse delay in ns here 100ms

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
boolean ec_configdc (void )
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ec_dcsync0 (uint16 slave,
boolean act,
uint32 CyclTime,
uint32 CyclShift 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ec_dcsync01 (uint16 slave,
boolean act,
uint32 CyclTime0,
uint32 CyclTime1,
uint32 CyclShift 
)
+
+ +
+
+ +
+
+ + + + + + + + +
boolean ecx_configdc (ecx_contexttcontext)
+
+

Locate DC slaves, measure propagation delays.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
boolean if slaves are found with DC
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_dcsync0 (ecx_contexttcontext,
uint16 slave,
boolean act,
uint32 CyclTime,
uint32 CyclShift 
)
+
+

Set DC of slave to fire sync0 at CyclTime interval with CyclShift offset.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]slaveSlave number.
[in]actTRUE = active, FALSE = deactivated
[in]CyclTimeCycltime in ns.
[in]CyclShiftCyclShift in ns.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_dcsync01 (ecx_contexttcontext,
uint16 slave,
boolean act,
uint32 CyclTime0,
uint32 CyclTime1,
uint32 CyclShift 
)
+
+

Set DC of slave to fire sync0 and sync1 at CyclTime interval with CyclShift offset.

+
Parameters
+ + + + + + + +
[in]context= context struct
[in]slaveSlave number.
[in]actTRUE = active, FALSE = deactivated
[in]CyclTime0Cycltime SYNC0 in ns.
[in]CyclTime1Cycltime SYNC1 in ns. This time is a delta time in relation to the SYNC0 fire. If CylcTime1 = 0 then SYNC1 fires a the same time as SYNC0.
[in]CyclShiftCyclShift in ns.
+
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
static uint8 ecx_parentport (ecx_contexttcontext,
uint16 parent 
)
+
+static
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
static int32 ecx_porttime (ecx_contexttcontext,
uint16 slave,
uint8 port 
)
+
+static
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
static uint8 ecx_prevport (ecx_contexttcontext,
uint16 slave,
uint8 port 
)
+
+static
+
+ +
+
+
+ + + + diff --git a/doc/html/ethercatdc_8h.html b/doc/html/ethercatdc_8h.html new file mode 100644 index 0000000..2e217b3 --- /dev/null +++ b/doc/html/ethercatdc_8h.html @@ -0,0 +1,220 @@ + + + + + + +SOEM: ethercatdc.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatdc.h File Reference
+
+
+ +

Headerfile for ethercatdc.c. +More...

+ + + + + + + + +

+Functions

boolean ecx_configdc (ecx_contextt *context)
 
void ecx_dcsync0 (ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift)
 
void ecx_dcsync01 (ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift)
 
+

Detailed Description

+

Headerfile for ethercatdc.c.

+

Function Documentation

+ +
+
+ + + + + + + + +
boolean ecx_configdc (ecx_contexttcontext)
+
+

Locate DC slaves, measure propagation delays.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
boolean if slaves are found with DC
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_dcsync0 (ecx_contexttcontext,
uint16 slave,
boolean act,
uint32 CyclTime,
uint32 CyclShift 
)
+
+

Set DC of slave to fire sync0 at CyclTime interval with CyclShift offset.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]slaveSlave number.
[in]actTRUE = active, FALSE = deactivated
[in]CyclTimeCycltime in ns.
[in]CyclShiftCyclShift in ns.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_dcsync01 (ecx_contexttcontext,
uint16 slave,
boolean act,
uint32 CyclTime0,
uint32 CyclTime1,
uint32 CyclShift 
)
+
+

Set DC of slave to fire sync0 and sync1 at CyclTime interval with CyclShift offset.

+
Parameters
+ + + + + + + +
[in]context= context struct
[in]slaveSlave number.
[in]actTRUE = active, FALSE = deactivated
[in]CyclTime0Cycltime SYNC0 in ns.
[in]CyclTime1Cycltime SYNC1 in ns. This time is a delta time in relation to the SYNC0 fire. If CylcTime1 = 0 then SYNC1 fires a the same time as SYNC0.
[in]CyclShiftCyclShift in ns.
+
+
+ +
+
+
+ + + + diff --git a/doc/html/ethercatfoe_8c.html b/doc/html/ethercatfoe_8c.html new file mode 100644 index 0000000..8e8d292 --- /dev/null +++ b/doc/html/ethercatfoe_8c.html @@ -0,0 +1,410 @@ + + + + + + +SOEM: ethercatfoe.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatfoe.c File Reference
+
+
+ +

File over EtherCAT (FoE) module. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "osal.h"
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatfoe.h"
+
+ + + +

+Data Structures

struct  ec_FOEt
 
+ + + +

+Macros

#define EC_MAXFOEDATA   512
 
+ + + + + + + + + + + + + +

+Functions

PACKED_END int ecx_FOEdefinehook (ecx_contextt *context, void *hook)
 
int ecx_FOEread (ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
 
int ecx_FOEwrite (ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
 
int ec_FOEdefinehook (void *hook)
 
int ec_FOEread (uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
 
int ec_FOEwrite (uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
 
+

Detailed Description

+

File over EtherCAT (FoE) module.

+

SDO read / write and SDO service functions

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_MAXFOEDATA   512
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
int ec_FOEdefinehook (void * hook)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FOEread (uint16 slave,
char * filename,
uint32 password,
int * psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_FOEwrite (uint16 slave,
char * filename,
uint32 password,
int psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
PACKED_END int ecx_FOEdefinehook (ecx_contexttcontext,
void * hook 
)
+
+

FoE progress hook.

+
Parameters
+ + + +
[in]context= context struct
[in]hook= Pointer to hook function.
+
+
+
Returns
1
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FOEread (ecx_contexttcontext,
uint16 slave,
char * filename,
uint32 password,
int * psize,
void * p,
int timeout 
)
+
+

FoE read, blocking.

+
Parameters
+ + + + + + + + +
[in]context= context struct
[in]slave= Slave number.
[in]filename= Filename of file to read.
[in]password= password.
[in,out]psize= Size in bytes of file buffer, returns bytes read from file.
[out]p= Pointer to file buffer
[in]timeout= Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FOEwrite (ecx_contexttcontext,
uint16 slave,
char * filename,
uint32 password,
int psize,
void * p,
int timeout 
)
+
+

FoE write, blocking.

+
Parameters
+ + + + + + + + +
[in]context= context struct
[in]slave= Slave number.
[in]filename= Filename of file to write.
[in]password= password.
[in]psize= Size in bytes of file buffer.
[out]p= Pointer to file buffer
[in]timeout= Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercatfoe_8h.html b/doc/html/ethercatfoe_8h.html new file mode 100644 index 0000000..1802c96 --- /dev/null +++ b/doc/html/ethercatfoe_8h.html @@ -0,0 +1,254 @@ + + + + + + +SOEM: ethercatfoe.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatfoe.h File Reference
+
+
+ +

Headerfile for ethercatfoe.c. +More...

+ + + + + + + + +

+Functions

int ecx_FOEdefinehook (ecx_contextt *context, void *hook)
 
int ecx_FOEread (ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
 
int ecx_FOEwrite (ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
 
+

Detailed Description

+

Headerfile for ethercatfoe.c.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_FOEdefinehook (ecx_contexttcontext,
void * hook 
)
+
+

FoE progress hook.

+
Parameters
+ + + +
[in]context= context struct
[in]hook= Pointer to hook function.
+
+
+
Returns
1
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FOEread (ecx_contexttcontext,
uint16 slave,
char * filename,
uint32 password,
int * psize,
void * p,
int timeout 
)
+
+

FoE read, blocking.

+
Parameters
+ + + + + + + + +
[in]context= context struct
[in]slave= Slave number.
[in]filename= Filename of file to read.
[in]password= password.
[in,out]psize= Size in bytes of file buffer, returns bytes read from file.
[out]p= Pointer to file buffer
[in]timeout= Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_FOEwrite (ecx_contexttcontext,
uint16 slave,
char * filename,
uint32 password,
int psize,
void * p,
int timeout 
)
+
+

FoE write, blocking.

+
Parameters
+ + + + + + + + +
[in]context= context struct
[in]slave= Slave number.
[in]filename= Filename of file to write.
[in]password= password.
[in]psize= Size in bytes of file buffer.
[out]p= Pointer to file buffer
[in]timeout= Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercatmain_8c.html b/doc/html/ethercatmain_8c.html new file mode 100644 index 0000000..66b7b5a --- /dev/null +++ b/doc/html/ethercatmain_8c.html @@ -0,0 +1,3500 @@ + + + + + + +SOEM: ethercatmain.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatmain.c File Reference
+
+
+ +

Main EtherCAT functions. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "osal.h"
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+
+ + + + + + + +

+Data Structures

struct  ec_eepromt
 
struct  ec_mbxerrort
 
struct  ec_emcyt
 
+ + + +

+Macros

#define EC_LOCALDELAY   200
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

ec_adaptert * ec_find_adapters (void)
 
void ec_free_adapters (ec_adaptert *adapter)
 
void ecx_pusherror (ecx_contextt *context, const ec_errort *Ec)
 
boolean ecx_poperror (ecx_contextt *context, ec_errort *Ec)
 
boolean ecx_iserror (ecx_contextt *context)
 
void ecx_packeterror (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode)
 
static void ecx_mbxerror (ecx_contextt *context, uint16 Slave, uint16 Detail)
 
static void ecx_mbxemergencyerror (ecx_contextt *context, uint16 Slave, uint16 ErrorCode, uint16 ErrorReg, uint8 b1, uint16 w1, uint16 w2)
 
int ecx_init (ecx_contextt *context, char *ifname)
 
int ecx_init_redundant (ecx_contextt *context, ecx_redportt *redport, char *ifname, char *if2name)
 
void ecx_close (ecx_contextt *context)
 
uint8 ecx_siigetbyte (ecx_contextt *context, uint16 slave, uint16 address)
 
int16 ecx_siifind (ecx_contextt *context, uint16 slave, uint16 cat)
 
void ecx_siistring (ecx_contextt *context, char *str, uint16 slave, uint16 Sn)
 
uint16 ecx_siiFMMU (ecx_contextt *context, uint16 slave, ec_eepromFMMUt *FMMU)
 
uint16 ecx_siiSM (ecx_contextt *context, uint16 slave, ec_eepromSMt *SM)
 
uint16 ecx_siiSMnext (ecx_contextt *context, uint16 slave, ec_eepromSMt *SM, uint16 n)
 
int ecx_siiPDO (ecx_contextt *context, uint16 slave, ec_eepromPDOt *PDO, uint8 t)
 
int ecx_readstate (ecx_contextt *context)
 
int ecx_writestate (ecx_contextt *context, uint16 slave)
 
uint16 ecx_statecheck (ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout)
 
uint8 ec_nextmbxcnt (uint8 cnt)
 
void ec_clearmbx (ec_mbxbuft *Mbx)
 
int ecx_mbxempty (ecx_contextt *context, uint16 slave, int timeout)
 
int ecx_mbxsend (ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout)
 
int ecx_mbxreceive (ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout)
 
void ecx_esidump (ecx_contextt *context, uint16 slave, uint8 *esibuf)
 
uint32 ecx_readeeprom (ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout)
 
int ecx_writeeeprom (ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout)
 
int ecx_eeprom2master (ecx_contextt *context, uint16 slave)
 
int ecx_eeprom2pdi (ecx_contextt *context, uint16 slave)
 
uint16 ecx_eeprom_waitnotbusyAP (ecx_contextt *context, uint16 aiadr, uint16 *estat, int timeout)
 
uint64 ecx_readeepromAP (ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout)
 
int ecx_writeeepromAP (ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout)
 
uint16 ecx_eeprom_waitnotbusyFP (ecx_contextt *context, uint16 configadr, uint16 *estat, int timeout)
 
uint64 ecx_readeepromFP (ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout)
 
int ecx_writeeepromFP (ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout)
 
void ecx_readeeprom1 (ecx_contextt *context, uint16 slave, uint16 eeproma)
 
uint32 ecx_readeeprom2 (ecx_contextt *context, uint16 slave, int timeout)
 
static void ecx_pushindex (ecx_contextt *context, uint8 idx, void *data, uint16 length)
 
static int ecx_pullindex (ecx_contextt *context)
 
int ecx_send_processdata_group (ecx_contextt *context, uint8 group)
 
int ecx_receive_processdata_group (ecx_contextt *context, uint8 group, int timeout)
 
int ecx_send_processdata (ecx_contextt *context)
 
int ecx_receive_processdata (ecx_contextt *context, int timeout)
 
void ec_pusherror (const ec_errort *Ec)
 
boolean ec_poperror (ec_errort *Ec)
 
boolean ec_iserror (void)
 
void ec_packeterror (uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode)
 
static void ec_mbxerror (uint16 Slave, uint16 Detail)
 
static void ec_mbxemergencyerror (uint16 Slave, uint16 ErrorCode, uint16 ErrorReg, uint8 b1, uint16 w1, uint16 w2)
 
int ec_init (char *ifname)
 
int ec_init_redundant (char *ifname, char *if2name)
 
void ec_close (void)
 
uint8 ec_siigetbyte (uint16 slave, uint16 address)
 
int16 ec_siifind (uint16 slave, uint16 cat)
 
void ec_siistring (char *str, uint16 slave, uint16 Sn)
 
uint16 ec_siiFMMU (uint16 slave, ec_eepromFMMUt *FMMU)
 
uint16 ec_siiSM (uint16 slave, ec_eepromSMt *SM)
 
uint16 ec_siiSMnext (uint16 slave, ec_eepromSMt *SM, uint16 n)
 
int ec_siiPDO (uint16 slave, ec_eepromPDOt *PDO, uint8 t)
 
int ec_readstate (void)
 
int ec_writestate (uint16 slave)
 
uint16 ec_statecheck (uint16 slave, uint16 reqstate, int timeout)
 
int ec_mbxempty (uint16 slave, int timeout)
 
int ec_mbxsend (uint16 slave, ec_mbxbuft *mbx, int timeout)
 
int ec_mbxreceive (uint16 slave, ec_mbxbuft *mbx, int timeout)
 
void ec_esidump (uint16 slave, uint8 *esibuf)
 
uint32 ec_readeeprom (uint16 slave, uint16 eeproma, int timeout)
 
int ec_writeeeprom (uint16 slave, uint16 eeproma, uint16 data, int timeout)
 
int ec_eeprom2master (uint16 slave)
 
int ec_eeprom2pdi (uint16 slave)
 
uint16 ec_eeprom_waitnotbusyAP (uint16 aiadr, uint16 *estat, int timeout)
 
uint64 ec_readeepromAP (uint16 aiadr, uint16 eeproma, int timeout)
 
int ec_writeeepromAP (uint16 aiadr, uint16 eeproma, uint16 data, int timeout)
 
uint16 ec_eeprom_waitnotbusyFP (uint16 configadr, uint16 *estat, int timeout)
 
uint64 ec_readeepromFP (uint16 configadr, uint16 eeproma, int timeout)
 
int ec_writeeepromFP (uint16 configadr, uint16 eeproma, uint16 data, int timeout)
 
void ec_readeeprom1 (uint16 slave, uint16 eeproma)
 
uint32 ec_readeeprom2 (uint16 slave, int timeout)
 
int ec_send_processdata_group (uint8 group)
 
int ec_receive_processdata_group (uint8 group, int timeout)
 
int ec_send_processdata (void)
 
int ec_receive_processdata (int timeout)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Variables

PACKED_END ec_slavet ec_slave [EC_MAXSLAVE]
 
int ec_slavecount
 
ec_groupt ec_group [EC_MAXGROUP]
 
static uint8 esibuf [EC_MAXEEPBUF]
 
static uint32 esimap [EC_MAXEEPBITMAP]
 
static ec_eringt ec_elist
 
static ec_idxstackT ec_idxstack
 
static ec_SMcommtypet ec_SMcommtype
 
static ec_PDOassignt ec_PDOassign
 
static ec_PDOdesct ec_PDOdesc
 
static ec_eepromSMt ec_SM
 
static ec_eepromFMMUt ec_FMMU
 
boolean EcatError = FALSE
 
int64 ec_DCtime
 
ecx_portt ecx_port
 
ecx_redportt ecx_redport
 
ecx_contextt ecx_context
 
+

Detailed Description

+

Main EtherCAT functions.

+

Initialisation, state set and read, mailbox primitives, EEPROM primitives, SII reading and processdata exchange.

+

Defines ec_slave[]. All slave information is put in this structure. Needed for most user interaction with slaves.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_LOCALDELAY   200
+
+

delay in us for eeprom ready loop

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void ec_clearmbx (ec_mbxbuftMbx)
+
+

Clear mailbox buffer.

+
Parameters
+ + +
[out]Mbx= Mailbox buffer to clear
+
+
+ +
+
+ +
+
+ + + + + + + + +
void ec_close (void )
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_eeprom2master (uint16 slave)
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_eeprom2pdi (uint16 slave)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_eeprom_waitnotbusyAP (uint16 aiadr,
uint16 * estat,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_eeprom_waitnotbusyFP (uint16 configadr,
uint16 * estat,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void ec_esidump (uint16 slave,
uint8 * esibuf 
)
+
+ +
+
+ +
+
+ + + + + + + + +
ec_adaptert* ec_find_adapters (void )
+
+

Create list over available network adapters.

+
Returns
First element in list over available network adapters.
+ +
+
+ +
+
+ + + + + + + + +
void ec_free_adapters (ec_adaptert * adapter)
+
+

Free dynamically allocated list over available network adapters.

+
Parameters
+ + +
[in]adapter= Struct holding adapter name, description and pointer to next.
+
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_init (char * ifname)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_init_redundant (char * ifname,
char * if2name 
)
+
+ +
+
+ +
+
+ + + + + + + + +
boolean ec_iserror (void )
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void ec_mbxemergencyerror (uint16 Slave,
uint16 ErrorCode,
uint16 ErrorReg,
uint8 b1,
uint16 w1,
uint16 w2 
)
+
+static
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_mbxempty (uint16 slave,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
static void ec_mbxerror (uint16 Slave,
uint16 Detail 
)
+
+static
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_mbxreceive (uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_mbxsend (uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + +
uint8 ec_nextmbxcnt (uint8 cnt)
+
+

Get index of next mailbox counter value. Used for Mailbox Link Layer.

+
Parameters
+ + +
[in]cnt= Mailbox counter value [0..7]
+
+
+
Returns
next mailbox counter value
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ec_packeterror (uint16 Slave,
uint16 Index,
uint8 SubIdx,
uint16 ErrorCode 
)
+
+ +
+
+ +
+
+ + + + + + + + +
boolean ec_poperror (ec_errortEc)
+
+ +
+
+ +
+
+ + + + + + + + +
void ec_pusherror (const ec_errortEc)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint32 ec_readeeprom (uint16 slave,
uint16 eeproma,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void ec_readeeprom1 (uint16 slave,
uint16 eeproma 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint32 ec_readeeprom2 (uint16 slave,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ec_readeepromAP (uint16 aiadr,
uint16 eeproma,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ec_readeepromFP (uint16 configadr,
uint16 eeproma,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_readstate (void )
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_receive_processdata (int timeout)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ec_receive_processdata_group (uint8 group,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_send_processdata (void )
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_send_processdata_group (uint8 group)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int16 ec_siifind (uint16 slave,
uint16 cat 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint16 ec_siiFMMU (uint16 slave,
ec_eepromFMMUtFMMU 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8 ec_siigetbyte (uint16 slave,
uint16 address 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_siiPDO (uint16 slave,
ec_eepromPDOtPDO,
uint8 t 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint16 ec_siiSM (uint16 slave,
ec_eepromSMtSM 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_siiSMnext (uint16 slave,
ec_eepromSMtSM,
uint16 n 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ec_siistring (char * str,
uint16 slave,
uint16 Sn 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ec_statecheck (uint16 slave,
uint16 reqstate,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_writeeeprom (uint16 slave,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_writeeepromAP (uint16 aiadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_writeeepromFP (uint16 configadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + +
int ec_writestate (uint16 slave)
+
+ +
+
+ +
+
+ + + + + + + + +
void ecx_close (ecx_contexttcontext)
+
+

Close lib.

+
Parameters
+ + +
[in]context= context struct
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_eeprom2master (ecx_contexttcontext,
uint16 slave 
)
+
+

Set eeprom control to master. Only if set to PDI.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_eeprom2pdi (ecx_contexttcontext,
uint16 slave 
)
+
+

Set eeprom control to PDI. Only if set to master.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_eeprom_waitnotbusyAP (ecx_contexttcontext,
uint16 aiadr,
uint16 * estat,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_eeprom_waitnotbusyFP (ecx_contexttcontext,
uint16 configadr,
uint16 * estat,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_esidump (ecx_contexttcontext,
uint16 slave,
uint8 * esibuf 
)
+
+

Dump complete EEPROM data from slave in buffer.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[out]esibuf= EEPROM data buffer, make sure it is big enough.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_init (ecx_contexttcontext,
char * ifname 
)
+
+

Initialise lib in single NIC mode

+
Parameters
+ + + +
[in]context= context struct
[in]ifname= Dev name, f.e. "eth0"
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_init_redundant (ecx_contexttcontext,
ecx_redportt * redport,
char * ifname,
char * if2name 
)
+
+

Initialise lib in redundant NIC mode

+
Parameters
+ + + + + +
[in]context= context struct
[in]redport= pointer to redport, redundant port data
[in]ifname= Primary Dev name, f.e. "eth0"
[in]if2name= Secondary Dev name, f.e. "eth1"
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + +
boolean ecx_iserror (ecx_contexttcontext)
+
+

Check if error list has entries.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
TRUE if error list contains entries.
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void ecx_mbxemergencyerror (ecx_contexttcontext,
uint16 Slave,
uint16 ErrorCode,
uint16 ErrorReg,
uint8 b1,
uint16 w1,
uint16 w2 
)
+
+static
+
+

Report Mailbox Emergency Error

+
Parameters
+ + + + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]ErrorCode= Following EtherCAT specification
[in]ErrorReg
[in]b1
[in]w1
[in]w2
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxempty (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Check if IN mailbox of slave is empty.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]timeout= Timeout in us
+
+
+
Returns
>0 is success
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
static void ecx_mbxerror (ecx_contexttcontext,
uint16 Slave,
uint16 Detail 
)
+
+static
+
+

Report Mailbox Error

+
Parameters
+ + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Detail= Following EtherCAT specification
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxreceive (ecx_contexttcontext,
uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+

Read OUT mailbox from slave. Supports Mailbox Link Layer with repeat requests.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]mbx= Mailbox data
[in]timeout= Timeout in us
+
+
+
Returns
Work counter (>0 is success)
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxsend (ecx_contexttcontext,
uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+

Write IN mailbox to slave.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]mbx= Mailbox data
[in]timeout= Timeout in us
+
+
+
Returns
Work counter (>0 is success)
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_packeterror (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIdx,
uint16 ErrorCode 
)
+
+

Report packet error

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index that generated error
[in]SubIdx= Subindex that generated error
[in]ErrorCode= Error code
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
boolean ecx_poperror (ecx_contexttcontext,
ec_errortEc 
)
+
+

Pops an error from the list.

+
Parameters
+ + + +
[in]context= context struct
[out]Ec= Struct describing the error.
+
+
+
Returns
TRUE if an error was popped.
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + +
static int ecx_pullindex (ecx_contexttcontext)
+
+static
+
+

Pull index of segmented LRD/LWR/LRW combination.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
Stack location, -1 if stack is empty.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void ecx_pusherror (ecx_contexttcontext,
const ec_errortEc 
)
+
+

Pushes an error on the error list.

+
Parameters
+ + + +
[in]context= context struct
[in]Ecpointer describing the error.
+
+
+ +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void ecx_pushindex (ecx_contexttcontext,
uint8 idx,
void * data,
uint16 length 
)
+
+static
+
+

Push index of segmented LRD/LWR/LRW combination.

+
Parameters
+ + + + + +
[in]context= context struct
[in]idx= Used datagram index.
[in]data= Pointer to process data segment.
[in]length= Length of data segment in bytes.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint32 ecx_readeeprom (ecx_contexttcontext,
uint16 slave,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_readeeprom1 (ecx_contexttcontext,
uint16 slave,
uint16 eeproma 
)
+
+

Read EEPROM from slave bypassing cache. Parallel read step 1, make request to slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint32 ecx_readeeprom2 (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. Parallel read step 2, actual read from slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ecx_readeepromAP (ecx_contexttcontext,
uint16 aiadr,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. APRD method.

+
Parameters
+ + + + + +
[in]context= context struct
[in]aiadr= auto increment address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 64bit or 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ecx_readeepromFP (ecx_contexttcontext,
uint16 configadr,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. FPRD method.

+
Parameters
+ + + + + +
[in]context= context struct
[in]configadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 64bit or 32bit
+ +
+
+ +
+
+ + + + + + + + +
int ecx_readstate (ecx_contexttcontext)
+
+

Read all slave states in ec_slave.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
lowest state found
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_receive_processdata (ecx_contexttcontext,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_receive_processdata_group (ecx_contexttcontext,
uint8 group,
int timeout 
)
+
+

Receive processdata from slaves. Second part from ec_send_processdata(). Received datagrams are recombined with the processdata with help from the stack. If a datagram contains input processdata it copies it to the processdata structure.

+
Parameters
+ + + + +
[in]context= context struct
[in]group= group number
[in]timeout= Timeout in us.
+
+
+
Returns
Work counter.
+ +
+
+ +
+
+ + + + + + + + +
int ecx_send_processdata (ecx_contexttcontext)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_send_processdata_group (ecx_contexttcontext,
uint8 group 
)
+
+

Transmit processdata to slaves. Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). Both the input and output processdata are transmitted. The outputs with the actual data, the inputs have a placeholder. The inputs are gathered with the receive processdata function. In contrast to the base LRW function this function is non-blocking. If the processdata does not fit in one datagram, multiple are used. In order to recombine the slave response, a stack is used.

+
Parameters
+ + + +
[in]context= context struct
[in]group= group number
+
+
+
Returns
>0 if processdata is transmitted.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int16 ecx_siifind (ecx_contexttcontext,
uint16 slave,
uint16 cat 
)
+
+

Find SII section header in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[in]cat= section category
+
+
+
Returns
byte address of section at section length entry, if not available then 0
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiFMMU (ecx_contexttcontext,
uint16 slave,
ec_eepromFMMUtFMMU 
)
+
+

Get FMMU data from SII FMMU section in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[out]FMMU= FMMU struct from SII, max. 4 FMMU's
+
+
+
Returns
number of FMMU's defined in section
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8 ecx_siigetbyte (ecx_contexttcontext,
uint16 slave,
uint16 address 
)
+
+

Read one byte from slave EEPROM via cache. If the cache location is empty then a read request is made to the slave. Depending on the slave capabillities the request is 4 or 8 bytes.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[in]address= eeprom address in bytes (slave uses words)
+
+
+
Returns
requested byte, if not available then 0xff
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_siiPDO (ecx_contexttcontext,
uint16 slave,
ec_eepromPDOtPDO,
uint8 t 
)
+
+

Get PDO data from SII PDO section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= slave number
[out]PDO= PDO struct from SII
[in]t= 0=RXPDO 1=TXPDO
+
+
+
Returns
mapping size in bits of PDO
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiSM (ecx_contexttcontext,
uint16 slave,
ec_eepromSMtSM 
)
+
+

Get SM data from SII SM section in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[out]SM= first SM struct from SII
+
+
+
Returns
number of SM's defined in section
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiSMnext (ecx_contexttcontext,
uint16 slave,
ec_eepromSMtSM,
uint16 n 
)
+
+

Get next SM data from SII SM section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= slave number
[out]SM= first SM struct from SII
[in]n= SM number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_siistring (ecx_contexttcontext,
char * str,
uint16 slave,
uint16 Sn 
)
+
+

Get string from SII string section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[out]str= requested string, 0x00 if not found
[in]slave= slave number
[in]Sn= string number
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_statecheck (ecx_contexttcontext,
uint16 slave,
uint16 reqstate,
int timeout 
)
+
+

Check actual slave state. This is a blocking function.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number, 0 = all slaves
[in]reqstate= Requested state
[in]timeout= Timout value in us
+
+
+
Returns
Requested state, or found state after timeout.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeeprom (ecx_contexttcontext,
uint16 slave,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeepromAP (ecx_contexttcontext,
uint16 aiadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache. APWR method.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]aiadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeepromFP (ecx_contexttcontext,
uint16 configadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache. FPWR method.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]configadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_writestate (ecx_contexttcontext,
uint16 slave 
)
+
+

Write slave state, if slave = 0 then write to all slaves. The function does not check if the actual state is changed.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number, 0 = master
+
+
+
Returns
0
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
int64 ec_DCtime
+
+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_eringt ec_elist
+
+static
+
+

current slave for EEPROM cache buffer

+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_eepromFMMUt ec_FMMU
+
+static
+
+

buffer for EEPROM FMMU data

+ +
+
+ +
+
+ + + + +
ec_groupt ec_group[EC_MAXGROUP]
+
+

slave group structure

+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_idxstackT ec_idxstack
+
+static
+
+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_PDOassignt ec_PDOassign
+
+static
+
+

PDO assign struct to store data of one slave

+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_PDOdesct ec_PDOdesc
+
+static
+
+

PDO description struct to store data of one slave

+ +
+
+ +
+
+ + + + +
PACKED_END ec_slavet ec_slave[EC_MAXSLAVE]
+
+

Main slave data array. Each slave found on the network gets its own record. ec_slave[0] is reserved for the master. Structure gets filled in by the configuration function ec_config().

+ +
+
+ +
+
+ + + + +
int ec_slavecount
+
+

number of slaves found on the network

+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_eepromSMt ec_SM
+
+static
+
+

buffer for EEPROM SM data

+ +
+
+ +
+
+ + + + + +
+ + + + +
ec_SMcommtypet ec_SMcommtype
+
+static
+
+

SyncManager Communication Type struct to store data of one slave

+ +
+
+ +
+
+ + + + +
boolean EcatError = FALSE
+
+

Global variable TRUE if error available in error stack

+ +
+
+ +
+
+ + + + +
ecx_contextt ecx_context
+
+Initial value:
= {
+ +
&ec_slave[0],
+ + +
&ec_group[0],
+ +
&esibuf[0],
+
&esimap[0],
+
0,
+ + + +
0,
+
0,
+ + + + +
&ec_SM,
+ +
}
+
+
+
+ +
+
+ + + + +
ecx_portt ecx_port
+
+ +
+
+ +
+
+ + + + +
ecx_redportt ecx_redport
+
+ +
+
+ +
+
+ + + + + +
+ + + + +
uint8 esibuf[EC_MAXEEPBUF]
+
+static
+
+

cache for EEPROM read functions

+ +
+
+ +
+
+ + + + + +
+ + + + +
uint32 esimap[EC_MAXEEPBITMAP]
+
+static
+
+

bitmap for filled cache buffer bytes

+ +
+
+
+ + + + diff --git a/doc/html/ethercatmain_8h.html b/doc/html/ethercatmain_8h.html new file mode 100644 index 0000000..987c9f9 --- /dev/null +++ b/doc/html/ethercatmain_8h.html @@ -0,0 +1,2079 @@ + + + + + + +SOEM: ethercatmain.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatmain.h File Reference
+
+
+ +

Headerfile for ethercatmain.c. +More...

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

+Data Structures

struct  ec_adaptert
 
struct  ec_fmmut
 
struct  ec_smt
 
struct  ec_state_status
 
struct  ec_slavet
 
struct  ec_groupt
 
struct  ec_eepromFMMUt
 
struct  ec_eepromSMt
 
struct  ec_eepromPDOt
 
struct  ec_mbxheadert
 
struct  ec_alstatust
 
struct  ec_idxstackT
 
struct  ec_eringt
 
struct  ec_SMcommtypet
 
struct  ec_PDOassignt
 
struct  ec_PDOdesct
 
struct  ecx_contextt
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

#define EC_MAXELIST   64
 
#define EC_MAXNAME   40
 
#define EC_MAXSLAVE   200
 
#define EC_MAXGROUP   2
 
#define EC_MAXIOSEGMENTS   64
 
#define EC_MAXMBX   0x3ff
 
#define EC_MAXEEPDO   0x200
 
#define EC_MAXSM   8
 
#define EC_MAXFMMU   4
 
#define EC_MAXLEN_ADAPTERNAME   128
 
#define ECT_MBXPROT_AOE   0x0001
 
#define ECT_MBXPROT_EOE   0x0002
 
#define ECT_MBXPROT_COE   0x0004
 
#define ECT_MBXPROT_FOE   0x0008
 
#define ECT_MBXPROT_SOE   0x0010
 
#define ECT_MBXPROT_VOE   0x0020
 
#define ECT_COEDET_SDO   0x01
 
#define ECT_COEDET_SDOINFO   0x02
 
#define ECT_COEDET_PDOASSIGN   0x04
 
#define ECT_COEDET_PDOCONFIG   0x08
 
#define ECT_COEDET_UPLOAD   0x10
 
#define ECT_COEDET_SDOCA   0x20
 
#define EC_SMENABLEMASK   0xfffeffff
 
+ + + +

+Typedefs

typedef uint8 ec_mbxbuft [EC_MAXMBX+1]
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

ec_adaptert * ec_find_adapters (void)
 
void ec_free_adapters (ec_adaptert *adapter)
 
uint8 ec_nextmbxcnt (uint8 cnt)
 
void ec_clearmbx (ec_mbxbuft *Mbx)
 
void ecx_pusherror (ecx_contextt *context, const ec_errort *Ec)
 
boolean ecx_poperror (ecx_contextt *context, ec_errort *Ec)
 
boolean ecx_iserror (ecx_contextt *context)
 
void ecx_packeterror (ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode)
 
int ecx_init (ecx_contextt *context, char *ifname)
 
int ecx_init_redundant (ecx_contextt *context, ecx_redportt *redport, char *ifname, char *if2name)
 
void ecx_close (ecx_contextt *context)
 
uint8 ecx_siigetbyte (ecx_contextt *context, uint16 slave, uint16 address)
 
int16 ecx_siifind (ecx_contextt *context, uint16 slave, uint16 cat)
 
void ecx_siistring (ecx_contextt *context, char *str, uint16 slave, uint16 Sn)
 
uint16 ecx_siiFMMU (ecx_contextt *context, uint16 slave, ec_eepromFMMUt *FMMU)
 
uint16 ecx_siiSM (ecx_contextt *context, uint16 slave, ec_eepromSMt *SM)
 
uint16 ecx_siiSMnext (ecx_contextt *context, uint16 slave, ec_eepromSMt *SM, uint16 n)
 
int ecx_siiPDO (ecx_contextt *context, uint16 slave, ec_eepromPDOt *PDO, uint8 t)
 
int ecx_readstate (ecx_contextt *context)
 
int ecx_writestate (ecx_contextt *context, uint16 slave)
 
uint16 ecx_statecheck (ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout)
 
int ecx_mbxempty (ecx_contextt *context, uint16 slave, int timeout)
 
int ecx_mbxsend (ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout)
 
int ecx_mbxreceive (ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout)
 
void ecx_esidump (ecx_contextt *context, uint16 slave, uint8 *esibuf)
 
uint32 ecx_readeeprom (ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout)
 
int ecx_writeeeprom (ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout)
 
int ecx_eeprom2master (ecx_contextt *context, uint16 slave)
 
int ecx_eeprom2pdi (ecx_contextt *context, uint16 slave)
 
uint64 ecx_readeepromAP (ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout)
 
int ecx_writeeepromAP (ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout)
 
uint64 ecx_readeepromFP (ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout)
 
int ecx_writeeepromFP (ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout)
 
void ecx_readeeprom1 (ecx_contextt *context, uint16 slave, uint16 eeproma)
 
uint32 ecx_readeeprom2 (ecx_contextt *context, uint16 slave, int timeout)
 
int ecx_send_processdata_group (ecx_contextt *context, uint8 group)
 
int ecx_receive_processdata_group (ecx_contextt *context, uint8 group, int timeout)
 
int ecx_send_processdata (ecx_contextt *context)
 
int ecx_receive_processdata (ecx_contextt *context, int timeout)
 
+

Detailed Description

+

Headerfile for ethercatmain.c.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_MAXEEPDO   0x200
+
+

max. eeprom PDO entries

+ +
+
+ +
+
+ + + + +
#define EC_MAXELIST   64
+
+

max. etries in EtherCAT error list

+ +
+
+ +
+
+ + + + +
#define EC_MAXFMMU   4
+
+

max. FMMU used

+ +
+
+ +
+
+ + + + +
#define EC_MAXGROUP   2
+
+

max. number of groups

+ +
+
+ +
+
+ + + + +
#define EC_MAXIOSEGMENTS   64
+
+

max. number of IO segments per group

+ +
+
+ +
+
+ + + + +
#define EC_MAXLEN_ADAPTERNAME   128
+
+

max. Adapter

+ +
+
+ +
+
+ + + + +
#define EC_MAXMBX   0x3ff
+
+

max. mailbox size

+ +
+
+ +
+
+ + + + +
#define EC_MAXNAME   40
+
+

max. length of readable name in slavelist and Object Description List

+ +
+
+ +
+
+ + + + +
#define EC_MAXSLAVE   200
+
+

max. number of slaves in array

+ +
+
+ +
+
+ + + + +
#define EC_MAXSM   8
+
+

max. SM used

+ +
+
+ +
+
+ + + + +
#define EC_SMENABLEMASK   0xfffeffff
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_PDOASSIGN   0x04
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_PDOCONFIG   0x08
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_SDO   0x01
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_SDOCA   0x20
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_SDOINFO   0x02
+
+ +
+
+ +
+
+ + + + +
#define ECT_COEDET_UPLOAD   0x10
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_AOE   0x0001
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_COE   0x0004
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_EOE   0x0002
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_FOE   0x0008
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_SOE   0x0010
+
+ +
+
+ +
+
+ + + + +
#define ECT_MBXPROT_VOE   0x0020
+
+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef uint8 ec_mbxbuft[EC_MAXMBX+1]
+
+

mailbox buffer array

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void ec_clearmbx (ec_mbxbuftMbx)
+
+

Clear mailbox buffer.

+
Parameters
+ + +
[out]Mbx= Mailbox buffer to clear
+
+
+ +
+
+ +
+
+ + + + + + + + +
ec_adaptert* ec_find_adapters (void )
+
+

Create list over available network adapters.

+
Returns
First element in list over available network adapters.
+ +
+
+ +
+
+ + + + + + + + +
void ec_free_adapters (ec_adaptert * adapter)
+
+

Free dynamically allocated list over available network adapters.

+
Parameters
+ + +
[in]adapter= Struct holding adapter name, description and pointer to next.
+
+
+ +
+
+ +
+
+ + + + + + + + +
uint8 ec_nextmbxcnt (uint8 cnt)
+
+

Get index of next mailbox counter value. Used for Mailbox Link Layer.

+
Parameters
+ + +
[in]cnt= Mailbox counter value [0..7]
+
+
+
Returns
next mailbox counter value
+ +
+
+ +
+
+ + + + + + + + +
void ecx_close (ecx_contexttcontext)
+
+

Close lib.

+
Parameters
+ + +
[in]context= context struct
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_eeprom2master (ecx_contexttcontext,
uint16 slave 
)
+
+

Set eeprom control to master. Only if set to PDI.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_eeprom2pdi (ecx_contexttcontext,
uint16 slave 
)
+
+

Set eeprom control to PDI. Only if set to master.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_esidump (ecx_contexttcontext,
uint16 slave,
uint8 * esibuf 
)
+
+

Dump complete EEPROM data from slave in buffer.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[out]esibuf= EEPROM data buffer, make sure it is big enough.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_init (ecx_contexttcontext,
char * ifname 
)
+
+

Initialise lib in single NIC mode

+
Parameters
+ + + +
[in]context= context struct
[in]ifname= Dev name, f.e. "eth0"
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_init_redundant (ecx_contexttcontext,
ecx_redportt * redport,
char * ifname,
char * if2name 
)
+
+

Initialise lib in redundant NIC mode

+
Parameters
+ + + + + +
[in]context= context struct
[in]redport= pointer to redport, redundant port data
[in]ifname= Primary Dev name, f.e. "eth0"
[in]if2name= Secondary Dev name, f.e. "eth1"
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + +
boolean ecx_iserror (ecx_contexttcontext)
+
+

Check if error list has entries.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
TRUE if error list contains entries.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxempty (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Check if IN mailbox of slave is empty.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]timeout= Timeout in us
+
+
+
Returns
>0 is success
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxreceive (ecx_contexttcontext,
uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+

Read OUT mailbox from slave. Supports Mailbox Link Layer with repeat requests.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]mbx= Mailbox data
[in]timeout= Timeout in us
+
+
+
Returns
Work counter (>0 is success)
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_mbxsend (ecx_contexttcontext,
uint16 slave,
ec_mbxbuftmbx,
int timeout 
)
+
+

Write IN mailbox to slave.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]mbx= Mailbox data
[in]timeout= Timeout in us
+
+
+
Returns
Work counter (>0 is success)
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_packeterror (ecx_contexttcontext,
uint16 Slave,
uint16 Index,
uint8 SubIdx,
uint16 ErrorCode 
)
+
+

Report packet error

+
Parameters
+ + + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]Index= Index that generated error
[in]SubIdx= Subindex that generated error
[in]ErrorCode= Error code
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
boolean ecx_poperror (ecx_contexttcontext,
ec_errortEc 
)
+
+

Pops an error from the list.

+
Parameters
+ + + +
[in]context= context struct
[out]Ec= Struct describing the error.
+
+
+
Returns
TRUE if an error was popped.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void ecx_pusherror (ecx_contexttcontext,
const ec_errortEc 
)
+
+

Pushes an error on the error list.

+
Parameters
+ + + +
[in]context= context struct
[in]Ecpointer describing the error.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint32 ecx_readeeprom (ecx_contexttcontext,
uint16 slave,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_readeeprom1 (ecx_contexttcontext,
uint16 slave,
uint16 eeproma 
)
+
+

Read EEPROM from slave bypassing cache. Parallel read step 1, make request to slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint32 ecx_readeeprom2 (ecx_contexttcontext,
uint16 slave,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. Parallel read step 2, actual read from slave.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= Slave number
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ecx_readeepromAP (ecx_contexttcontext,
uint16 aiadr,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. APRD method.

+
Parameters
+ + + + + +
[in]context= context struct
[in]aiadr= auto increment address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 64bit or 32bit
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint64 ecx_readeepromFP (ecx_contexttcontext,
uint16 configadr,
uint16 eeproma,
int timeout 
)
+
+

Read EEPROM from slave bypassing cache. FPRD method.

+
Parameters
+ + + + + +
[in]context= context struct
[in]configadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]timeout= Timeout in us.
+
+
+
Returns
EEPROM data 64bit or 32bit
+ +
+
+ +
+
+ + + + + + + + +
int ecx_readstate (ecx_contexttcontext)
+
+

Read all slave states in ec_slave.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
lowest state found
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_receive_processdata (ecx_contexttcontext,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_receive_processdata_group (ecx_contexttcontext,
uint8 group,
int timeout 
)
+
+

Receive processdata from slaves. Second part from ec_send_processdata(). Received datagrams are recombined with the processdata with help from the stack. If a datagram contains input processdata it copies it to the processdata structure.

+
Parameters
+ + + + +
[in]context= context struct
[in]group= group number
[in]timeout= Timeout in us.
+
+
+
Returns
Work counter.
+ +
+
+ +
+
+ + + + + + + + +
int ecx_send_processdata (ecx_contexttcontext)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_send_processdata_group (ecx_contexttcontext,
uint8 group 
)
+
+

Transmit processdata to slaves. Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). Both the input and output processdata are transmitted. The outputs with the actual data, the inputs have a placeholder. The inputs are gathered with the receive processdata function. In contrast to the base LRW function this function is non-blocking. If the processdata does not fit in one datagram, multiple are used. In order to recombine the slave response, a stack is used.

+
Parameters
+ + + +
[in]context= context struct
[in]group= group number
+
+
+
Returns
>0 if processdata is transmitted.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int16 ecx_siifind (ecx_contexttcontext,
uint16 slave,
uint16 cat 
)
+
+

Find SII section header in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[in]cat= section category
+
+
+
Returns
byte address of section at section length entry, if not available then 0
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiFMMU (ecx_contexttcontext,
uint16 slave,
ec_eepromFMMUtFMMU 
)
+
+

Get FMMU data from SII FMMU section in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[out]FMMU= FMMU struct from SII, max. 4 FMMU's
+
+
+
Returns
number of FMMU's defined in section
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8 ecx_siigetbyte (ecx_contexttcontext,
uint16 slave,
uint16 address 
)
+
+

Read one byte from slave EEPROM via cache. If the cache location is empty then a read request is made to the slave. Depending on the slave capabillities the request is 4 or 8 bytes.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[in]address= eeprom address in bytes (slave uses words)
+
+
+
Returns
requested byte, if not available then 0xff
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_siiPDO (ecx_contexttcontext,
uint16 slave,
ec_eepromPDOtPDO,
uint8 t 
)
+
+

Get PDO data from SII PDO section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= slave number
[out]PDO= PDO struct from SII
[in]t= 0=RXPDO 1=TXPDO
+
+
+
Returns
mapping size in bits of PDO
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiSM (ecx_contexttcontext,
uint16 slave,
ec_eepromSMtSM 
)
+
+

Get SM data from SII SM section in slave EEPROM.

+
Parameters
+ + + + +
[in]context= context struct
[in]slave= slave number
[out]SM= first SM struct from SII
+
+
+
Returns
number of SM's defined in section
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_siiSMnext (ecx_contexttcontext,
uint16 slave,
ec_eepromSMtSM,
uint16 n 
)
+
+

Get next SM data from SII SM section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= slave number
[out]SM= first SM struct from SII
[in]n= SM number
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void ecx_siistring (ecx_contexttcontext,
char * str,
uint16 slave,
uint16 Sn 
)
+
+

Get string from SII string section in slave EEPROM.

+
Parameters
+ + + + + +
[in]context= context struct
[out]str= requested string, 0x00 if not found
[in]slave= slave number
[in]Sn= string number
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint16 ecx_statecheck (ecx_contexttcontext,
uint16 slave,
uint16 reqstate,
int timeout 
)
+
+

Check actual slave state. This is a blocking function.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number, 0 = all slaves
[in]reqstate= Requested state
[in]timeout= Timout value in us
+
+
+
Returns
Requested state, or found state after timeout.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeeprom (ecx_contexttcontext,
uint16 slave,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeepromAP (ecx_contexttcontext,
uint16 aiadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache. APWR method.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]aiadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_writeeepromFP (ecx_contexttcontext,
uint16 configadr,
uint16 eeproma,
uint16 data,
int timeout 
)
+
+

Write EEPROM to slave bypassing cache. FPWR method.

+
Parameters
+ + + + + + +
[in]context= context struct
[in]configadr= configured address of slave
[in]eeproma= (WORD) Address in the EEPROM
[in]data= 16bit data
[in]timeout= Timeout in us.
+
+
+
Returns
>0 if OK
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int ecx_writestate (ecx_contexttcontext,
uint16 slave 
)
+
+

Write slave state, if slave = 0 then write to all slaves. The function does not check if the actual state is changed.

+
Parameters
+ + + +
[in]context= context struct
[in]slave= Slave number, 0 = master
+
+
+
Returns
0
+ +
+
+
+ + + + diff --git a/doc/html/ethercatprint_8c.html b/doc/html/ethercatprint_8c.html new file mode 100644 index 0000000..6974e8b --- /dev/null +++ b/doc/html/ethercatprint_8c.html @@ -0,0 +1,489 @@ + + + + + + +SOEM: ethercatprint.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatprint.c File Reference
+
+
+ +

Module to convert EtherCAT errors to readable messages. +More...

+
#include <stdio.h>
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatmain.h"
+
+ + + + + + + + + +

+Data Structures

struct  ec_sdoerrorlist_t
 
struct  ec_ALstatuscodelist_t
 
struct  ec_soeerrorlist_t
 
struct  ec_mbxerrorlist_t
 
+ + + +

+Macros

#define EC_MAXERRORNAME   127
 
+ + + + + + + + + + + + + +

+Functions

char * ec_sdoerror2string (uint32 sdoerrorcode)
 
char * ec_ALstatuscode2string (uint16 ALstatuscode)
 
char * ec_soeerror2string (uint16 errorcode)
 
char * ec_mbxerror2string (uint16 errorcode)
 
char * ecx_elist2string (ecx_contextt *context)
 
char * ec_elist2string (void)
 
+ + + + + + + + + + + +

+Variables

char estring [EC_MAXERRORNAME]
 
const ec_sdoerrorlist_t ec_sdoerrorlist []
 
const ec_ALstatuscodelist_t ec_ALstatuscodelist []
 
const ec_soeerrorlist_t ec_soeerrorlist []
 
const ec_mbxerrorlist_t ec_mbxerrorlist []
 
+

Detailed Description

+

Module to convert EtherCAT errors to readable messages.

+

SDO abort messages and AL status codes are used to relay slave errors to the user application. This module converts the binary codes to readble text. For the defined error codes see the EtherCAT protocol documentation.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_MAXERRORNAME   127
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
char* ec_ALstatuscode2string (uint16 ALstatuscode)
+
+

Look up text string that belongs to AL status code.

+
Parameters
+ + +
[in]ALstatuscode= AL status code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ec_elist2string (void )
+
+ +
+
+ +
+
+ + + + + + + + +
char* ec_mbxerror2string (uint16 errorcode)
+
+

Look up text string that belongs to MBX error code.

+
Parameters
+ + +
[in]errorcode= MBX error code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ec_sdoerror2string (uint32 sdoerrorcode)
+
+

Look up text string that belongs to SDO error code.

+
Parameters
+ + +
[in]sdoerrorcode= SDO error code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ec_soeerror2string (uint16 errorcode)
+
+

Look up text string that belongs to SoE error code.

+
Parameters
+ + +
[in]errorcode= SoE error code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ecx_elist2string (ecx_contexttcontext)
+
+

Look up error in ec_errorlist and convert to text string.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
readable string
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
const ec_ALstatuscodelist_t ec_ALstatuscodelist[]
+
+Initial value:
= {
+
{0x0000 , "No error" },
+
{0x0001 , "Unspecified error" },
+
{0x0002 , "No memory" },
+
{0x0011 , "Invalid requested state change" },
+
{0x0012 , "Unknown requested state" },
+
{0x0013 , "Bootstrap not supported" },
+
{0x0014 , "No valid firmware" },
+
{0x0015 , "Invalid mailbox configuration" },
+
{0x0016 , "Invalid mailbox configuration" },
+
{0x0017 , "Invalid sync manager configuration" },
+
{0x0018 , "No valid inputs available" },
+
{0x0019 , "No valid outputs" },
+
{0x001A , "Synchronization error" },
+
{0x001B , "Sync manager watchdog" },
+
{0x001C , "Invalid sync Manager types" },
+
{0x001D , "Invalid output configuration" },
+
{0x001E , "Invalid input configuration" },
+
{0x001F , "Invalid watchdog configuration" },
+
{0x0020 , "Slave needs cold start" },
+
{0x0021 , "Slave needs INIT" },
+
{0x0022 , "Slave needs PREOP" },
+
{0x0023 , "Slave needs SAFEOP" },
+
{0x0024 , "Invalid input mapping" },
+
{0x0025 , "Invalid output mapping" },
+
{0x0026 , "Inconsistent settings" },
+
{0x0027 , "Freerun not supported" },
+
{0x0028 , "Synchronisation not supported" },
+
{0x0029 , "Freerun needs 3buffer mode" },
+
{0x002A , "Background watchdog" },
+
{0x002B , "No valid Inputs and Outputs" },
+
{0x002C , "Fatal sync error" },
+
{0x002D , "No sync error" },
+
{0x002E , "Invalid input FMMU configuration" },
+
{0x0030 , "Invalid DC SYNC configuration" },
+
{0x0031 , "Invalid DC latch configuration" },
+
{0x0032 , "PLL error" },
+
{0x0033 , "DC sync IO error" },
+
{0x0034 , "DC sync timeout error" },
+
{0x0035 , "DC invalid sync cycle time" },
+
{0x0035 , "DC invalid sync0 cycle time" },
+
{0x0035 , "DC invalid sync1 cycle time" },
+
{0x0042 , "MBX_EOE" },
+
{0x0043 , "MBX_COE" },
+
{0x0044 , "MBX_FOE" },
+
{0x0045 , "MBX_SOE" },
+
{0x004F , "MBX_VOE" },
+
{0x0050 , "EEPROM no access" },
+
{0x0051 , "EEPROM error" },
+
{0x0060 , "Slave restarted locally" },
+
{0x0061 , "Device identification value updated" },
+
{0x00f0 , "Application controller available" },
+
{0xffff , "Unknown" }
+
}
+

AL status code list definition

+ +
+
+ +
+
+ + + + +
const ec_mbxerrorlist_t ec_mbxerrorlist[]
+
+Initial value:
= {
+
{0x0000, "No error" },
+
{0x0001, "Syntax of 6 octet Mailbox Header is wrong" },
+
{0x0002, "The mailbox protocol is not supported" },
+
{0x0003, "Channel Field contains wrong value"},
+
{0x0004, "The service is no supported"},
+
{0x0005, "Invalid mailbox header"},
+
{0x0006, "Length of received mailbox data is too short"},
+
{0x0007, "No more memory in slave"},
+
{0x0008, "The lenght of data is inconsistent"},
+
{0xffff, "Unknown"}
+
}
+

MBX error list definition

+ +
+
+ +
+
+ + + + +
const ec_sdoerrorlist_t ec_sdoerrorlist[]
+
+Initial value:
= {
+
{0x00000000, "No error" },
+
{0x05030000, "Toggle bit not changed" },
+
{0x05040000, "SDO protocol timeout" },
+
{0x05040001, "Client/Server command specifier not valid or unknown" },
+
{0x05040005, "Out of memory" },
+
{0x06010000, "Unsupported access to an object" },
+
{0x06010001, "Attempt to read to a write only object" },
+
{0x06010002, "Attempt to write to a read only object" },
+
{0x06010003, "Subindex can not be written, SI0 must be 0 for write access" },
+
{0x06010004, "SDO Complete access not supported for variable length objects" },
+
{0x06010005, "Object length exceeds mailbox size" },
+
{0x06010006, "Object mapped to RxPDO, SDO download blocked" },
+
{0x06020000, "The object does not exist in the object directory" },
+
{0x06040041, "The object can not be mapped into the PDO" },
+
{0x06040042, "The number and length of the objects to be mapped would exceed the PDO length" },
+
{0x06040043, "General parameter incompatibility reason" },
+
{0x06040047, "General internal incompatibility in the device" },
+
{0x06060000, "Access failed due to a hardware error" },
+
{0x06070010, "Data type does not match, length of service parameter does not match" },
+
{0x06070012, "Data type does not match, length of service parameter too high" },
+
{0x06070013, "Data type does not match, length of service parameter too low" },
+
{0x06090011, "Subindex does not exist" },
+
{0x06090030, "Value range of parameter exceeded (only for write access)" },
+
{0x06090031, "Value of parameter written too high" },
+
{0x06090032, "Value of parameter written too low" },
+
{0x06090036, "Maximum value is less than minimum value" },
+
{0x08000000, "General error" },
+
{0x08000020, "Data cannot be transferred or stored to the application" },
+
{0x08000021, "Data cannot be transferred or stored to the application because of local control" },
+
{0x08000022, "Data cannot be transferred or stored to the application because of the present device state" },
+
{0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present" },
+
{0xffffffff, "Unknown" }
+
}
+

SDO error list definition

+ +
+
+ +
+
+ + + + +
const ec_soeerrorlist_t ec_soeerrorlist[]
+
+Initial value:
= {
+
{0x0000, "No error" },
+
{0x1001, "No IDN" },
+
{0x1009, "Invalid access to element 1" },
+
{0x2001, "No Name" },
+
{0x2002, "Name transmission too short" },
+
{0x2003, "Name transmission too long" },
+
{0x2004, "Name cannot be changed (read only)" },
+
{0x2005, "Name is write-protected at this time" },
+
{0x3002, "Attribute transmission too short" },
+
{0x3003, "Attribute transmission too long" },
+
{0x3004, "Attribute cannot be changed (read only)" },
+
{0x3005, "Attribute is write-protected at this time" },
+
{0x4001, "No units" },
+
{0x4002, "Unit transmission too short" },
+
{0x4003, "Unit transmission too long" },
+
{0x4004, "Unit cannot be changed (read only)" },
+
{0x4005, "Unit is write-protected at this time" },
+
{0x5001, "No minimum input value" },
+
{0x5002, "Minimum input value transmission too short" },
+
{0x5003, "Minimum input value transmission too long" },
+
{0x5004, "Minimum input value cannot be changed (read only)" },
+
{0x5005, "Minimum input value is write-protected at this time" },
+
{0x6001, "No maximum input value" },
+
{0x6002, "Maximum input value transmission too short" },
+
{0x6003, "Maximum input value transmission too long" },
+
{0x6004, "Maximum input value cannot be changed (read only)" },
+
{0x6005, "Maximum input value is write-protected at this time" },
+
{0x7002, "Operation data transmission too short" },
+
{0x7003, "Operation data transmission too long" },
+
{0x7004, "Operation data cannot be changed (read only)" },
+
{0x7005, "Operation data is write-protected at this time (state)" },
+
{0x7006, "Operation data is smaller than the minimum input value" },
+
{0x7007, "Operation data is smaller than the maximum input value" },
+
{0x7008, "Invalid operation data:Configured IDN will not be supported" },
+
{0x7009, "Operation data write protected by a password" },
+
{0x700A, "Operation data is write protected, it is configured cyclically" },
+
{0x700B, "Invalid indirect addressing: (e.g., data container, list handling)" },
+
{0x700C, "Operation data is write protected, due to other settings" },
+
{0x700D, "Reserved" },
+
{0x7010, "Procedure command already active" },
+
{0x7011, "Procedure command not interruptible" },
+
{0x7012, "Procedure command at this time not executable (state)" },
+
{0x7013, "Procedure command not executable (invalid or false parameters)" },
+
{0x7014, "No data state" },
+
{0x8001, "No default value" },
+
{0x8002, "Default value transmission too long" },
+
{0x8004, "Default value cannot be changed, read only" },
+
{0x800A, "Invalid drive number" },
+
{0x800A, "General error" },
+
{0x800A, "No element addressed" },
+
{0xffff, "Unknown" }
+
}
+

SoE error list definition

+ +
+
+ +
+
+ + + + +
char estring[EC_MAXERRORNAME]
+
+ +
+
+
+ + + + diff --git a/doc/html/ethercatprint_8h.html b/doc/html/ethercatprint_8h.html new file mode 100644 index 0000000..a6ba212 --- /dev/null +++ b/doc/html/ethercatprint_8h.html @@ -0,0 +1,169 @@ + + + + + + +SOEM: ethercatprint.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatprint.h File Reference
+
+
+ +

Headerfile for ethercatprint.c. +More...

+ + + + + + + + + + +

+Functions

char * ec_sdoerror2string (uint16 sdoerrorcode)
 
char * ec_ALstatuscode2string (uint16 ALstatuscode)
 
char * ec_soeerror2string (uint16 errorcode)
 
char * ecx_elist2string (ecx_contextt *context)
 
+

Detailed Description

+

Headerfile for ethercatprint.c.

+

Function Documentation

+ +
+
+ + + + + + + + +
char* ec_ALstatuscode2string (uint16 ALstatuscode)
+
+

Look up text string that belongs to AL status code.

+
Parameters
+ + +
[in]ALstatuscode= AL status code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ec_sdoerror2string (uint16 sdoerrorcode)
+
+ +
+
+ +
+
+ + + + + + + + +
char* ec_soeerror2string (uint16 errorcode)
+
+

Look up text string that belongs to SoE error code.

+
Parameters
+ + +
[in]errorcode= SoE error code as defined in EtherCAT protocol
+
+
+
Returns
readable string
+ +
+
+ +
+
+ + + + + + + + +
char* ecx_elist2string (ecx_contexttcontext)
+
+

Look up error in ec_errorlist and convert to text string.

+
Parameters
+ + +
[in]context= context struct
+
+
+
Returns
readable string
+ +
+
+
+ + + + diff --git a/doc/html/ethercatsoe_8c.html b/doc/html/ethercatsoe_8c.html new file mode 100644 index 0000000..31fa497 --- /dev/null +++ b/doc/html/ethercatsoe_8c.html @@ -0,0 +1,499 @@ + + + + + + +SOEM: ethercatsoe.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatsoe.c File Reference
+
+
+ +

Servo over EtherCAT (SoE) Module. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "osal.h"
+#include "oshw.h"
+#include "ethercattype.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatsoe.h"
+
+ + + +

+Data Structures

struct  ec_SoEt
 
+ + + + + + + + + + + + + + + +

+Functions

PACKED_END void ecx_SoEerror (ecx_contextt *context, uint16 Slave, uint16 idn, uint16 Error)
 
int ecx_SoEread (ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout)
 
int ecx_SoEwrite (ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout)
 
int ecx_readIDNmap (ecx_contextt *context, uint16 slave, int *Osize, int *Isize)
 
int ec_SoEread (uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout)
 
int ec_SoEwrite (uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout)
 
int ec_readIDNmap (uint16 slave, int *Osize, int *Isize)
 
+

Detailed Description

+

Servo over EtherCAT (SoE) Module.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int ec_readIDNmap (uint16 slave,
int * Osize,
int * Isize 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_SoEread (uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int * psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ec_SoEwrite (uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int psize,
void * p,
int timeout 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readIDNmap (ecx_contexttcontext,
uint16 slave,
int * Osize,
int * Isize 
)
+
+

SoE read AT and MTD mapping.

+

SoE has standard indexes defined for mapping. This function tries to read them and collect a full input and output mapping size of designated slave.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]Osize= Size in bits of output mapping (MTD) found
[out]Isize= Size in bits of input mapping (AT) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PACKED_END void ecx_SoEerror (ecx_contexttcontext,
uint16 Slave,
uint16 idn,
uint16 Error 
)
+
+

Report SoE error.

+
Parameters
+ + + + + +
[in]context= context struct
[in]Slave= Slave number
[in]idn= IDN that generated error
[in]Error= Error code, see EtherCAT documentation for list
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SoEread (ecx_contexttcontext,
uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int * psize,
void * p,
int timeout 
)
+
+

SoE read, blocking.

+

The IDN object of the selected slave and DriveNo is read. If a response is larger than the mailbox size then the response is segmented. The function will combine all segments and copy them to the parameter buffer.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]driveNo= Drive number in slave
[in]elementflags= Flags to select what properties of IDN are to be transfered.
[in]idn= IDN.
[in,out]psize= Size in bytes of parameter buffer, returns bytes read from SoE.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SoEwrite (ecx_contexttcontext,
uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int psize,
void * p,
int timeout 
)
+
+

SoE write, blocking.

+

The IDN object of the selected slave and DriveNo is written. If a response is larger than the mailbox size then the response is segmented.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]driveNo= Drive number in slave
[in]elementflags= Flags to select what properties of IDN are to be transfered.
[in]idn= IDN.
[in]psize= Size in bytes of parameter buffer.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercatsoe_8h.html b/doc/html/ethercatsoe_8h.html new file mode 100644 index 0000000..8d09621 --- /dev/null +++ b/doc/html/ethercatsoe_8h.html @@ -0,0 +1,638 @@ + + + + + + +SOEM: ethercatsoe.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercatsoe.h File Reference
+
+
+ +

Headerfile for ethercatsoe.c. +More...

+ + + + + + + + + + +

+Data Structures

struct  ec_SoEnamet
 
struct  ec_SoElistt
 
struct  ec_SoEmappingt
 
struct  ec_SoEattributet
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

#define EC_SOE_DATASTATE_B   0x01
 
#define EC_SOE_NAME_B   0x02
 
#define EC_SOE_ATTRIBUTE_B   0x04
 
#define EC_SOE_UNIT_B   0x08
 
#define EC_SOE_MIN_B   0x10
 
#define EC_SOE_MAX_B   0x20
 
#define EC_SOE_VALUE_B   0x40
 
#define EC_SOE_DEFAULT_B   0x80
 
#define EC_SOE_MAXNAME   60
 
#define EC_SOE_MAXMAPPING   64
 
#define EC_IDN_MDTCONFIG   24
 
#define EC_IDN_ATCONFIG   16
 
#define EC_SOE_LENGTH_1   0x00
 
#define EC_SOE_LENGTH_2   0x01
 
#define EC_SOE_LENGTH_4   0x02
 
#define EC_SOE_LENGTH_8   0x03
 
#define EC_SOE_TYPE_BINARY   0x00
 
#define EC_SOE_TYPE_UINT   0x01
 
#define EC_SOE_TYPE_INT   0x02
 
#define EC_SOE_TYPE_HEX   0x03
 
#define EC_SOE_TYPE_STRING   0x04
 
#define EC_SOE_TYPE_IDN   0x05
 
#define EC_SOE_TYPE_FLOAT   0x06
 
#define EC_SOE_TYPE_PARAMETER   0x07
 
+ + + + + + + +

+Functions

PACKED_END int ecx_SoEread (ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout)
 
int ecx_SoEwrite (ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout)
 
int ecx_readIDNmap (ecx_contextt *context, uint16 slave, int *Osize, int *Isize)
 
+

Detailed Description

+

Headerfile for ethercatsoe.c.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_IDN_ATCONFIG   16
+
+ +
+
+ +
+
+ + + + +
#define EC_IDN_MDTCONFIG   24
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_ATTRIBUTE_B   0x04
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_DATASTATE_B   0x01
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_DEFAULT_B   0x80
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_LENGTH_1   0x00
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_LENGTH_2   0x01
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_LENGTH_4   0x02
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_LENGTH_8   0x03
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_MAX_B   0x20
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_MAXMAPPING   64
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_MAXNAME   60
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_MIN_B   0x10
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_NAME_B   0x02
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_BINARY   0x00
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_FLOAT   0x06
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_HEX   0x03
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_IDN   0x05
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_INT   0x02
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_PARAMETER   0x07
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_STRING   0x04
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_TYPE_UINT   0x01
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_UNIT_B   0x08
+
+ +
+
+ +
+
+ + + + +
#define EC_SOE_VALUE_B   0x40
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_readIDNmap (ecx_contexttcontext,
uint16 slave,
int * Osize,
int * Isize 
)
+
+

SoE read AT and MTD mapping.

+

SoE has standard indexes defined for mapping. This function tries to read them and collect a full input and output mapping size of designated slave.

+
Parameters
+ + + + + +
[in]context= context struct
[in]slave= Slave number
[out]Osize= Size in bits of output mapping (MTD) found
[out]Isize= Size in bits of input mapping (AT) found
+
+
+
Returns
>0 if mapping succesful.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PACKED_END int ecx_SoEread (ecx_contexttcontext,
uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int * psize,
void * p,
int timeout 
)
+
+

SoE read, blocking.

+

The IDN object of the selected slave and DriveNo is read. If a response is larger than the mailbox size then the response is segmented. The function will combine all segments and copy them to the parameter buffer.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]driveNo= Drive number in slave
[in]elementflags= Flags to select what properties of IDN are to be transfered.
[in]idn= IDN.
[in,out]psize= Size in bytes of parameter buffer, returns bytes read from SoE.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int ecx_SoEwrite (ecx_contexttcontext,
uint16 slave,
uint8 driveNo,
uint8 elementflags,
uint16 idn,
int psize,
void * p,
int timeout 
)
+
+

SoE write, blocking.

+

The IDN object of the selected slave and DriveNo is written. If a response is larger than the mailbox size then the response is segmented.

+
Parameters
+ + + + + + + + + +
[in]context= context struct
[in]slave= Slave number
[in]driveNo= Drive number in slave
[in]elementflags= Flags to select what properties of IDN are to be transfered.
[in]idn= IDN.
[in]psize= Size in bytes of parameter buffer.
[out]p= Pointer to parameter buffer
[in]timeout= Timeout in us, standard is EC_TIMEOUTRXM
+
+
+
Returns
Workcounter from last slave response
+ +
+
+
+ + + + diff --git a/doc/html/ethercattype_8h.html b/doc/html/ethercattype_8h.html new file mode 100644 index 0000000..1a55056 --- /dev/null +++ b/doc/html/ethercattype_8h.html @@ -0,0 +1,1882 @@ + + + + + + +SOEM: ethercattype.h File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
ethercattype.h File Reference
+
+
+ +

General typedefs and defines for EtherCAT. +More...

+
#include <osal.h>
+
+ + + + + + + +

+Data Structures

struct  ec_etherheadert
 
struct  ec_comt
 
struct  ec_errort
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

#define EC_LITTLE_ENDIAN
 
#define EC_VER1
 
#define EC_ERROR   -3
 
#define EC_NOFRAME   -1
 
#define EC_OTHERFRAME   -2
 
#define EC_MAXECATFRAME   1518
 
#define EC_MAXLRWDATA   (EC_MAXECATFRAME - 14 - 2 - 10 - 2 - 4)
 
#define EC_FIRSTDCDATAGRAM   20
 
#define EC_BUFSIZE   EC_MAXECATFRAME
 
#define EC_ECATTYPE   0x1000
 
#define EC_MAXBUF   16
 
#define EC_TIMEOUTRET   2000
 
#define EC_TIMEOUTRET3   (EC_TIMEOUTRET * 3)
 
#define EC_TIMEOUTSAFE   20000
 
#define EC_TIMEOUTEEP   20000
 
#define EC_TIMEOUTTXM   20000
 
#define EC_TIMEOUTRXM   700000
 
#define EC_TIMEOUTSTATE   2000000
 
#define EC_MAXEEPBITMAP   128
 
#define EC_MAXEEPBUF   EC_MAXEEPBITMAP << 5
 
#define EC_DEFAULTRETRIES   3
 
#define ETH_HEADERSIZE   sizeof(ec_etherheadert)
 
#define EC_HEADERSIZE   sizeof(ec_comt)
 
#define EC_ELENGTHSIZE   sizeof(uint16)
 
#define EC_CMDOFFSET   EC_ELENGTHSIZE
 
#define EC_WKCSIZE   sizeof(uint16)
 
#define EC_DATAGRAMFOLLOWS   (1 << 15)
 
#define EC_ESTAT_R64   0x0040
 
#define EC_ESTAT_BUSY   0x8000
 
#define EC_ESTAT_EMASK   0x7800
 
#define EC_ESTAT_NACK   0x2000
 
#define ECT_SII_START   0x0040
 
#define ECT_SDO_SMCOMMTYPE   0x1c00
 
#define ECT_SDO_PDOASSIGN   0x1c10
 
#define ECT_SDO_RXPDOASSIGN   0x1c12
 
#define ECT_SDO_TXPDOASSIGN   0x1c13
 
#define ETH_P_ECAT   0x88A4
 
#define MK_WORD(msb, lsb)   ((((uint16)(msb))<<8) | (lsb))
 
#define HI_BYTE(w)   ((w) >> 8)
 
#define LO_BYTE(w)   ((w) & 0x00ff)
 
#define SWAP(w)   ((((w)& 0xff00) >> 8) | (((w) & 0x00ff) << 8))
 
#define LO_WORD(l)   ((l) & 0xffff)
 
#define HI_WORD(l)   ((l) >> 16)
 
#define get_unaligned(ptr)   ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
 
#define put_unaligned32(val, ptr)   (memcpy((ptr), &(val), 4))
 
#define put_unaligned64(val, ptr)   (memcpy((ptr), &(val), 8))
 
#define htoes(A)   (A)
 
#define htoel(A)   (A)
 
#define htoell(A)   (A)
 
#define etohs(A)   (A)
 
#define etohl(A)   (A)
 
#define etohll(A)   (A)
 
+ + + +

+Typedefs

typedef uint8 ec_bufT [EC_BUFSIZE]
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Enumerations

enum  ec_err {
+  EC_ERR_OK = 0, +EC_ERR_ALREADY_INITIALIZED, +EC_ERR_NOT_INITIALIZED, +EC_ERR_TIMEOUT, +
+  EC_ERR_NO_SLAVES, +EC_ERR_NOK +
+ }
 
enum  ec_state {
+  EC_STATE_INIT = 0x01, +EC_STATE_PRE_OP = 0x02, +EC_STATE_BOOT = 0x03, +EC_STATE_SAFE_OP = 0x04, +
+  EC_STATE_OPERATIONAL = 0x08, +EC_STATE_ACK = 0x10, +EC_STATE_ERROR = 0x10 +
+ }
 
enum  ec_bufstate {
+  EC_BUF_EMPTY = 0x00, +EC_BUF_ALLOC = 0x01, +EC_BUF_TX = 0x02, +EC_BUF_RCVD = 0x03, +
+  EC_BUF_COMPLETE = 0x04 +
+ }
 
enum  ec_datatype {
+  ECT_BOOLEAN = 0x0001, +ECT_INTEGER8 = 0x0002, +ECT_INTEGER16 = 0x0003, +ECT_INTEGER32 = 0x0004, +
+  ECT_UNSIGNED8 = 0x0005, +ECT_UNSIGNED16 = 0x0006, +ECT_UNSIGNED32 = 0x0007, +ECT_REAL32 = 0x0008, +
+  ECT_VISIBLE_STRING = 0x0009, +ECT_OCTET_STRING = 0x000A, +ECT_UNICODE_STRING = 0x000B, +ECT_TIME_OF_DAY = 0x000C, +
+  ECT_TIME_DIFFERENCE = 0x000D, +ECT_DOMAIN = 0x000F, +ECT_INTEGER24 = 0x0010, +ECT_REAL64 = 0x0011, +
+  ECT_INTEGER64 = 0x0015, +ECT_UNSIGNED24 = 0x0016, +ECT_UNSIGNED64 = 0x001B, +ECT_BIT1 = 0x0030, +
+  ECT_BIT2 = 0x0031, +ECT_BIT3 = 0x0032, +ECT_BIT4 = 0x0033, +ECT_BIT5 = 0x0034, +
+  ECT_BIT6 = 0x0035, +ECT_BIT7 = 0x0036, +ECT_BIT8 = 0x0037 +
+ }
 
enum  ec_cmdtype {
+  EC_CMD_NOP = 0x00, +EC_CMD_APRD, +EC_CMD_APWR, +EC_CMD_APRW, +
+  EC_CMD_FPRD, +EC_CMD_FPWR, +EC_CMD_FPRW, +EC_CMD_BRD, +
+  EC_CMD_BWR, +EC_CMD_BRW, +EC_CMD_LRD, +EC_CMD_LWR, +
+  EC_CMD_LRW, +EC_CMD_ARMW, +EC_CMD_FRMW +
+ }
 
enum  ec_ecmdtype { EC_ECMD_NOP = 0x0000, +EC_ECMD_READ = 0x0100, +EC_ECMD_WRITE = 0x0201, +EC_ECMD_RELOAD = 0x0300 + }
 
enum  {
+  ECT_SII_STRING = 10, +ECT_SII_GENERAL = 30, +ECT_SII_FMMU = 40, +ECT_SII_SM = 41, +
+  ECT_SII_PDO = 50 +
+ }
 
enum  {
+  ECT_SII_MANUF = 0x0008, +ECT_SII_ID = 0x000a, +ECT_SII_REV = 0x000c, +ECT_SII_BOOTRXMBX = 0x0014, +
+  ECT_SII_BOOTTXMBX = 0x0016, +ECT_SII_MBXSIZE = 0x0019, +ECT_SII_TXMBXADR = 0x001a, +ECT_SII_RXMBXADR = 0x0018, +
+  ECT_SII_MBXPROTO = 0x001c +
+ }
 
enum  {
+  ECT_MBXT_ERR = 0x00, +ECT_MBXT_AOE, +ECT_MBXT_EOE, +ECT_MBXT_COE, +
+  ECT_MBXT_FOE, +ECT_MBXT_SOE, +ECT_MBXT_VOE = 0x0f +
+ }
 
enum  {
+  ECT_COES_EMERGENCY = 0x01, +ECT_COES_SDOREQ, +ECT_COES_SDORES, +ECT_COES_TXPDO, +
+  ECT_COES_RXPDO, +ECT_COES_TXPDO_RR, +ECT_COES_RXPDO_RR, +ECT_COES_SDOINFO +
+ }
 
enum  {
+  ECT_SDO_DOWN_INIT = 0x21, +ECT_SDO_DOWN_EXP = 0x23, +ECT_SDO_DOWN_INIT_CA = 0x31, +ECT_SDO_UP_REQ = 0x40, +
+  ECT_SDO_UP_REQ_CA = 0x50, +ECT_SDO_SEG_UP_REQ = 0x60, +ECT_SDO_ABORT = 0x80 +
+ }
 
enum  {
+  ECT_GET_ODLIST_REQ = 0x01, +ECT_GET_ODLIST_RES = 0x02, +ECT_GET_OD_REQ = 0x03, +ECT_GET_OD_RES = 0x04, +
+  ECT_GET_OE_REQ = 0x05, +ECT_GET_OE_RES = 0x06, +ECT_SDOINFO_ERROR = 0x07 +
+ }
 
enum  {
+  ECT_FOE_READ = 0x01, +ECT_FOE_WRITE, +ECT_FOE_DATA, +ECT_FOE_ACK, +
+  ECT_FOE_ERROR, +ECT_FOE_BUSY +
+ }
 
enum  {
+  ECT_SOE_READREQ = 0x01, +ECT_SOE_READRES, +ECT_SOE_WRITEREQ, +ECT_SOE_WRITERES, +
+  ECT_SOE_NOTIFICATION, +ECT_SOE_EMERGENCY +
+ }
 
enum  {
+  ECT_REG_TYPE = 0x0000, +ECT_REG_PORTDES = 0x0007, +ECT_REG_ESCSUP = 0x0008, +ECT_REG_STADR = 0x0010, +
+  ECT_REG_ALIAS = 0x0012, +ECT_REG_DLCTL = 0x0100, +ECT_REG_DLPORT = 0x0101, +ECT_REG_DLALIAS = 0x0103, +
+  ECT_REG_DLSTAT = 0x0110, +ECT_REG_ALCTL = 0x0120, +ECT_REG_ALSTAT = 0x0130, +ECT_REG_ALSTATCODE = 0x0134, +
+  ECT_REG_PDICTL = 0x0140, +ECT_REG_IRQMASK = 0x0200, +ECT_REG_RXERR = 0x0300, +ECT_REG_EEPCFG = 0x0500, +
+  ECT_REG_EEPCTL = 0x0502, +ECT_REG_EEPSTAT = 0x0502, +ECT_REG_EEPADR = 0x0504, +ECT_REG_EEPDAT = 0x0508, +
+  ECT_REG_FMMU0 = 0x0600, +ECT_REG_FMMU1 = ECT_REG_FMMU0 + 0x10, +ECT_REG_FMMU2 = ECT_REG_FMMU1 + 0x10, +ECT_REG_FMMU3 = ECT_REG_FMMU2 + 0x10, +
+  ECT_REG_SM0 = 0x0800, +ECT_REG_SM1 = ECT_REG_SM0 + 0x08, +ECT_REG_SM2 = ECT_REG_SM1 + 0x08, +ECT_REG_SM3 = ECT_REG_SM2 + 0x08, +
+  ECT_REG_SM0STAT = ECT_REG_SM0 + 0x05, +ECT_REG_SM1STAT = ECT_REG_SM1 + 0x05, +ECT_REG_SM1ACT = ECT_REG_SM1 + 0x06, +ECT_REG_SM1CONTR = ECT_REG_SM1 + 0x07, +
+  ECT_REG_DCTIME0 = 0x0900, +ECT_REG_DCTIME1 = 0x0904, +ECT_REG_DCTIME2 = 0x0908, +ECT_REG_DCTIME3 = 0x090C, +
+  ECT_REG_DCSYSTIME = 0x0910, +ECT_REG_DCSOF = 0x0918, +ECT_REG_DCSYSOFFSET = 0x0920, +ECT_REG_DCSYSDELAY = 0x0928, +
+  ECT_REG_DCSYSDIFF = 0x092C, +ECT_REG_DCSPEEDCNT = 0x0930, +ECT_REG_DCTIMEFILT = 0x0934, +ECT_REG_DCCUC = 0x0980, +
+  ECT_REG_DCSYNCACT = 0x0981, +ECT_REG_DCSTART0 = 0x0990, +ECT_REG_DCCYCLE0 = 0x09A0, +ECT_REG_DCCYCLE1 = 0x09A4 +
+ }
 
enum  ec_err_type {
+  EC_ERR_TYPE_SDO_ERROR = 0, +EC_ERR_TYPE_EMERGENCY = 1, +EC_ERR_TYPE_PACKET_ERROR = 3, +EC_ERR_TYPE_SDOINFO_ERROR = 4, +
+  EC_ERR_TYPE_FOE_ERROR = 5, +EC_ERR_TYPE_FOE_BUF2SMALL = 6, +EC_ERR_TYPE_FOE_PACKETNUMBER = 7, +EC_ERR_TYPE_SOE_ERROR = 8, +
+  EC_ERR_TYPE_MBX_ERROR = 9 +
+ }
 
+

Detailed Description

+

General typedefs and defines for EtherCAT.

+

Defines that could need optimalisation for specific applications are the EC_TIMEOUTxxx. Assumptions for the standard settings are a standard linux PC or laptop and a wired connection to maximal 100 slaves. For use with wireless connections or lots of slaves the timouts need increasing. For fast systems running Xenomai and RT-net or alike the timeouts need to be shorter.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_BUFSIZE   EC_MAXECATFRAME
+
+

standard frame buffer size in bytes

+ +
+
+ +
+
+ + + + +
#define EC_CMDOFFSET   EC_ELENGTHSIZE
+
+

offset position of command in EtherCAT header

+ +
+
+ +
+
+ + + + +
#define EC_DATAGRAMFOLLOWS   (1 << 15)
+
+

definition of datagram follows bit in ec_comt.dlength

+ +
+
+ +
+
+ + + + +
#define EC_DEFAULTRETRIES   3
+
+

default number of retries if wkc <= 0

+ +
+
+ +
+
+ + + + +
#define EC_ECATTYPE   0x1000
+
+

datagram type EtherCAT

+ +
+
+ +
+
+ + + + +
#define EC_ELENGTHSIZE   sizeof(uint16)
+
+

size of ec_comt.elength item in EtherCAT header

+ +
+
+ +
+
+ + + + +
#define EC_ERROR   -3
+
+

return value general error

+ +
+
+ +
+
+ + + + +
#define EC_ESTAT_BUSY   0x8000
+
+

EEprom state machine busy flag

+ +
+
+ +
+
+ + + + +
#define EC_ESTAT_EMASK   0x7800
+
+

EEprom state machine error flag mask

+ +
+
+ +
+
+ + + + +
#define EC_ESTAT_NACK   0x2000
+
+

EEprom state machine error acknowledge

+ +
+
+ +
+
+ + + + +
#define EC_ESTAT_R64   0x0040
+
+

EEprom state machine read size

+ +
+
+ +
+
+ + + + +
#define EC_FIRSTDCDATAGRAM   20
+
+

size of DC datagram used in first LRW frame

+ +
+
+ +
+
+ + + + +
#define EC_HEADERSIZE   sizeof(ec_comt)
+
+

EtherCAT header size

+ +
+
+ +
+
+ + + + +
#define EC_LITTLE_ENDIAN
+
+

Define Little or Big endian target

+ +
+
+ +
+
+ + + + +
#define EC_MAXBUF   16
+
+

number of frame buffers per channel (tx, rx1 rx2)

+ +
+
+ +
+
+ + + + +
#define EC_MAXECATFRAME   1518
+
+

maximum EtherCAT frame length in bytes

+ +
+
+ +
+
+ + + + +
#define EC_MAXEEPBITMAP   128
+
+

size of EEPROM bitmap cache

+ +
+
+ +
+
+ + + + +
#define EC_MAXEEPBUF   EC_MAXEEPBITMAP << 5
+
+

size of EEPROM cache buffer

+ +
+
+ +
+
+ + + + +
#define EC_MAXLRWDATA   (EC_MAXECATFRAME - 14 - 2 - 10 - 2 - 4)
+
+

maximum EtherCAT LRW frame length in bytes

+ +
+
+ +
+
+ + + + +
#define EC_NOFRAME   -1
+
+

return value no frame returned

+ +
+
+ +
+
+ + + + +
#define EC_OTHERFRAME   -2
+
+

return value unknown frame received

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTEEP   20000
+
+

timeout value in us for EEPROM access

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTRET   2000
+
+

timeout value in us for tx frame to return to rx

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTRET3   (EC_TIMEOUTRET * 3)
+
+

timeout value in us for safe data transfer, max. triple retry

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTRXM   700000
+
+

timeout value in us for rx mailbox cycle

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTSAFE   20000
+
+

timeout value in us for return "safe" variant (f.e. wireless)

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTSTATE   2000000
+
+

timeout value in us for check statechange

+ +
+
+ +
+
+ + + + +
#define EC_TIMEOUTTXM   20000
+
+

timeout value in us for tx mailbox cycle

+ +
+
+ +
+
+ + + + +
#define EC_VER1
+
+

define EC_VER1 if version 1 default context and functions are needed comment if application uses only ecx_ functions and own context

+ +
+
+ +
+
+ + + + +
#define EC_WKCSIZE   sizeof(uint16)
+
+

size of workcounter item in EtherCAT datagram

+ +
+
+ +
+
+ + + + +
#define ECT_SDO_PDOASSIGN   0x1c10
+
+

standard SDO PDO assignment

+ +
+
+ +
+
+ + + + +
#define ECT_SDO_RXPDOASSIGN   0x1c12
+
+

standard SDO RxPDO assignment

+ +
+
+ +
+
+ + + + +
#define ECT_SDO_SMCOMMTYPE   0x1c00
+
+

standard SDO Sync Manager Communication Type

+ +
+
+ +
+
+ + + + +
#define ECT_SDO_TXPDOASSIGN   0x1c13
+
+

standard SDO TxPDO assignment

+ +
+
+ +
+
+ + + + +
#define ECT_SII_START   0x0040
+
+

Start address SII sections in Eeprom

+ +
+
+ +
+
+ + + + +
#define ETH_HEADERSIZE   sizeof(ec_etherheadert)
+
+

ethernet header size

+ +
+
+ +
+
+ + + + +
#define ETH_P_ECAT   0x88A4
+
+

Ethercat packet type

+ +
+
+ +
+
+ + + + + + + + +
#define etohl( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define etohll( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define etohs( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define get_unaligned( ptr)   ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+ +
+
+ +
+
+ + + + + + + + +
#define HI_BYTE( w)   ((w) >> 8)
+
+

Macro to get hi byte of a word

+ +
+
+ +
+
+ + + + + + + + +
#define HI_WORD( l)   ((l) >> 16)
+
+

Macro to get hi word of a dword

+ +
+
+ +
+
+ + + + + + + + +
#define htoel( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define htoell( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define htoes( A)   (A)
+
+ +
+
+ +
+
+ + + + + + + + +
#define LO_BYTE( w)   ((w) & 0x00ff)
+
+

Macro to get low byte of a word

+ +
+
+ +
+
+ + + + + + + + +
#define LO_WORD( l)   ((l) & 0xffff)
+
+

Macro to get hi word of a dword

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
#define MK_WORD( msb,
 lsb 
)   ((((uint16)(msb))<<8) | (lsb))
+
+

Helper macros Macro to make a word from 2 bytes

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
#define put_unaligned32( val,
 ptr 
)   (memcpy((ptr), &(val), 4))
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
#define put_unaligned64( val,
 ptr 
)   (memcpy((ptr), &(val), 8))
+
+ +
+
+ +
+
+ + + + + + + + +
#define SWAP( w)   ((((w)& 0xff00) >> 8) | (((w) & 0x00ff) << 8))
+
+

Macro to swap hi and low byte of a word

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef uint8 ec_bufT[EC_BUFSIZE]
+
+

definition for frame buffers

+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
anonymous enum
+
+ + + + + + +
Enumerator
ECT_SII_STRING  +

SII category strings

+
ECT_SII_GENERAL  +

SII category general

+
ECT_SII_FMMU  +

SII category FMMU

+
ECT_SII_SM  +

SII category SM

+
ECT_SII_PDO  +

SII category PDO

+
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

Item offsets in SII general section

+ + + + + + + + + + +
Enumerator
ECT_SII_MANUF  +
ECT_SII_ID  +
ECT_SII_REV  +
ECT_SII_BOOTRXMBX  +
ECT_SII_BOOTTXMBX  +
ECT_SII_MBXSIZE  +
ECT_SII_TXMBXADR  +
ECT_SII_RXMBXADR  +
ECT_SII_MBXPROTO  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

Mailbox types definitions

+ + + + + + + + +
Enumerator
ECT_MBXT_ERR  +

Error mailbox type

+
ECT_MBXT_AOE  +

ADS over EtherCAT mailbox type

+
ECT_MBXT_EOE  +

Ethernet over EtherCAT mailbox type

+
ECT_MBXT_COE  +

CANopen over EtherCAT mailbox type

+
ECT_MBXT_FOE  +

File over EtherCAT mailbox type

+
ECT_MBXT_SOE  +

Servo over EtherCAT mailbox type

+
ECT_MBXT_VOE  +

Vendor over EtherCAT mailbox type

+
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

CoE mailbox types

+ + + + + + + + + +
Enumerator
ECT_COES_EMERGENCY  +
ECT_COES_SDOREQ  +
ECT_COES_SDORES  +
ECT_COES_TXPDO  +
ECT_COES_RXPDO  +
ECT_COES_TXPDO_RR  +
ECT_COES_RXPDO_RR  +
ECT_COES_SDOINFO  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

CoE SDO commands

+ + + + + + + + +
Enumerator
ECT_SDO_DOWN_INIT  +
ECT_SDO_DOWN_EXP  +
ECT_SDO_DOWN_INIT_CA  +
ECT_SDO_UP_REQ  +
ECT_SDO_UP_REQ_CA  +
ECT_SDO_SEG_UP_REQ  +
ECT_SDO_ABORT  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

CoE Object Description commands

+ + + + + + + + +
Enumerator
ECT_GET_ODLIST_REQ  +
ECT_GET_ODLIST_RES  +
ECT_GET_OD_REQ  +
ECT_GET_OD_RES  +
ECT_GET_OE_REQ  +
ECT_GET_OE_RES  +
ECT_SDOINFO_ERROR  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

FoE opcodes

+ + + + + + + +
Enumerator
ECT_FOE_READ  +
ECT_FOE_WRITE  +
ECT_FOE_DATA  +
ECT_FOE_ACK  +
ECT_FOE_ERROR  +
ECT_FOE_BUSY  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

SoE opcodes

+ + + + + + + +
Enumerator
ECT_SOE_READREQ  +
ECT_SOE_READRES  +
ECT_SOE_WRITEREQ  +
ECT_SOE_WRITERES  +
ECT_SOE_NOTIFICATION  +
ECT_SOE_EMERGENCY  +
+ +
+
+ +
+
+ + + + +
anonymous enum
+
+

Ethercat registers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
ECT_REG_TYPE  +
ECT_REG_PORTDES  +
ECT_REG_ESCSUP  +
ECT_REG_STADR  +
ECT_REG_ALIAS  +
ECT_REG_DLCTL  +
ECT_REG_DLPORT  +
ECT_REG_DLALIAS  +
ECT_REG_DLSTAT  +
ECT_REG_ALCTL  +
ECT_REG_ALSTAT  +
ECT_REG_ALSTATCODE  +
ECT_REG_PDICTL  +
ECT_REG_IRQMASK  +
ECT_REG_RXERR  +
ECT_REG_EEPCFG  +
ECT_REG_EEPCTL  +
ECT_REG_EEPSTAT  +
ECT_REG_EEPADR  +
ECT_REG_EEPDAT  +
ECT_REG_FMMU0  +
ECT_REG_FMMU1  +
ECT_REG_FMMU2  +
ECT_REG_FMMU3  +
ECT_REG_SM0  +
ECT_REG_SM1  +
ECT_REG_SM2  +
ECT_REG_SM3  +
ECT_REG_SM0STAT  +
ECT_REG_SM1STAT  +
ECT_REG_SM1ACT  +
ECT_REG_SM1CONTR  +
ECT_REG_DCTIME0  +
ECT_REG_DCTIME1  +
ECT_REG_DCTIME2  +
ECT_REG_DCTIME3  +
ECT_REG_DCSYSTIME  +
ECT_REG_DCSOF  +
ECT_REG_DCSYSOFFSET  +
ECT_REG_DCSYSDELAY  +
ECT_REG_DCSYSDIFF  +
ECT_REG_DCSPEEDCNT  +
ECT_REG_DCTIMEFILT  +
ECT_REG_DCCUC  +
ECT_REG_DCSYNCACT  +
ECT_REG_DCSTART0  +
ECT_REG_DCCYCLE0  +
ECT_REG_DCCYCLE1  +
+ +
+
+ +
+
+ + + + +
enum ec_bufstate
+
+

Possible buffer states

+ + + + + + +
Enumerator
EC_BUF_EMPTY  +

Empty

+
EC_BUF_ALLOC  +

Allocated, but not filled

+
EC_BUF_TX  +

Transmitted

+
EC_BUF_RCVD  +

Received, but not consumed

+
EC_BUF_COMPLETE  +

Cycle completed

+
+ +
+
+ +
+
+ + + + +
enum ec_cmdtype
+
+

Ethercat command types

+ + + + + + + + + + + + + + + + +
Enumerator
EC_CMD_NOP  +

No operation

+
EC_CMD_APRD  +

Auto Increment Read

+
EC_CMD_APWR  +

Auto Increment Write

+
EC_CMD_APRW  +

Auto Increment Read Write

+
EC_CMD_FPRD  +

Configured Address Read

+
EC_CMD_FPWR  +

Configured Address Write

+
EC_CMD_FPRW  +

Configured Address Read Write

+
EC_CMD_BRD  +

Broadcast Read

+
EC_CMD_BWR  +

Broaddcast Write

+
EC_CMD_BRW  +

Broadcast Read Write

+
EC_CMD_LRD  +

Logical Memory Read

+
EC_CMD_LWR  +

Logical Memory Write

+
EC_CMD_LRW  +

Logical Memory Read Write

+
EC_CMD_ARMW  +

Auto Increment Read Mulitple Write

+
EC_CMD_FRMW  +

Configured Read Mulitple Write Reserved

+
+ +
+
+ +
+
+ + + + +
enum ec_datatype
+
+

Ethercat data types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
ECT_BOOLEAN  +
ECT_INTEGER8  +
ECT_INTEGER16  +
ECT_INTEGER32  +
ECT_UNSIGNED8  +
ECT_UNSIGNED16  +
ECT_UNSIGNED32  +
ECT_REAL32  +
ECT_VISIBLE_STRING  +
ECT_OCTET_STRING  +
ECT_UNICODE_STRING  +
ECT_TIME_OF_DAY  +
ECT_TIME_DIFFERENCE  +
ECT_DOMAIN  +
ECT_INTEGER24  +
ECT_REAL64  +
ECT_INTEGER64  +
ECT_UNSIGNED24  +
ECT_UNSIGNED64  +
ECT_BIT1  +
ECT_BIT2  +
ECT_BIT3  +
ECT_BIT4  +
ECT_BIT5  +
ECT_BIT6  +
ECT_BIT7  +
ECT_BIT8  +
+ +
+
+ +
+
+ + + + +
enum ec_ecmdtype
+
+

Ethercat EEprom command types

+ + + + + +
Enumerator
EC_ECMD_NOP  +

No operation

+
EC_ECMD_READ  +

Read

+
EC_ECMD_WRITE  +

Write

+
EC_ECMD_RELOAD  +

Reload

+
+ +
+
+ +
+
+ + + + +
enum ec_err
+
+

Possible error codes returned.

+ + + + + + + +
Enumerator
EC_ERR_OK  +

No error

+
EC_ERR_ALREADY_INITIALIZED  +

Library already initialized.

+
EC_ERR_NOT_INITIALIZED  +

Library not initialized.

+
EC_ERR_TIMEOUT  +

Timeout occured during execution of the function.

+
EC_ERR_NO_SLAVES  +

No slaves were found.

+
EC_ERR_NOK  +

Function failed.

+
+ +
+
+ +
+
+ + + + +
enum ec_err_type
+
+

Error types

+ + + + + + + + + + +
Enumerator
EC_ERR_TYPE_SDO_ERROR  +
EC_ERR_TYPE_EMERGENCY  +
EC_ERR_TYPE_PACKET_ERROR  +
EC_ERR_TYPE_SDOINFO_ERROR  +
EC_ERR_TYPE_FOE_ERROR  +
EC_ERR_TYPE_FOE_BUF2SMALL  +
EC_ERR_TYPE_FOE_PACKETNUMBER  +
EC_ERR_TYPE_SOE_ERROR  +
EC_ERR_TYPE_MBX_ERROR  +
+ +
+
+ +
+
+ + + + +
enum ec_state
+
+

Possible EtherCAT slave states

+ + + + + + + + +
Enumerator
EC_STATE_INIT  +

Init state

+
EC_STATE_PRE_OP  +

Pre-operational.

+
EC_STATE_BOOT  +

Boot state

+
EC_STATE_SAFE_OP  +

Safe-operational.

+
EC_STATE_OPERATIONAL  +

Operational

+
EC_STATE_ACK  +

Error or ACK error

+
EC_STATE_ERROR  +
+ +
+
+
+ + + + diff --git a/doc/html/files.html b/doc/html/files.html new file mode 100644 index 0000000..4c5b38b --- /dev/null +++ b/doc/html/files.html @@ -0,0 +1,84 @@ + + + + + + +SOEM: File List + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+
+
File List
+
+
+
Here is a list of all files with brief descriptions:
+ + + + + + + + + + + + + + + + + + + + + + + + +
o*ebox.cExample code for Simple Open EtherCAT master
o*eepromtool.cEEprom tool for Simple Open EtherCAT master
o*ethercatbase.cBase EtherCAT functions
o*ethercatbase.hHeaderfile for ethercatbase.c
o*ethercatcoe.cCAN over EtherCAT (CoE) module
o*ethercatcoe.hHeaderfile for ethercatcoe.c
o*ethercatconfig.cConfiguration module for EtherCAT master
o*ethercatconfig.hHeaderfile for ethercatconfig.c
o*ethercatconfiglist.hDEPRICATED Configuration list of known EtherCAT slave devices
o*ethercatdc.cDistributed Clock EtherCAT functions
o*ethercatdc.hHeaderfile for ethercatdc.c
o*ethercatfoe.cFile over EtherCAT (FoE) module
o*ethercatfoe.hHeaderfile for ethercatfoe.c
o*ethercatmain.cMain EtherCAT functions
o*ethercatmain.hHeaderfile for ethercatmain.c
o*ethercatprint.cModule to convert EtherCAT errors to readable messages
o*ethercatprint.hHeaderfile for ethercatprint.c
o*ethercatsoe.cServo over EtherCAT (SoE) Module
o*ethercatsoe.hHeaderfile for ethercatsoe.c
o*ethercattype.hGeneral typedefs and defines for EtherCAT
o*red_test.cExample code for Simple Open EtherCAT master
o*simple_test.cExample code for Simple Open EtherCAT master
\*slaveinfo.cExample code for Simple Open EtherCAT master
+
+
+ + + + diff --git a/doc/html/ftv2blank.png b/doc/html/ftv2blank.png new file mode 100644 index 0000000..63c605b Binary files /dev/null and b/doc/html/ftv2blank.png differ diff --git a/doc/html/ftv2cl.png b/doc/html/ftv2cl.png new file mode 100644 index 0000000..132f657 Binary files /dev/null and b/doc/html/ftv2cl.png differ diff --git a/doc/html/ftv2doc.png b/doc/html/ftv2doc.png new file mode 100644 index 0000000..17edabf Binary files /dev/null and b/doc/html/ftv2doc.png differ diff --git a/doc/html/ftv2folderclosed.png b/doc/html/ftv2folderclosed.png new file mode 100644 index 0000000..bb8ab35 Binary files /dev/null and b/doc/html/ftv2folderclosed.png differ diff --git a/doc/html/ftv2folderopen.png b/doc/html/ftv2folderopen.png new file mode 100644 index 0000000..d6c7f67 Binary files /dev/null and b/doc/html/ftv2folderopen.png differ diff --git a/doc/html/ftv2lastnode.png b/doc/html/ftv2lastnode.png new file mode 100644 index 0000000..63c605b Binary files /dev/null and b/doc/html/ftv2lastnode.png differ diff --git a/doc/html/ftv2link.png b/doc/html/ftv2link.png new file mode 100644 index 0000000..17edabf Binary files /dev/null and b/doc/html/ftv2link.png differ diff --git a/doc/html/ftv2mlastnode.png b/doc/html/ftv2mlastnode.png new file mode 100644 index 0000000..0b63f6d Binary files /dev/null and b/doc/html/ftv2mlastnode.png differ diff --git a/doc/html/ftv2mnode.png b/doc/html/ftv2mnode.png new file mode 100644 index 0000000..0b63f6d Binary files /dev/null and b/doc/html/ftv2mnode.png differ diff --git a/doc/html/ftv2mo.png b/doc/html/ftv2mo.png new file mode 100644 index 0000000..4bfb80f Binary files /dev/null and b/doc/html/ftv2mo.png differ diff --git a/doc/html/ftv2node.png b/doc/html/ftv2node.png new file mode 100644 index 0000000..63c605b Binary files /dev/null and b/doc/html/ftv2node.png differ diff --git a/doc/html/ftv2ns.png b/doc/html/ftv2ns.png new file mode 100644 index 0000000..72e3d71 Binary files /dev/null and b/doc/html/ftv2ns.png differ diff --git a/doc/html/ftv2plastnode.png b/doc/html/ftv2plastnode.png new file mode 100644 index 0000000..c6ee22f Binary files /dev/null and b/doc/html/ftv2plastnode.png differ diff --git a/doc/html/ftv2pnode.png b/doc/html/ftv2pnode.png new file mode 100644 index 0000000..c6ee22f Binary files /dev/null and b/doc/html/ftv2pnode.png differ diff --git a/doc/html/ftv2splitbar.png b/doc/html/ftv2splitbar.png new file mode 100644 index 0000000..fe895f2 Binary files /dev/null and b/doc/html/ftv2splitbar.png differ diff --git a/doc/html/ftv2vertline.png b/doc/html/ftv2vertline.png new file mode 100644 index 0000000..63c605b Binary files /dev/null and b/doc/html/ftv2vertline.png differ diff --git a/doc/html/functions.html b/doc/html/functions.html new file mode 100644 index 0000000..6a1f747 --- /dev/null +++ b/doc/html/functions.html @@ -0,0 +1,131 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- a -

+
+ + + + diff --git a/doc/html/functions_0x62.html b/doc/html/functions_0x62.html new file mode 100644 index 0000000..9345a72 --- /dev/null +++ b/doc/html/functions_0x62.html @@ -0,0 +1,112 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- b -

+
+ + + + diff --git a/doc/html/functions_0x63.html b/doc/html/functions_0x63.html new file mode 100644 index 0000000..8e2c27d --- /dev/null +++ b/doc/html/functions_0x63.html @@ -0,0 +1,132 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- c -

+
+ + + + diff --git a/doc/html/functions_0x64.html b/doc/html/functions_0x64.html new file mode 100644 index 0000000..25320f7 --- /dev/null +++ b/doc/html/functions_0x64.html @@ -0,0 +1,182 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- d -

+
+ + + + diff --git a/doc/html/functions_0x65.html b/doc/html/functions_0x65.html new file mode 100644 index 0000000..16b9510 --- /dev/null +++ b/doc/html/functions_0x65.html @@ -0,0 +1,183 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- e -

+
+ + + + diff --git a/doc/html/functions_0x66.html b/doc/html/functions_0x66.html new file mode 100644 index 0000000..305a71a --- /dev/null +++ b/doc/html/functions_0x66.html @@ -0,0 +1,144 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- f -

+
+ + + + diff --git a/doc/html/functions_0x67.html b/doc/html/functions_0x67.html new file mode 100644 index 0000000..83e801e --- /dev/null +++ b/doc/html/functions_0x67.html @@ -0,0 +1,93 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- g -

+
+ + + + diff --git a/doc/html/functions_0x68.html b/doc/html/functions_0x68.html new file mode 100644 index 0000000..be0a409 --- /dev/null +++ b/doc/html/functions_0x68.html @@ -0,0 +1,94 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- h -

+
+ + + + diff --git a/doc/html/functions_0x69.html b/doc/html/functions_0x69.html new file mode 100644 index 0000000..81bc148 --- /dev/null +++ b/doc/html/functions_0x69.html @@ -0,0 +1,153 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- i -

+
+ + + + diff --git a/doc/html/functions_0x6c.html b/doc/html/functions_0x6c.html new file mode 100644 index 0000000..44f4dff --- /dev/null +++ b/doc/html/functions_0x6c.html @@ -0,0 +1,122 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- l -

+
+ + + + diff --git a/doc/html/functions_0x6d.html b/doc/html/functions_0x6d.html new file mode 100644 index 0000000..5ae67bb --- /dev/null +++ b/doc/html/functions_0x6d.html @@ -0,0 +1,133 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- m -

+
+ + + + diff --git a/doc/html/functions_0x6e.html b/doc/html/functions_0x6e.html new file mode 100644 index 0000000..3df24cc --- /dev/null +++ b/doc/html/functions_0x6e.html @@ -0,0 +1,126 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- n -

+
+ + + + diff --git a/doc/html/functions_0x6f.html b/doc/html/functions_0x6f.html new file mode 100644 index 0000000..6b77561 --- /dev/null +++ b/doc/html/functions_0x6f.html @@ -0,0 +1,120 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- o -

+
+ + + + diff --git a/doc/html/functions_0x70.html b/doc/html/functions_0x70.html new file mode 100644 index 0000000..b7a067a --- /dev/null +++ b/doc/html/functions_0x70.html @@ -0,0 +1,147 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- p -

+
+ + + + diff --git a/doc/html/functions_0x72.html b/doc/html/functions_0x72.html new file mode 100644 index 0000000..f70b489 --- /dev/null +++ b/doc/html/functions_0x72.html @@ -0,0 +1,97 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- r -

+
+ + + + diff --git a/doc/html/functions_0x73.html b/doc/html/functions_0x73.html new file mode 100644 index 0000000..f501160 --- /dev/null +++ b/doc/html/functions_0x73.html @@ -0,0 +1,178 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- s -

+
+ + + + diff --git a/doc/html/functions_0x74.html b/doc/html/functions_0x74.html new file mode 100644 index 0000000..1118e5f --- /dev/null +++ b/doc/html/functions_0x74.html @@ -0,0 +1,102 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- t -

+
+ + + + diff --git a/doc/html/functions_0x75.html b/doc/html/functions_0x75.html new file mode 100644 index 0000000..01341c3 --- /dev/null +++ b/doc/html/functions_0x75.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- u -

+
+ + + + diff --git a/doc/html/functions_0x76.html b/doc/html/functions_0x76.html new file mode 100644 index 0000000..2cf599f --- /dev/null +++ b/doc/html/functions_0x76.html @@ -0,0 +1,90 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- v -

+
+ + + + diff --git a/doc/html/functions_0x77.html b/doc/html/functions_0x77.html new file mode 100644 index 0000000..162b43d --- /dev/null +++ b/doc/html/functions_0x77.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: Data Fields + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all struct and union fields with links to the structures/unions they belong to:
+ +

- w -

+
+ + + + diff --git a/doc/html/functions_vars.html b/doc/html/functions_vars.html new file mode 100644 index 0000000..459144a --- /dev/null +++ b/doc/html/functions_vars.html @@ -0,0 +1,131 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- a -

+
+ + + + diff --git a/doc/html/functions_vars_0x62.html b/doc/html/functions_vars_0x62.html new file mode 100644 index 0000000..c838fab --- /dev/null +++ b/doc/html/functions_vars_0x62.html @@ -0,0 +1,112 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- b -

+
+ + + + diff --git a/doc/html/functions_vars_0x63.html b/doc/html/functions_vars_0x63.html new file mode 100644 index 0000000..f59315f --- /dev/null +++ b/doc/html/functions_vars_0x63.html @@ -0,0 +1,132 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- c -

+
+ + + + diff --git a/doc/html/functions_vars_0x64.html b/doc/html/functions_vars_0x64.html new file mode 100644 index 0000000..f6255e4 --- /dev/null +++ b/doc/html/functions_vars_0x64.html @@ -0,0 +1,182 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- d -

+
+ + + + diff --git a/doc/html/functions_vars_0x65.html b/doc/html/functions_vars_0x65.html new file mode 100644 index 0000000..e4ef9a9 --- /dev/null +++ b/doc/html/functions_vars_0x65.html @@ -0,0 +1,183 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- e -

+
+ + + + diff --git a/doc/html/functions_vars_0x66.html b/doc/html/functions_vars_0x66.html new file mode 100644 index 0000000..240c32e --- /dev/null +++ b/doc/html/functions_vars_0x66.html @@ -0,0 +1,144 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- f -

+
+ + + + diff --git a/doc/html/functions_vars_0x67.html b/doc/html/functions_vars_0x67.html new file mode 100644 index 0000000..9f23e34 --- /dev/null +++ b/doc/html/functions_vars_0x67.html @@ -0,0 +1,93 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- g -

+
+ + + + diff --git a/doc/html/functions_vars_0x68.html b/doc/html/functions_vars_0x68.html new file mode 100644 index 0000000..63164a0 --- /dev/null +++ b/doc/html/functions_vars_0x68.html @@ -0,0 +1,94 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- h -

+
+ + + + diff --git a/doc/html/functions_vars_0x69.html b/doc/html/functions_vars_0x69.html new file mode 100644 index 0000000..1afc97d --- /dev/null +++ b/doc/html/functions_vars_0x69.html @@ -0,0 +1,153 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- i -

+
+ + + + diff --git a/doc/html/functions_vars_0x6c.html b/doc/html/functions_vars_0x6c.html new file mode 100644 index 0000000..04e8150 --- /dev/null +++ b/doc/html/functions_vars_0x6c.html @@ -0,0 +1,122 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- l -

+
+ + + + diff --git a/doc/html/functions_vars_0x6d.html b/doc/html/functions_vars_0x6d.html new file mode 100644 index 0000000..1160592 --- /dev/null +++ b/doc/html/functions_vars_0x6d.html @@ -0,0 +1,133 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- m -

+
+ + + + diff --git a/doc/html/functions_vars_0x6e.html b/doc/html/functions_vars_0x6e.html new file mode 100644 index 0000000..2c54c1e --- /dev/null +++ b/doc/html/functions_vars_0x6e.html @@ -0,0 +1,126 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- n -

+
+ + + + diff --git a/doc/html/functions_vars_0x6f.html b/doc/html/functions_vars_0x6f.html new file mode 100644 index 0000000..366f7b8 --- /dev/null +++ b/doc/html/functions_vars_0x6f.html @@ -0,0 +1,120 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- o -

+
+ + + + diff --git a/doc/html/functions_vars_0x70.html b/doc/html/functions_vars_0x70.html new file mode 100644 index 0000000..ba83386 --- /dev/null +++ b/doc/html/functions_vars_0x70.html @@ -0,0 +1,147 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- p -

+
+ + + + diff --git a/doc/html/functions_vars_0x72.html b/doc/html/functions_vars_0x72.html new file mode 100644 index 0000000..c9ca08e --- /dev/null +++ b/doc/html/functions_vars_0x72.html @@ -0,0 +1,97 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- r -

+
+ + + + diff --git a/doc/html/functions_vars_0x73.html b/doc/html/functions_vars_0x73.html new file mode 100644 index 0000000..16fdf14 --- /dev/null +++ b/doc/html/functions_vars_0x73.html @@ -0,0 +1,178 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- s -

+
+ + + + diff --git a/doc/html/functions_vars_0x74.html b/doc/html/functions_vars_0x74.html new file mode 100644 index 0000000..d6284cb --- /dev/null +++ b/doc/html/functions_vars_0x74.html @@ -0,0 +1,102 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- t -

+
+ + + + diff --git a/doc/html/functions_vars_0x75.html b/doc/html/functions_vars_0x75.html new file mode 100644 index 0000000..3a632ac --- /dev/null +++ b/doc/html/functions_vars_0x75.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- u -

+
+ + + + diff --git a/doc/html/functions_vars_0x76.html b/doc/html/functions_vars_0x76.html new file mode 100644 index 0000000..34f7c9b --- /dev/null +++ b/doc/html/functions_vars_0x76.html @@ -0,0 +1,90 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- v -

+
+ + + + diff --git a/doc/html/functions_vars_0x77.html b/doc/html/functions_vars_0x77.html new file mode 100644 index 0000000..cf9771e --- /dev/null +++ b/doc/html/functions_vars_0x77.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: Data Fields - Variables + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- w -

+
+ + + + diff --git a/doc/html/globals.html b/doc/html/globals.html new file mode 100644 index 0000000..8312548 --- /dev/null +++ b/doc/html/globals.html @@ -0,0 +1,102 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- a -

+
+ + + + diff --git a/doc/html/globals_0x62.html b/doc/html/globals_0x62.html new file mode 100644 index 0000000..8e7c550 --- /dev/null +++ b/doc/html/globals_0x62.html @@ -0,0 +1,93 @@ + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.2.8 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- b -

+
+ + + + diff --git a/doc/html/globals_0x63.html b/doc/html/globals_0x63.html new file mode 100644 index 0000000..2d9c842 --- /dev/null +++ b/doc/html/globals_0x63.html @@ -0,0 +1,106 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- c -

+
+ + + + diff --git a/doc/html/globals_0x64.html b/doc/html/globals_0x64.html new file mode 100644 index 0000000..f71b5d0 --- /dev/null +++ b/doc/html/globals_0x64.html @@ -0,0 +1,107 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- d -

+
+ + + + diff --git a/doc/html/globals_0x65.html b/doc/html/globals_0x65.html new file mode 100644 index 0000000..c23319a --- /dev/null +++ b/doc/html/globals_0x65.html @@ -0,0 +1,1691 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- e -

+
+ + + + diff --git a/doc/html/globals_0x66.html b/doc/html/globals_0x66.html new file mode 100644 index 0000000..eeff009 --- /dev/null +++ b/doc/html/globals_0x66.html @@ -0,0 +1,99 @@ + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.2.8 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- f -

+
+ + + + diff --git a/doc/html/globals_0x67.html b/doc/html/globals_0x67.html new file mode 100644 index 0000000..ee19493 --- /dev/null +++ b/doc/html/globals_0x67.html @@ -0,0 +1,95 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- g -

+
+ + + + diff --git a/doc/html/globals_0x68.html b/doc/html/globals_0x68.html new file mode 100644 index 0000000..9632565 --- /dev/null +++ b/doc/html/globals_0x68.html @@ -0,0 +1,107 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- h -

+
+ + + + diff --git a/doc/html/globals_0x69.html b/doc/html/globals_0x69.html new file mode 100644 index 0000000..e74dd05 --- /dev/null +++ b/doc/html/globals_0x69.html @@ -0,0 +1,114 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- i -

+
+ + + + diff --git a/doc/html/globals_0x6c.html b/doc/html/globals_0x6c.html new file mode 100644 index 0000000..eafdca1 --- /dev/null +++ b/doc/html/globals_0x6c.html @@ -0,0 +1,95 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- l -

+
+ + + + diff --git a/doc/html/globals_0x6d.html b/doc/html/globals_0x6d.html new file mode 100644 index 0000000..5f28092 --- /dev/null +++ b/doc/html/globals_0x6d.html @@ -0,0 +1,139 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- m -

+
+ + + + diff --git a/doc/html/globals_0x6e.html b/doc/html/globals_0x6e.html new file mode 100644 index 0000000..2c23740 --- /dev/null +++ b/doc/html/globals_0x6e.html @@ -0,0 +1,97 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- n -

+
+ + + + diff --git a/doc/html/globals_0x6f.html b/doc/html/globals_0x6f.html new file mode 100644 index 0000000..6a64183 --- /dev/null +++ b/doc/html/globals_0x6f.html @@ -0,0 +1,127 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- o -

+
+ + + + diff --git a/doc/html/globals_0x70.html b/doc/html/globals_0x70.html new file mode 100644 index 0000000..6b89bf3 --- /dev/null +++ b/doc/html/globals_0x70.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- p -

+
+ + + + diff --git a/doc/html/globals_0x72.html b/doc/html/globals_0x72.html new file mode 100644 index 0000000..8a60e7a --- /dev/null +++ b/doc/html/globals_0x72.html @@ -0,0 +1,92 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- r -

+
+ + + + diff --git a/doc/html/globals_0x73.html b/doc/html/globals_0x73.html new file mode 100644 index 0000000..1f82b0b --- /dev/null +++ b/doc/html/globals_0x73.html @@ -0,0 +1,147 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- s -

+
+ + + + diff --git a/doc/html/globals_0x74.html b/doc/html/globals_0x74.html new file mode 100644 index 0000000..18d6c7f --- /dev/null +++ b/doc/html/globals_0x74.html @@ -0,0 +1,112 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- t -

+
+ + + + diff --git a/doc/html/globals_0x75.html b/doc/html/globals_0x75.html new file mode 100644 index 0000000..64f2b5e --- /dev/null +++ b/doc/html/globals_0x75.html @@ -0,0 +1,92 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- u -

+
+ + + + diff --git a/doc/html/globals_0x77.html b/doc/html/globals_0x77.html new file mode 100644 index 0000000..18f5c3d --- /dev/null +++ b/doc/html/globals_0x77.html @@ -0,0 +1,94 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+
Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
+ +

- w -

+
+ + + + diff --git a/doc/html/globals_defs.html b/doc/html/globals_defs.html new file mode 100644 index 0000000..99057ca --- /dev/null +++ b/doc/html/globals_defs.html @@ -0,0 +1,519 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- c -

+ + +

- e -

+ + +

- g -

+ + +

- h -

+ + +

- i -

+ + +

- l -

+ + +

- m -

+ + +

- n -

+ + +

- p -

+ + +

- s -

+
+ + + + diff --git a/doc/html/globals_enum.html b/doc/html/globals_enum.html new file mode 100644 index 0000000..aa484aa --- /dev/null +++ b/doc/html/globals_enum.html @@ -0,0 +1,87 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+
+ + + + diff --git a/doc/html/globals_eval.html b/doc/html/globals_eval.html new file mode 100644 index 0000000..45516a5 --- /dev/null +++ b/doc/html/globals_eval.html @@ -0,0 +1,601 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- e -

+
+ + + + diff --git a/doc/html/globals_func.html b/doc/html/globals_func.html new file mode 100644 index 0000000..947a79f --- /dev/null +++ b/doc/html/globals_func.html @@ -0,0 +1,85 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- a -

+
+ + + + diff --git a/doc/html/globals_func_0x63.html b/doc/html/globals_func_0x63.html new file mode 100644 index 0000000..5ce7894 --- /dev/null +++ b/doc/html/globals_func_0x63.html @@ -0,0 +1,84 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- c -

+
+ + + + diff --git a/doc/html/globals_func_0x64.html b/doc/html/globals_func_0x64.html new file mode 100644 index 0000000..600b61d --- /dev/null +++ b/doc/html/globals_func_0x64.html @@ -0,0 +1,84 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- d -

+
+ + + + diff --git a/doc/html/globals_func_0x65.html b/doc/html/globals_func_0x65.html new file mode 100644 index 0000000..cee3a50 --- /dev/null +++ b/doc/html/globals_func_0x65.html @@ -0,0 +1,751 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- e -

+
+ + + + diff --git a/doc/html/globals_func_0x69.html b/doc/html/globals_func_0x69.html new file mode 100644 index 0000000..d3a562a --- /dev/null +++ b/doc/html/globals_func_0x69.html @@ -0,0 +1,87 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- i -

+
+ + + + diff --git a/doc/html/globals_func_0x6d.html b/doc/html/globals_func_0x6d.html new file mode 100644 index 0000000..d6832a0 --- /dev/null +++ b/doc/html/globals_func_0x6d.html @@ -0,0 +1,88 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- m -

+
+ + + + diff --git a/doc/html/globals_func_0x6f.html b/doc/html/globals_func_0x6f.html new file mode 100644 index 0000000..3308606 --- /dev/null +++ b/doc/html/globals_func_0x6f.html @@ -0,0 +1,90 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- o -

+
+ + + + diff --git a/doc/html/globals_func_0x72.html b/doc/html/globals_func_0x72.html new file mode 100644 index 0000000..cbe964e --- /dev/null +++ b/doc/html/globals_func_0x72.html @@ -0,0 +1,84 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- r -

+
+ + + + diff --git a/doc/html/globals_func_0x73.html b/doc/html/globals_func_0x73.html new file mode 100644 index 0000000..0ae6529 --- /dev/null +++ b/doc/html/globals_func_0x73.html @@ -0,0 +1,108 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- s -

+
+ + + + diff --git a/doc/html/globals_type.html b/doc/html/globals_type.html new file mode 100644 index 0000000..57b0c88 --- /dev/null +++ b/doc/html/globals_type.html @@ -0,0 +1,72 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+
+ + + + diff --git a/doc/html/globals_vars.html b/doc/html/globals_vars.html new file mode 100644 index 0000000..f560d4f --- /dev/null +++ b/doc/html/globals_vars.html @@ -0,0 +1,372 @@ + + + + + + +SOEM: Globals + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + + +
+
+  + +

- a -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- g -

+ + +

- h -

+ + +

- i -

+ + +

- m -

+ + +

- n -

+ + +

- o -

+ + +

- p -

+ + +

- s -

+ + +

- t -

+ + +

- u -

+ + +

- w -

+
+ + + + diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..f3172d1 --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,255 @@ + + + + + + +SOEM: Simple Open EtherCAT Master or SOEM + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + +
+
+
+
Simple Open EtherCAT Master or SOEM
+
+
+

+Getting started

+

For a tutorial on SOEM See tutorial.txt

+

+Overview

+

SOEM is an EtherCAT master library written in c. Its purpose is to learn and to use. All users are invited to study the source to get an understanding how an EtherCAT master functions and how it interacts with EtherCAT slaves.

+

As all applications are different SOEM tries to not impose any design architecture. Under Linux it can be used in generic user mode, PREEMPT_RT or Xenomai. under Windows it can be used as user mode program.

+

Preconditions Linux:

+
    +
  • Linux 2.6 kernel.
  • +
  • GCC compiler (others might work, just not tested).
  • +
  • One (or two if in redundant mode) 100Mb/s NIC that can connect to a RAW socket.
  • +
  • Application must run as root / kernel.
  • +
+

Preconditions Windows:

+
    +
  • Windows2000 - Windows 7 (8 not tested, might work).
  • +
  • VC compiler (others might work, just not tested).
  • +
  • One (or two if in redundant mode) 100Mb/s NIC that can connect to a RAW socket.
  • +
  • WinPcap installed.
  • +
+

Features as of 1.1.2 :

+
    +
  • Connects to a standard RAW socket.
  • +
  • Full redundancy support.
  • +
  • Recovery of "out-of-order" frames.
  • +
  • Low level functions, BRD, BWR, APRMW, FPRD, LRW....
  • +
  • Blocking or non blocking transfers.
  • +
  • Automatic configuration of slaves.
  • +
  • Use of internal configuration table (quick).
  • +
  • Use of slave internal data in EEprom and/or CoE.
  • +
  • Setting and reading of slave state.
  • +
  • Automatic generation of processdata mapping.
  • +
  • Mailbox link layer support with resend toggle.
  • +
  • CoE, SDO read / write.
  • +
  • CoE, Complete Access support.
  • +
  • CoE, Segmented transfer support.
  • +
  • CoE, Object Description list
  • +
  • CoE, Emergency and abort SDO support.
  • +
  • Distributed Clock (DC) support.
  • +
  • Automatic configuration of DC slaves.
  • +
  • Automatic sync of clocks with process data exchange.
  • +
  • Flexible settting of sync0 and sync1 firing per slave.
  • +
  • Access to slave functions through one slave structure.
  • +
  • EEPROM read / write.
  • +
  • Local cache for EEPROM access with automatic 4/8 byte reading.
  • +
  • SII parsing.
  • +
  • Portable code, only standard c, usable for embedded applications.
  • +
  • All buffers are static so can be memory locked.
  • +
  • Support for Little and Big endian targets.
  • +
+

Features as of 1.1.3 :

+
    +
  • CoE, TxPDO and RxPDO, master is client (beta).
  • +
  • FoE, Read and Write file (beta).
  • +
+

Features as of 1.1.4 :

+
    +
  • FMMU allocation is floating instead of fixed. If needed more than 2 FMMUs are used.
  • +
  • SYNC1 generation supported.
  • +
+

Features as of 1.2.0 :

+
    +
  • Changed license to GPLv2 only. Adresses leagal concerns about master licensing.
  • +
  • Slave init and process data mapping is split in two functions. This allows dynamic user reconfiguration of PDO mapping.
  • +
  • Eeprom transfer to and from PDI
  • +
  • Eeprom is released to PDI when going to SAFEOP.
  • +
+

Features as of 1.2.2 :

+
    +
  • Redesign of topology and delay measurement. 4 port slaves are fully supported now.
  • +
  • Delay measurement of slaves that are reverse connected work too.
  • +
  • New ethercatprint unit to display errors in readable text.
  • +
+

Features as of 1.2.4 :

+
    +
  • SoE, servo over EtherCAT support.
  • +
  • SoE read request and write request.
  • +
  • SoE segmented transfers.
  • +
  • SoE error response.
  • +
  • Added SoE errors to print module.
  • +
  • Auto config of SoE process data.
  • +
+

Features as of 1.2.5 :

+
    +
  • Added eepromtool, it can read and write the ESC eeprom of a designated slave.
  • +
  • Rewrite of eeprom read/write functions.
  • +
  • Added infrastructure change to allow slave groups.
  • +
  • Added recovery and reconfiguration of slaves after connection loss.
  • +
  • Improved CoE PDO assignment read from slaves, no longer assume assign indexes as functionally fixed.
  • +
+

Features as of 1.2.8 :

+
    +
  • Changed directory structure.
  • +
  • Changed make file.
  • +
  • Moved hardware / OS dependend part in separate directories.
  • +
  • Added firm_update tool to upload firmware to slaves in Boot state, use with care.
  • +
  • Added DC for LRD/LWR case.
  • +
  • Separated expectedWKC to inputsWKC and outputsWKC.
  • +
  • Added PreOP->SafeOP hooks in configuration functions.
  • +
  • With CoE use expedited download if mailbox size is very small and object <= 4 bytes.
  • +
  • Added mailbox error handling.
  • +
  • Rewrite of ec_recover_slave() and ec_reconfigure_slave()
  • +
  • Added -map option in slaveinfo, shows SOEM IO mapping of all slaves found.
  • +
+

Features as of 1.3.0 :

+
    +
  • Added win32 target.
  • +
  • Added rtk target.
  • +
  • Compiles under gcc / visual-c / borland-c.
  • +
  • Multiple port support. One master can run concurrent stacks on multiple network ports.
  • +
  • All global vars are encapsulated in context struct.
  • +
  • All timing abstracted in osal.c.
  • +
  • Linux timing converted to get_clock(CLOCK_MONOTONIC).
  • +
  • Error messages updated to latest ETG1020 document.
  • +
  • FoE transfers now support busy response.
  • +
+

+Getting started

+

For Linux

+
    +
  • go to project directory
  • +
  • source ./setup.sh linux
  • +
  • make all
  • +
+

For examples see simple_test.c in ~/test/linux/simple_test. First try (assume EtherCAT on eth0): sudo ./simple_test eth0 As SOEM uses RAW sockets it will need to run as root.

+

For Windows

+
    +
  • have winpcap installed (included with WireShark)
  • +
  • go to project directory
  • +
  • for VC, run vcvarsall.bat f.e. : C: Files (x86) Visual Studio 10.0.bat x86
  • +
  • run make_test_win32_all.bat
  • +
+

+Squashed bugs

+

Version 1.1.3

+ +

Version 1.1.4

+
    +
  • Changed FMMU algorithm of allocation during configuration. EL4732 supported now.
  • +
  • Changed the ec_slave structure around SM en FMMU storage.
  • +
  • Fixed bug in FoE write in ethercatfoe.c
  • +
+

Version 1.2.0

+
    +
  • Fixed bug in type definition of int32 and uint32 for 64bit OS.
  • +
  • Fixed bug in maximum dataframe size calculation.
  • +
+

Version 1.2.2

+
    +
  • Fixed bugs in ec_adddatagram.
  • +
  • Fixed several bugs in CoE object dictionary read functions.
  • +
  • Fixed bug in PDO mapping read function.
  • +
  • Changed ec_slave structure around topology and delay variables.
  • +
  • Added several constants in ethercattype.c
  • +
+

Version 1.2.3

+
    +
  • Clear SM enable if size is 0, even if enable is set in SII.
  • +
  • Fixed bug in DC propagation delay calculation. Branches with only non DC slaves now correctly close root port.
  • +
  • Fixed bug in ec_receive_processdata(), wkc now checks for EC_NOFRAME instead of 0.
  • +
  • Fixed bug in makefile.
  • +
+

Version 1.2.5

+
    +
  • Fixed bugs in ec_config_map().
  • +
  • Added EC_STATE_BOOT constant.
  • +
  • Fixed mailbox size bug, In and Out mailbox can now be of different size.
  • +
  • Fixed SM type bug.
  • +
  • Fixed FoE bugs.
  • +
  • Fixed siigetbyte() unaligned copy.
  • +
  • Fixed bug in nicdrv.c, socket handles are 0 included.
  • +
  • Fixed bug in ethercatconfig.c causing memory corruption.
  • +
+

Version 1.2.8

+
    +
  • Fixed NetX mailbox configuration behaviour.
  • +
  • Fixed FoE write bug.
  • +
  • Fixed SII string read bug.
  • +
  • Fixed bug in table lookup for printing
  • +
+

Version 1.3.0

+
    +
  • Fixed NetX100 configuration behaviour.
  • +
  • Fixed linux gettimeofday() to get_clock().
  • +
  • Fixed eeprom cache flush on reinit.
  • +
  • Fixed make for new gcc linker version.
  • +
+

+Legal notice

+

Copyright© 2005-2013 Speciaal Machinefabriek Ketels v.o.f.
+ Copyright© 2005-2013 Arthur Ketels
+ Copyright© 2008-2010 TU/e Technische Universiteit Eindhoven
+ Copyright© 2012-2013 RT-labs AB
+

+

SOEM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

+

SOEM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

+

As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License.

+

This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License.

+

The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual property of, and protected by Beckhoff Automation GmbH. You can use SOEM for the sole purpose of creating, using and/or selling or otherwise distributing an EtherCAT network master provided that an EtherCAT Master License is obtained from Beckhoff Automation GmbH.

+

In case you did not receive a copy of the EtherCAT Master License along with SOEM write to Beckhoff Automation GmbH, Eiserstrasse 5, D-33415 Verl, Germany (www.beckhoff.com).

+
+ + + + diff --git a/doc/html/jquery.js b/doc/html/jquery.js new file mode 100644 index 0000000..63939e7 --- /dev/null +++ b/doc/html/jquery.js @@ -0,0 +1,8 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")), +f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c) +{if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); diff --git a/doc/html/memory_layout.png b/doc/html/memory_layout.png new file mode 100644 index 0000000..ef444ba Binary files /dev/null and b/doc/html/memory_layout.png differ diff --git a/doc/html/nav_f.png b/doc/html/nav_f.png new file mode 100644 index 0000000..72a58a5 Binary files /dev/null and b/doc/html/nav_f.png differ diff --git a/doc/html/nav_g.png b/doc/html/nav_g.png new file mode 100644 index 0000000..2093a23 Binary files /dev/null and b/doc/html/nav_g.png differ diff --git a/doc/html/nav_h.png b/doc/html/nav_h.png new file mode 100644 index 0000000..33389b1 Binary files /dev/null and b/doc/html/nav_h.png differ diff --git a/doc/html/open.png b/doc/html/open.png new file mode 100644 index 0000000..30f75c7 Binary files /dev/null and b/doc/html/open.png differ diff --git a/doc/html/red__test_8c.html b/doc/html/red__test_8c.html new file mode 100644 index 0000000..63caa65 --- /dev/null +++ b/doc/html/red__test_8c.html @@ -0,0 +1,593 @@ + + + + + + +SOEM: red_test.c File Reference + + + + + + +
+
+
+ + + + + +
+
SOEM +  v1.3.0 +
+
+ + + + + + + +
+ +
+
red_test.c File Reference
+
+
+ +

Example code for Simple Open EtherCAT master. +More...

+
#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sched.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <math.h>
+#include "ethercattype.h"
+#include "nicdrv.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatcoe.h"
+#include "ethercatconfig.h"
+#include "ethercatdc.h"
+#include "ethercatprint.h"
+
+ + + + + +

+Macros

#define NSEC_PER_SEC   1000000000
 
#define EC_TIMEOUTMON   500
 
+ + + + + + + + + + + + + +

+Functions

void redtest (char *ifname, char *ifname2)
 
void add_timespec (struct timespec *ts, int64 addtime)
 
void ec_sync (int64 reftime, int64 cycletime, int64 *offsettime)
 
void ecatthread (void *ptr)
 
void ecatcheck (void *ptr)
 
int main (int argc, char *argv[])
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Variables

struct sched_param schedp
 
char IOmap [4096]
 
pthread_t thread1
 
pthread_t thread2
 
struct timeval tv t1 t2
 
int dorun = 0
 
int deltat
 
int tmax = 0
 
int64 toff
 
int64 gl_delta
 
int DCdiff
 
int os
 
uint8 ob
 
uint16 ob2
 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER
 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
 
uint8 * digout = 0
 
int expectedWKC
 
boolean needlf
 
volatile int wkc
 
boolean inOP
 
uint8 currentgroup = 0
 
+

Detailed Description

+

Example code for Simple Open EtherCAT master.

+

Usage : red_test [ifname1] [ifname2] [cycletime] ifname is NIC interface, f.e. eth0 cycletime in us, f.e. 500

+

This is a redundancy test.

+

(c)Arthur Ketels 2008

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_TIMEOUTMON   500
+
+ +
+
+ +
+
+ + + + +
#define NSEC_PER_SEC   1000000000
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void add_timespec (struct timespec * ts,
int64 addtime 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void ec_sync (int64 reftime,
int64 cycletime,
int64 * offsettime 
)
+
+ +
+
+ +
+
+ + + + + + + + +
void ecatcheck (void * ptr)
+
+ +
+
+ +
+
+ + + + + + + + +
void ecatthread (void * ptr)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void redtest (char * ifname,
char * ifname2 
)
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
pthread_cond_t cond = PTHREAD_COND_INITIALIZER
+
+ +
+
+ +
+
+ + + + +
uint8 currentgroup = 0
+
+ +
+
+ +
+
+ + + + +
int DCdiff
+
+ +
+
+ +
+
+ + + + +
int deltat
+
+ +
+
+ +
+
+ + + + +
uint8* digout = 0
+
+ +
+
+ +
+
+ + + + +
int dorun = 0
+
+ +
+
+ +
+
+ + + + +
int expectedWKC
+
+ +
+
+ +
+
+ + + + +
int64 gl_delta
+
+ +
+
+ +
+
+ + + + +
boolean inOP
+
+ +
+
+ +
+
+ + + + +
char IOmap[4096]
+
+ +
+
+ +
+
+ + + + +
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
+
+ +
+
+ +
+
+ + + + +
boolean needlf
+
+ +
+
+ +
+
+ + + + +
uint8 ob
+
+ +
+
+ +
+
+ + + + +
uint16 ob2
+
+ +
+
+ +
+
+ + + + +
int os
+
+ +
+
+ +
+
+ + + + +
struct sched_param schedp
+
+ +
+
+ +
+
+ + + + +
struct timeval tv t1 t2
+
+ +
+
+ +
+
+ + + + +
pthread_t thread1
+
+ +
+
+ +
+
+ + + + +
pthread_t thread2
+
+ +
+
+ +
+
+ + + + +
int tmax = 0
+
+ +
+
+ +
+
+ + + + +
int64 toff
+
+ +
+
+ +
+
+ + + + +
volatile int wkc
+
+ +
+
+
+ + + + diff --git a/doc/html/simple__test_8c.html b/doc/html/simple__test_8c.html new file mode 100644 index 0000000..b0d3a70 --- /dev/null +++ b/doc/html/simple__test_8c.html @@ -0,0 +1,276 @@ + + + + + + +SOEM: simple_test.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
simple_test.c File Reference
+
+
+ +

Example code for Simple Open EtherCAT master. +More...

+
#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "ethercattype.h"
+#include "nicdrv.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatdc.h"
+#include "ethercatcoe.h"
+#include "ethercatfoe.h"
+#include "ethercatconfig.h"
+#include "ethercatprint.h"
+
+ + + +

+Macros

#define EC_TIMEOUTMON   500
 
+ + + + + + + +

+Functions

void simpletest (char *ifname)
 
void ecatcheck (void *ptr)
 
int main (int argc, char *argv[])
 
+ + + + + + + + + + + + + + + +

+Variables

char IOmap [4096]
 
pthread_t thread1
 
int expectedWKC
 
boolean needlf
 
volatile int wkc
 
boolean inOP
 
uint8 currentgroup = 0
 
+

Detailed Description

+

Example code for Simple Open EtherCAT master.

+

Usage : simple_test [ifname1] ifname is NIC interface, f.e. eth0

+

This is a minimal test.

+

(c)Arthur Ketels 2010 - 2011

+

Macro Definition Documentation

+ +
+
+ + + + +
#define EC_TIMEOUTMON   500
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void ecatcheck (void * ptr)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +
+
+ +
+
+ + + + + + + + +
void simpletest (char * ifname)
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
uint8 currentgroup = 0
+
+ +
+
+ +
+
+ + + + +
int expectedWKC
+
+ +
+
+ +
+
+ + + + +
boolean inOP
+
+ +
+
+ +
+
+ + + + +
char IOmap[4096]
+
+ +
+
+ +
+
+ + + + +
boolean needlf
+
+ +
+
+ +
+
+ + + + +
pthread_t thread1
+
+ +
+
+ +
+
+ + + + +
volatile int wkc
+
+ +
+
+
+ + + + diff --git a/doc/html/slaveinfo_8c.html b/doc/html/slaveinfo_8c.html new file mode 100644 index 0000000..4f75b10 --- /dev/null +++ b/doc/html/slaveinfo_8c.html @@ -0,0 +1,428 @@ + + + + + + +SOEM: slaveinfo.c File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + + +
+
+ +
+
slaveinfo.c File Reference
+
+
+ +

Example code for Simple Open EtherCAT master. +More...

+
#include <stdio.h>
+#include <string.h>
+#include "ethercattype.h"
+#include "nicdrv.h"
+#include "ethercatbase.h"
+#include "ethercatmain.h"
+#include "ethercatconfig.h"
+#include "ethercatcoe.h"
+#include "ethercatdc.h"
+#include "ethercatprint.h"
+
+ + + + + + + + + + + + + + + + + + + +

+Functions

char * dtype2string (uint16 dtype)
 
char * SDO2string (uint16 slave, uint16 index, uint8 subidx, uint16 dtype)
 
int si_PDOassign (uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
 
int si_map_sdo (int slave)
 
int si_siiPDO (uint16 slave, uint8 t, int mapoffset, int bitoffset)
 
int si_map_sii (int slave)
 
void si_sdo (int cnt)
 
void slaveinfo (char *ifname)
 
int main (int argc, char *argv[])
 
+ + + + + + + + + + + + + + + +

+Variables

char IOmap [4096]
 
ec_ODlistt ODlist
 
ec_OElistt OElist
 
boolean printSDO = FALSE
 
boolean printMAP = FALSE
 
char usdo [128]
 
char hstr [1024]
 
+

Detailed Description

+

Example code for Simple Open EtherCAT master.

+

Usage : slaveinfo [ifname] [-sdo] [-map] Ifname is NIC interface, f.e. eth0. Optional -sdo to display CoE object dictionary. Optional -map to display slave PDO mapping

+

This shows the configured slave data.

+

(c)Arthur Ketels 2010 - 2011

+

Function Documentation

+ +
+
+ + + + + + + + +
char* dtype2string (uint16 dtype)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
char* SDO2string (uint16 slave,
uint16 index,
uint8 subidx,
uint16 dtype 
)
+
+ +
+
+ +
+
+ + + + + + + + +
int si_map_sdo (int slave)
+
+ +
+
+ +
+
+ + + + + + + + +
int si_map_sii (int slave)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int si_PDOassign (uint16 slave,
uint16 PDOassign,
int mapoffset,
int bitoffset 
)
+
+

Read PDO assign structure

+ +
+
+ +
+
+ + + + + + + + +
void si_sdo (int cnt)
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int si_siiPDO (uint16 slave,
uint8 t,
int mapoffset,
int bitoffset 
)
+
+ +
+
+ +
+
+ + + + + + + + +
void slaveinfo (char * ifname)
+
+ +
+
+

Variable Documentation

+ +
+
+ + + + +
char hstr[1024]
+
+ +
+
+ +
+
+ + + + +
char IOmap[4096]
+
+ +
+
+ +
+
+ + + + +
ec_ODlistt ODlist
+
+ +
+
+ +
+
+ + + + +
ec_OElistt OElist
+
+ +
+
+ +
+
+ + + + +
boolean printMAP = FALSE
+
+ +
+
+ +
+
+ + + + +
boolean printSDO = FALSE
+
+ +
+
+ +
+
+ + + + +
char usdo[128]
+
+ +
+
+
+ + + + diff --git a/doc/html/soem_8dox.html b/doc/html/soem_8dox.html new file mode 100644 index 0000000..9945f05 --- /dev/null +++ b/doc/html/soem_8dox.html @@ -0,0 +1,57 @@ + + + + + + +SOEM: soem.dox File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+
+
soem.dox File Reference
+
+
+
+ + + + diff --git a/doc/html/structec__ALstatuscodelist__t.html b/doc/html/structec__ALstatuscodelist__t.html new file mode 100644 index 0000000..2a9ed8a --- /dev/null +++ b/doc/html/structec__ALstatuscodelist__t.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: ec_ALstatuscodelist_t Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_ALstatuscodelist_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint16 ALstatuscode
 
char ALstatuscodedescription [EC_MAXERRORNAME+1]
 
+

Detailed Description

+

AL status code list type definition

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_ALstatuscodelist_t::ALstatuscode
+
+

AL status code

+ +
+
+ +
+
+ + + + +
char ec_ALstatuscodelist_t::ALstatuscodedescription[EC_MAXERRORNAME+1]
+
+

Readable description

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__FOEt.html b/doc/html/structec__FOEt.html new file mode 100644 index 0000000..520c00d --- /dev/null +++ b/doc/html/structec__FOEt.html @@ -0,0 +1,225 @@ + + + + + + +SOEM: ec_FOEt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_FOEt Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint8 OpCode
 
uint8 Reserved
 
union {
   uint32   Password
 
   uint32   PacketNumber
 
   uint32   ErrorCode
 
}; 
 
union {
   char   FileName [EC_MAXFOEDATA]
 
   uint8   Data [EC_MAXFOEDATA]
 
   char   ErrorText [EC_MAXFOEDATA]
 
}; 
 
+

Detailed Description

+

FOE structure. Used for Read, Write, Data, Ack and Error mailbox packets.

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
uint8 ec_FOEt::Data[EC_MAXFOEDATA]
+
+ +
+
+ +
+
+ + + + +
uint32 ec_FOEt::ErrorCode
+
+ +
+
+ +
+
+ + + + +
char ec_FOEt::ErrorText[EC_MAXFOEDATA]
+
+ +
+
+ +
+
+ + + + +
char ec_FOEt::FileName[EC_MAXFOEDATA]
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_FOEt::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint8 ec_FOEt::OpCode
+
+ +
+
+ +
+
+ + + + +
uint32 ec_FOEt::PacketNumber
+
+ +
+
+ +
+
+ + + + +
uint32 ec_FOEt::Password
+
+ +
+
+ +
+
+ + + + +
uint8 ec_FOEt::Reserved
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__ODlistt.html b/doc/html/structec__ODlistt.html new file mode 100644 index 0000000..787175b --- /dev/null +++ b/doc/html/structec__ODlistt.html @@ -0,0 +1,174 @@ + + + + + + +SOEM: ec_ODlistt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_ODlistt Struct Reference
+
+
+ +

#include <ethercatcoe.h>

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

+Data Fields

uint16 Slave
 
uint16 Entries
 
uint16 Index [EC_MAXODLIST]
 
uint16 DataType [EC_MAXODLIST]
 
uint8 ObjectCode [EC_MAXODLIST]
 
uint8 MaxSub [EC_MAXODLIST]
 
char Name [EC_MAXODLIST][EC_MAXNAME+1]
 
+

Field Documentation

+ +
+
+ + + + +
uint16 ec_ODlistt::DataType[EC_MAXODLIST]
+
+

array of datatypes, see EtherCAT specification

+ +
+
+ +
+
+ + + + +
uint16 ec_ODlistt::Entries
+
+

number of entries in list

+ +
+
+ +
+
+ + + + +
uint16 ec_ODlistt::Index[EC_MAXODLIST]
+
+

array of indexes

+ +
+
+ +
+
+ + + + +
uint8 ec_ODlistt::MaxSub[EC_MAXODLIST]
+
+

number of subindexes for each index

+ +
+
+ +
+
+ + + + +
char ec_ODlistt::Name[EC_MAXODLIST][EC_MAXNAME+1]
+
+

textual description of each index

+ +
+
+ +
+
+ + + + +
uint8 ec_ODlistt::ObjectCode[EC_MAXODLIST]
+
+

array of object codes, see EtherCAT specification

+ +
+
+ +
+
+ + + + +
uint16 ec_ODlistt::Slave
+
+

slave number

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__OElistt.html b/doc/html/structec__OElistt.html new file mode 100644 index 0000000..fc90b3a --- /dev/null +++ b/doc/html/structec__OElistt.html @@ -0,0 +1,159 @@ + + + + + + +SOEM: ec_OElistt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_OElistt Struct Reference
+
+
+ +

#include <ethercatcoe.h>

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

+Data Fields

uint16 Entries
 
uint8 ValueInfo [EC_MAXOELIST]
 
uint16 DataType [EC_MAXOELIST]
 
uint16 BitLength [EC_MAXOELIST]
 
uint16 ObjAccess [EC_MAXOELIST]
 
char Name [EC_MAXOELIST][EC_MAXNAME+1]
 
+

Field Documentation

+ +
+
+ + + + +
uint16 ec_OElistt::BitLength[EC_MAXOELIST]
+
+

array of bit lengths, see EtherCAT specification

+ +
+
+ +
+
+ + + + +
uint16 ec_OElistt::DataType[EC_MAXOELIST]
+
+

array of value infos, see EtherCAT specification

+ +
+
+ +
+
+ + + + +
uint16 ec_OElistt::Entries
+
+

number of entries in list

+ +
+
+ +
+
+ + + + +
char ec_OElistt::Name[EC_MAXOELIST][EC_MAXNAME+1]
+
+

textual description of each index

+ +
+
+ +
+
+ + + + +
uint16 ec_OElistt::ObjAccess[EC_MAXOELIST]
+
+

array of object access bits, see EtherCAT specification

+ +
+
+ +
+
+ + + + +
uint8 ec_OElistt::ValueInfo[EC_MAXOELIST]
+
+

array of value infos, see EtherCAT specification

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__PDOassignt.html b/doc/html/structec__PDOassignt.html new file mode 100644 index 0000000..87420a6 --- /dev/null +++ b/doc/html/structec__PDOassignt.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_PDOassignt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_PDOassignt Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint8 n
 
uint8 nu1
 
uint16 index [256]
 
+

Detailed Description

+

SDO assign structure for CA

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_PDOassignt::index[256]
+
+ +
+
+ +
+
+ + + + +
uint8 ec_PDOassignt::n
+
+ +
+
+ +
+
+ + + + +
uint8 ec_PDOassignt::nu1
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__PDOdesct.html b/doc/html/structec__PDOdesct.html new file mode 100644 index 0000000..030e763 --- /dev/null +++ b/doc/html/structec__PDOdesct.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_PDOdesct Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_PDOdesct Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint8 n
 
uint8 nu1
 
uint32 PDO [256]
 
+

Detailed Description

+

SDO description structure for CA

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_PDOdesct::n
+
+ +
+
+ +
+
+ + + + +
uint8 ec_PDOdesct::nu1
+
+ +
+
+ +
+
+ + + + +
uint32 ec_PDOdesct::PDO[256]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SDOservicet.html b/doc/html/structec__SDOservicet.html new file mode 100644 index 0000000..29dad0e --- /dev/null +++ b/doc/html/structec__SDOservicet.html @@ -0,0 +1,196 @@ + + + + + + +SOEM: ec_SDOservicet Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SDOservicet Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint16 CANOpen
 
uint8 Opcode
 
uint8 Reserved
 
uint16 Fragments
 
union {
   uint8   bdata [0x200]
 
   uint16   wdata [0x100]
 
   uint32   ldata [0x80]
 
}; 
 
+

Detailed Description

+

SDO service structure

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOservicet::bdata[0x200]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOservicet::CANOpen
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOservicet::Fragments
+
+ +
+
+ +
+
+ + + + +
uint32 ec_SDOservicet::ldata[0x80]
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_SDOservicet::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOservicet::Opcode
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOservicet::Reserved
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOservicet::wdata[0x100]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SDOt.html b/doc/html/structec__SDOt.html new file mode 100644 index 0000000..66adf61 --- /dev/null +++ b/doc/html/structec__SDOt.html @@ -0,0 +1,196 @@ + + + + + + +SOEM: ec_SDOt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SDOt Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint16 CANOpen
 
uint8 Command
 
uint16 Index
 
uint8 SubIndex
 
union {
   uint8   bdata [0x200]
 
   uint16   wdata [0x100]
 
   uint32   ldata [0x80]
 
}; 
 
+

Detailed Description

+

SDO structure, not to be confused with EcSDOserviceT

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOt::bdata[0x200]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOt::CANOpen
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOt::Command
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOt::Index
+
+ +
+
+ +
+
+ + + + +
uint32 ec_SDOt::ldata[0x80]
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_SDOt::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SDOt::SubIndex
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SDOt::wdata[0x100]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SMcommtypet.html b/doc/html/structec__SMcommtypet.html new file mode 100644 index 0000000..6bc2cc8 --- /dev/null +++ b/doc/html/structec__SMcommtypet.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_SMcommtypet Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SMcommtypet Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint8 n
 
uint8 nu1
 
uint8 SMtype [EC_MAXSM]
 
+

Detailed Description

+

SyncManager Communication Type structure for CA

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_SMcommtypet::n
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SMcommtypet::nu1
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SMcommtypet::SMtype[EC_MAXSM]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SoEattributet.html b/doc/html/structec__SoEattributet.html new file mode 100644 index 0000000..ebebf88 --- /dev/null +++ b/doc/html/structec__SoEattributet.html @@ -0,0 +1,234 @@ + + + + + + +SOEM: ec_SoEattributet Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SoEattributet Struct Reference
+
+
+ +

#include <ethercatsoe.h>

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

+Data Fields

uint32 evafactor:16
 
uint32 length:2
 
uint32 list:1
 
uint32 command:1
 
uint32 datatype:3
 
uint32 reserved1:1
 
uint32 decimals:4
 
uint32 wppreop:1
 
uint32 wpsafeop:1
 
uint32 wpop:1
 
uint32 reserved2:1
 
+

Detailed Description

+

SoE attribute structure

+

Field Documentation

+ +
+
+ + + + +
uint32 ec_SoEattributet::command
+
+

IDN is command

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::datatype
+
+

datatype

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::decimals
+
+

decimals to display if float datatype

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::evafactor
+
+

evaluation factor for display purposes

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::length
+
+

length of IDN element(s)

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::list
+
+

IDN is list

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::reserved1
+
+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::reserved2
+
+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::wpop
+
+

write protected in op

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::wppreop
+
+

write protected in pre-op

+ +
+
+ +
+
+ + + + +
uint32 ec_SoEattributet::wpsafeop
+
+

write protected in safe-op

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SoElistt.html b/doc/html/structec__SoElistt.html new file mode 100644 index 0000000..d43d567 --- /dev/null +++ b/doc/html/structec__SoElistt.html @@ -0,0 +1,172 @@ + + + + + + +SOEM: ec_SoElistt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SoElistt Struct Reference
+
+
+ +

#include <ethercatsoe.h>

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

+Data Fields

uint16 currentlength
 
uint16 maxlength
 
union {
   uint8   byte [8]
 
   uint16   word [4]
 
   uint32   dword [2]
 
   uint64   lword [1]
 
}; 
 
+

Detailed Description

+

SoE list structure

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoElistt::byte[8]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SoElistt::currentlength
+
+

current length in bytes of list

+ +
+
+ +
+
+ + + + +
uint32 ec_SoElistt::dword[2]
+
+ +
+
+ +
+
+ + + + +
uint64 ec_SoElistt::lword[1]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SoElistt::maxlength
+
+

maximum length in bytes of list

+ +
+
+ +
+
+ + + + +
uint16 ec_SoElistt::word[4]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SoEmappingt.html b/doc/html/structec__SoEmappingt.html new file mode 100644 index 0000000..c3697ae --- /dev/null +++ b/doc/html/structec__SoEmappingt.html @@ -0,0 +1,115 @@ + + + + + + +SOEM: ec_SoEmappingt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SoEmappingt Struct Reference
+
+
+ +

#include <ethercatsoe.h>

+ + + + + + + + +

+Data Fields

uint16 currentlength
 
uint16 maxlength
 
uint16 idn [EC_SOE_MAXMAPPING]
 
+

Detailed Description

+

SoE IDN mapping structure

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_SoEmappingt::currentlength
+
+

current length in bytes of list

+ +
+
+ +
+
+ + + + +
uint16 ec_SoEmappingt::idn[EC_SOE_MAXMAPPING]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SoEmappingt::maxlength
+
+

maximum length in bytes of list

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SoEnamet.html b/doc/html/structec__SoEnamet.html new file mode 100644 index 0000000..e543e39 --- /dev/null +++ b/doc/html/structec__SoEnamet.html @@ -0,0 +1,115 @@ + + + + + + +SOEM: ec_SoEnamet Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SoEnamet Struct Reference
+
+
+ +

#include <ethercatsoe.h>

+ + + + + + + + +

+Data Fields

uint16 currentlength
 
uint16 maxlength
 
char name [EC_SOE_MAXNAME]
 
+

Detailed Description

+

SoE name structure

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_SoEnamet::currentlength
+
+

current length in bytes of list

+ +
+
+ +
+
+ + + + +
uint16 ec_SoEnamet::maxlength
+
+

maximum length in bytes of list

+ +
+
+ +
+
+ + + + +
char ec_SoEnamet::name[EC_SOE_MAXNAME]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__SoEt.html b/doc/html/structec__SoEt.html new file mode 100644 index 0000000..5054d7e --- /dev/null +++ b/doc/html/structec__SoEt.html @@ -0,0 +1,196 @@ + + + + + + +SOEM: ec_SoEt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_SoEt Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint8 opCode:3
 
uint8 incomplete:1
 
uint8 error:1
 
uint8 driveNo:3
 
uint8 elementflags
 
union {
   uint16   idn
 
   uint16   fragmentsleft
 
}; 
 
+

Detailed Description

+

SoE (Servo over EtherCAT) mailbox structure

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoEt::driveNo
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoEt::elementflags
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoEt::error
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SoEt::fragmentsleft
+
+ +
+
+ +
+
+ + + + +
uint16 ec_SoEt::idn
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoEt::incomplete
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_SoEt::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint8 ec_SoEt::opCode
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__adapter.html b/doc/html/structec__adapter.html new file mode 100644 index 0000000..1996ae7 --- /dev/null +++ b/doc/html/structec__adapter.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: ec_adaptert Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_adaptert Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

char name [EC_MAXLEN_ADAPTERNAME]
 
char desc [EC_MAXLEN_ADAPTERNAME]
 
ec_adaptert * next
 
+

Field Documentation

+ +
+
+ + + + +
char ec_adaptert::desc[EC_MAXLEN_ADAPTERNAME]
+
+ +
+
+ +
+
+ + + + +
char ec_adaptert::name[EC_MAXLEN_ADAPTERNAME]
+
+ +
+
+ +
+
+ + + + +
ec_adaptert* ec_adaptert::next
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__alstatust.html b/doc/html/structec__alstatust.html new file mode 100644 index 0000000..81c97ce --- /dev/null +++ b/doc/html/structec__alstatust.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_alstatust Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_alstatust Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint16 alstatus
 
uint16 unused
 
uint16 alstatuscode
 
+

Detailed Description

+

ALstatus and ALstatus code

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_alstatust::alstatus
+
+ +
+
+ +
+
+ + + + +
uint16 ec_alstatust::alstatuscode
+
+ +
+
+ +
+
+ + + + +
uint16 ec_alstatust::unused
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__comt.html b/doc/html/structec__comt.html new file mode 100644 index 0000000..8839a01 --- /dev/null +++ b/doc/html/structec__comt.html @@ -0,0 +1,176 @@ + + + + + + +SOEM: ec_comt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_comt Struct Reference
+
+
+ +

#include <ethercattype.h>

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

+Data Fields

uint16 elength
 
uint8 command
 
uint8 index
 
uint16 ADP
 
uint16 ADO
 
uint16 dlength
 
uint16 irpt
 
+

Detailed Description

+

EtherCAT datagram header definition

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_comt::ADO
+
+

ADO

+ +
+
+ +
+
+ + + + +
uint16 ec_comt::ADP
+
+

ADP

+ +
+
+ +
+
+ + + + +
uint8 ec_comt::command
+
+

EtherCAT command, see ec_cmdtype

+ +
+
+ +
+
+ + + + +
uint16 ec_comt::dlength
+
+

length of data portion in datagram

+ +
+
+ +
+
+ + + + +
uint16 ec_comt::elength
+
+

length of EtherCAT datagram

+ +
+
+ +
+
+ + + + +
uint8 ec_comt::index
+
+

index, used in SOEM for Tx to Rx recombination

+ +
+
+ +
+
+ + + + +
uint16 ec_comt::irpt
+
+

interrupt, currently unused

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__configlist__t.html b/doc/html/structec__configlist__t.html new file mode 100644 index 0000000..3d93a82 --- /dev/null +++ b/doc/html/structec__configlist__t.html @@ -0,0 +1,249 @@ + + + + + + +SOEM: ec_configlist_t Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_configlist_t Struct Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

uint32 man
 
uint32 id
 
char name [EC_MAXNAME+1]
 
uint8 Dtype
 
uint16 Ibits
 
uint16 Obits
 
uint16 SM2a
 
uint32 SM2f
 
uint16 SM3a
 
uint32 SM3f
 
uint8 FM0ac
 
uint8 FM1ac
 
+

Detailed Description

+

Slave configuration structure

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_configlist_t::Dtype
+
+

Data type

+ +
+
+ +
+
+ + + + +
uint8 ec_configlist_t::FM0ac
+
+

FMMU 0 activation

+ +
+
+ +
+
+ + + + +
uint8 ec_configlist_t::FM1ac
+
+

FMMU 1 activation

+ +
+
+ +
+
+ + + + +
uint16 ec_configlist_t::Ibits
+
+

Input bits

+ +
+
+ +
+
+ + + + +
uint32 ec_configlist_t::id
+
+

ID of slave

+ +
+
+ +
+
+ + + + +
uint32 ec_configlist_t::man
+
+

Manufacturer code of slave

+ +
+
+ +
+
+ + + + +
char ec_configlist_t::name[EC_MAXNAME+1]
+
+

Readable name

+ +
+
+ +
+
+ + + + +
uint16 ec_configlist_t::Obits
+
+

Output bits

+ +
+
+ +
+
+ + + + +
uint16 ec_configlist_t::SM2a
+
+

SyncManager 2 address

+ +
+
+ +
+
+ + + + +
uint32 ec_configlist_t::SM2f
+
+

SyncManager 2 flags

+ +
+
+ +
+
+ + + + +
uint16 ec_configlist_t::SM3a
+
+

SyncManager 3 address

+ +
+
+ +
+
+ + + + +
uint32 ec_configlist_t::SM3f
+
+

SyncManager 3 flags

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__eepromFMMUt.html b/doc/html/structec__eepromFMMUt.html new file mode 100644 index 0000000..e0e8fea --- /dev/null +++ b/doc/html/structec__eepromFMMUt.html @@ -0,0 +1,155 @@ + + + + + + +SOEM: ec_eepromFMMUt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_eepromFMMUt Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint16 Startpos
 
uint8 nFMMU
 
uint8 FMMU0
 
uint8 FMMU1
 
uint8 FMMU2
 
uint8 FMMU3
 
+

Detailed Description

+

SII FMMU structure

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_eepromFMMUt::FMMU0
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromFMMUt::FMMU1
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromFMMUt::FMMU2
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromFMMUt::FMMU3
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromFMMUt::nFMMU
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromFMMUt::Startpos
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__eepromPDOt.html b/doc/html/structec__eepromPDOt.html new file mode 100644 index 0000000..a495a60 --- /dev/null +++ b/doc/html/structec__eepromPDOt.html @@ -0,0 +1,169 @@ + + + + + + +SOEM: ec_eepromPDOt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_eepromPDOt Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint16 Startpos
 
uint16 Length
 
uint16 nPDO
 
uint16 Index [EC_MAXEEPDO]
 
uint16 SyncM [EC_MAXEEPDO]
 
uint16 BitSize [EC_MAXEEPDO]
 
uint16 SMbitsize [EC_MAXSM]
 
+

Detailed Description

+

record to store rxPDO and txPDO table from eeprom

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_eepromPDOt::BitSize[EC_MAXEEPDO]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::Index[EC_MAXEEPDO]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::Length
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::nPDO
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::SMbitsize[EC_MAXSM]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::Startpos
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromPDOt::SyncM[EC_MAXEEPDO]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__eepromSMt.html b/doc/html/structec__eepromSMt.html new file mode 100644 index 0000000..c9b53c9 --- /dev/null +++ b/doc/html/structec__eepromSMt.html @@ -0,0 +1,183 @@ + + + + + + +SOEM: ec_eepromSMt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_eepromSMt Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint16 Startpos
 
uint8 nSM
 
uint16 PhStart
 
uint16 Plength
 
uint8 Creg
 
uint8 Sreg
 
uint8 Activate
 
uint8 PDIctrl
 
+

Detailed Description

+

SII SM structure

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_eepromSMt::Activate
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromSMt::Creg
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromSMt::nSM
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromSMt::PDIctrl
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromSMt::PhStart
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromSMt::Plength
+
+ +
+
+ +
+
+ + + + +
uint8 ec_eepromSMt::Sreg
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromSMt::Startpos
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__eepromt.html b/doc/html/structec__eepromt.html new file mode 100644 index 0000000..47cb25d --- /dev/null +++ b/doc/html/structec__eepromt.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: ec_eepromt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_eepromt Struct Reference
+
+
+ + + + + + + + +

+Data Fields

uint16 comm
 
uint16 addr
 
uint16 d2
 
+

Detailed Description

+

record for ethercat eeprom communications

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_eepromt::addr
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromt::comm
+
+ +
+
+ +
+
+ + + + +
uint16 ec_eepromt::d2
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__emcyt.html b/doc/html/structec__emcyt.html new file mode 100644 index 0000000..48c89d8 --- /dev/null +++ b/doc/html/structec__emcyt.html @@ -0,0 +1,167 @@ + + + + + + +SOEM: ec_emcyt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_emcyt Struct Reference
+
+
+ + + + + + + + + + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint16 CANOpen
 
uint16 ErrorCode
 
uint8 ErrorReg
 
uint8 bData
 
uint16 w1
 
uint16 w2
 
+

Detailed Description

+

emergency request structure

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_emcyt::bData
+
+ +
+
+ +
+
+ + + + +
uint16 ec_emcyt::CANOpen
+
+ +
+
+ +
+
+ + + + +
uint16 ec_emcyt::ErrorCode
+
+ +
+
+ +
+
+ + + + +
uint8 ec_emcyt::ErrorReg
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_emcyt::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint16 ec_emcyt::w1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_emcyt::w2
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__eringt.html b/doc/html/structec__eringt.html new file mode 100644 index 0000000..90bf93c --- /dev/null +++ b/doc/html/structec__eringt.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_eringt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_eringt Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

int16 head
 
int16 tail
 
ec_errort Error [EC_MAXELIST+1]
 
+

Detailed Description

+

ringbuf for error storage

+

Field Documentation

+ +
+
+ + + + +
ec_errort ec_eringt::Error[EC_MAXELIST+1]
+
+ +
+
+ +
+
+ + + + +
int16 ec_eringt::head
+
+ +
+
+ +
+
+ + + + +
int16 ec_eringt::tail
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__errort.html b/doc/html/structec__errort.html new file mode 100644 index 0000000..84ffa54 --- /dev/null +++ b/doc/html/structec__errort.html @@ -0,0 +1,264 @@ + + + + + + +SOEM: ec_errort Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_errort Struct Reference
+
+
+ +

#include <ethercattype.h>

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

+Data Fields

ec_timet Time
 
boolean Signal
 
uint16 Slave
 
uint16 Index
 
uint8 SubIdx
 
ec_err_type Etype
 
union {
   int32   AbortCode
 
   struct {
      uint16   ErrorCode
 
      uint8   ErrorReg
 
      uint8   b1
 
      uint16   w1
 
      uint16   w2
 
   } 
 
}; 
 
+

Detailed Description

+

Struct to retrieve errors.

+

Field Documentation

+ +
+
+ + + + +
union { ... }
+
+ +
+
+ +
+
+ + + + +
int32 ec_errort::AbortCode
+
+

General abortcode

+ +
+
+ +
+
+ + + + +
uint8 ec_errort::b1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_errort::ErrorCode
+
+ +
+
+ +
+
+ + + + +
uint8 ec_errort::ErrorReg
+
+ +
+
+ +
+
+ + + + +
ec_err_type ec_errort::Etype
+
+

Type of error

+ +
+
+ +
+
+ + + + +
uint16 ec_errort::Index
+
+

CoE SDO index that generated the error

+ +
+
+ +
+
+ + + + +
boolean ec_errort::Signal
+
+

Signal bit, error set but not read

+ +
+
+ +
+
+ + + + +
uint16 ec_errort::Slave
+
+

Slave number that generated the error

+ +
+
+ +
+
+ + + + +
uint8 ec_errort::SubIdx
+
+

CoE SDO subindex that generated the error

+ +
+
+ +
+
+ + + + +
ec_timet ec_errort::Time
+
+

Time at which the error was generated.

+ +
+
+ +
+
+ + + + +
uint16 ec_errort::w1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_errort::w2
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__etherheadert.html b/doc/html/structec__etherheadert.html new file mode 100644 index 0000000..62717e9 --- /dev/null +++ b/doc/html/structec__etherheadert.html @@ -0,0 +1,172 @@ + + + + + + +SOEM: ec_etherheadert Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_etherheadert Struct Reference
+
+
+ +

#include <ethercattype.h>

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

+Data Fields

uint16 da0
 
uint16 da1
 
uint16 da2
 
uint16 sa0
 
uint16 sa1
 
uint16 sa2
 
uint16 etype
 
+

Detailed Description

+

ethernet header definition

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_etherheadert::da0
+
+

destination MAC

+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::da1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::da2
+
+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::etype
+
+

ethernet type

+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::sa0
+
+

source MAC

+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::sa1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_etherheadert::sa2
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__fmmut.html b/doc/html/structec__fmmut.html new file mode 100644 index 0000000..e597195 --- /dev/null +++ b/doc/html/structec__fmmut.html @@ -0,0 +1,211 @@ + + + + + + +SOEM: ec_fmmut Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_fmmut Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint32 LogStart
 
uint16 LogLength
 
uint8 LogStartbit
 
uint8 LogEndbit
 
uint16 PhysStart
 
uint8 PhysStartBit
 
uint8 FMMUtype
 
uint8 FMMUactive
 
uint8 unused1
 
uint16 unused2
 
+

Detailed Description

+

record for FMMU

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_fmmut::FMMUactive
+
+ +
+
+ +
+
+ + + + +
uint8 ec_fmmut::FMMUtype
+
+ +
+
+ +
+
+ + + + +
uint8 ec_fmmut::LogEndbit
+
+ +
+
+ +
+
+ + + + +
uint16 ec_fmmut::LogLength
+
+ +
+
+ +
+
+ + + + +
uint32 ec_fmmut::LogStart
+
+ +
+
+ +
+
+ + + + +
uint8 ec_fmmut::LogStartbit
+
+ +
+
+ +
+
+ + + + +
uint16 ec_fmmut::PhysStart
+
+ +
+
+ +
+
+ + + + +
uint8 ec_fmmut::PhysStartBit
+
+ +
+
+ +
+
+ + + + +
uint8 ec_fmmut::unused1
+
+ +
+
+ +
+
+ + + + +
uint16 ec_fmmut::unused2
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__groupt.html b/doc/html/structec__groupt.html new file mode 100644 index 0000000..1ae359b --- /dev/null +++ b/doc/html/structec__groupt.html @@ -0,0 +1,311 @@ + + + + + + +SOEM: ec_groupt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_groupt Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint32 logstartaddr
 
uint32 Obytes
 
uint8 * outputs
 
uint32 Ibytes
 
uint8 * inputs
 
boolean hasdc
 
uint16 DCnext
 
int16 Ebuscurrent
 
uint8 blockLRW
 
uint16 nsegments
 
uint16 Isegment
 
uint16 Ioffset
 
uint16 outputsWKC
 
uint16 inputsWKC
 
boolean docheckstate
 
uint32 IOsegment [EC_MAXIOSEGMENTS]
 
+

Detailed Description

+

for list of ethercat slave groups

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_groupt::blockLRW
+
+

if >0 block use of LRW in processdata

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::DCnext
+
+

next DC slave

+ +
+
+ +
+
+ + + + +
boolean ec_groupt::docheckstate
+
+

check slave states

+ +
+
+ +
+
+ + + + +
int16 ec_groupt::Ebuscurrent
+
+

E-bus current

+ +
+
+ +
+
+ + + + +
boolean ec_groupt::hasdc
+
+

has DC capabillity

+ +
+
+ +
+
+ + + + +
uint32 ec_groupt::Ibytes
+
+

input bytes, if Ibits < 8 then Ibytes = 0

+ +
+
+ +
+
+ + + + +
uint8* ec_groupt::inputs
+
+

input pointer in IOmap buffer

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::inputsWKC
+
+

Expected workcounter inputs

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::Ioffset
+
+

Offset in input segment

+ +
+
+ +
+
+ + + + +
uint32 ec_groupt::IOsegment[EC_MAXIOSEGMENTS]
+
+

IO segmentation list. Datagrams must not break SM in two.

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::Isegment
+
+

1st input segment

+ +
+
+ +
+
+ + + + +
uint32 ec_groupt::logstartaddr
+
+

logical start address for this group

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::nsegments
+
+

IO segegments used

+ +
+
+ +
+
+ + + + +
uint32 ec_groupt::Obytes
+
+

output bytes, if Obits < 8 then Obytes = 0

+ +
+
+ +
+
+ + + + +
uint8* ec_groupt::outputs
+
+

output pointer in IOmap buffer

+ +
+
+ +
+
+ + + + +
uint16 ec_groupt::outputsWKC
+
+

Expected workcounter outputs

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__idxstackT.html b/doc/html/structec__idxstackT.html new file mode 100644 index 0000000..6617b36 --- /dev/null +++ b/doc/html/structec__idxstackT.html @@ -0,0 +1,141 @@ + + + + + + +SOEM: ec_idxstackT Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_idxstackT Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint8 pushed
 
uint8 pulled
 
uint8 idx [EC_MAXBUF]
 
void * data [EC_MAXBUF]
 
uint16 length [EC_MAXBUF]
 
+

Detailed Description

+

stack structure to store segmented LRD/LWR/LRW constructs

+

Field Documentation

+ +
+
+ + + + +
void* ec_idxstackT::data[EC_MAXBUF]
+
+ +
+
+ +
+
+ + + + +
uint8 ec_idxstackT::idx[EC_MAXBUF]
+
+ +
+
+ +
+
+ + + + +
uint16 ec_idxstackT::length[EC_MAXBUF]
+
+ +
+
+ +
+
+ + + + +
uint8 ec_idxstackT::pulled
+
+ +
+
+ +
+
+ + + + +
uint8 ec_idxstackT::pushed
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__mbxerrorlist__t.html b/doc/html/structec__mbxerrorlist__t.html new file mode 100644 index 0000000..c647d7a --- /dev/null +++ b/doc/html/structec__mbxerrorlist__t.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: ec_mbxerrorlist_t Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_mbxerrorlist_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint16 errorcode
 
char errordescription [EC_MAXERRORNAME+1]
 
+

Detailed Description

+

MBX error list type definition

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_mbxerrorlist_t::errorcode
+
+

MBX error code

+ +
+
+ +
+
+ + + + +
char ec_mbxerrorlist_t::errordescription[EC_MAXERRORNAME+1]
+
+

Readable description

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__mbxerrort.html b/doc/html/structec__mbxerrort.html new file mode 100644 index 0000000..ac415af --- /dev/null +++ b/doc/html/structec__mbxerrort.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: ec_mbxerrort Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_mbxerrort Struct Reference
+
+
+ + + + + + + + +

+Data Fields

ec_mbxheadert MbxHeader
 
uint16 Type
 
uint16 Detail
 
+

Detailed Description

+

mailbox error structure

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_mbxerrort::Detail
+
+ +
+
+ +
+
+ + + + +
ec_mbxheadert ec_mbxerrort::MbxHeader
+
+ +
+
+ +
+
+ + + + +
uint16 ec_mbxerrort::Type
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__mbxheadert.html b/doc/html/structec__mbxheadert.html new file mode 100644 index 0000000..a38c5c8 --- /dev/null +++ b/doc/html/structec__mbxheadert.html @@ -0,0 +1,127 @@ + + + + + + +SOEM: ec_mbxheadert Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_mbxheadert Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + + + +

+Data Fields

uint16 length
 
uint16 address
 
uint8 priority
 
uint8 mbxtype
 
+

Detailed Description

+

standard ethercat mailbox header

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_mbxheadert::address
+
+ +
+
+ +
+
+ + + + +
uint16 ec_mbxheadert::length
+
+ +
+
+ +
+
+ + + + +
uint8 ec_mbxheadert::mbxtype
+
+ +
+
+ +
+
+ + + + +
uint8 ec_mbxheadert::priority
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__sdoerrorlist__t.html b/doc/html/structec__sdoerrorlist__t.html new file mode 100644 index 0000000..92cd7d0 --- /dev/null +++ b/doc/html/structec__sdoerrorlist__t.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: ec_sdoerrorlist_t Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_sdoerrorlist_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint32 errorcode
 
char errordescription [EC_MAXERRORNAME+1]
 
+

Detailed Description

+

SDO error list type definition

+

Field Documentation

+ +
+
+ + + + +
uint32 ec_sdoerrorlist_t::errorcode
+
+

Error code returned from SDO

+ +
+
+ +
+
+ + + + +
char ec_sdoerrorlist_t::errordescription[EC_MAXERRORNAME+1]
+
+

Readable error description

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__slavet.html b/doc/html/structec__slavet.html new file mode 100644 index 0000000..310de58 --- /dev/null +++ b/doc/html/structec__slavet.html @@ -0,0 +1,1016 @@ + + + + + + +SOEM: ec_slavet Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_slavet Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

uint16 state
 
uint16 ALstatuscode
 
uint16 configadr
 
uint16 aliasadr
 
uint32 eep_man
 
uint32 eep_id
 
uint32 eep_rev
 
uint16 Itype
 
uint16 Dtype
 
uint16 Obits
 
uint32 Obytes
 
uint8 * outputs
 
uint8 Ostartbit
 
uint16 Ibits
 
uint32 Ibytes
 
uint8 * inputs
 
uint8 Istartbit
 
ec_smt SM [EC_MAXSM]
 
uint8 SMtype [EC_MAXSM]
 
ec_fmmut FMMU [EC_MAXFMMU]
 
uint8 FMMU0func
 
uint8 FMMU1func
 
uint8 FMMU2func
 
uint8 FMMU3func
 
uint16 mbx_l
 
uint16 mbx_wo
 
uint16 mbx_rl
 
uint16 mbx_ro
 
uint16 mbx_proto
 
uint8 mbx_cnt
 
boolean hasdc
 
uint8 ptype
 
uint8 topology
 
uint8 activeports
 
uint8 consumedports
 
uint16 parent
 
uint8 parentport
 
uint8 entryport
 
int32 DCrtA
 
int32 DCrtB
 
int32 DCrtC
 
int32 DCrtD
 
int32 pdelay
 
uint16 DCnext
 
uint16 DCprevious
 
int32 DCcycle
 
int32 DCshift
 
uint8 DCactive
 
uint16 configindex
 
uint16 SIIindex
 
uint8 eep_8byte
 
uint8 eep_pdi
 
uint8 CoEdetails
 
uint8 FoEdetails
 
uint8 EoEdetails
 
uint8 SoEdetails
 
int16 Ebuscurrent
 
uint8 blockLRW
 
uint8 group
 
uint8 FMMUunused
 
boolean islost
 
int(* PO2SOconfig )(uint16 slave)
 
char name [EC_MAXNAME+1]
 
+

Detailed Description

+

for list of ethercat slaves detected

+

Field Documentation

+ +
+
+ + + + +
uint8 ec_slavet::activeports
+
+

active ports bitmap : ....3210 , set if respective port is active

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::aliasadr
+
+

Alias address

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::ALstatuscode
+
+

AL status code

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::blockLRW
+
+

if >0 block use of LRW in processdata

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::CoEdetails
+
+

CoE details

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::configadr
+
+

Configured address

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::configindex
+
+

link to config table

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::consumedports
+
+

consumed ports bitmap : ....3210, used for internal delay measurement

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::DCactive
+
+

DC sync activation, 0=off, 1=on

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCcycle
+
+

DC cyle time in ns

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::DCnext
+
+

next DC slave

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::DCprevious
+
+

previous DC slave

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCrtA
+
+

DC receivetimes on port A

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCrtB
+
+

DC receivetimes on port B

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCrtC
+
+

DC receivetimes on port C

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCrtD
+
+

DC receivetimes on port D

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::DCshift
+
+

DC shift from clock modulus boundary

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::Dtype
+
+

Device type

+ +
+
+ +
+
+ + + + +
int16 ec_slavet::Ebuscurrent
+
+

E-bus current

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::eep_8byte
+
+

1 = 8 bytes per read, 0 = 4 bytes per read

+ +
+
+ +
+
+ + + + +
uint32 ec_slavet::eep_id
+
+

ID from EEprom

+ +
+
+ +
+
+ + + + +
uint32 ec_slavet::eep_man
+
+

Manufacturer from EEprom

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::eep_pdi
+
+

0 = eeprom to master , 1 = eeprom to PDI

+ +
+
+ +
+
+ + + + +
uint32 ec_slavet::eep_rev
+
+

revision from EEprom

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::entryport
+
+

port number on this slave the parent is connected to

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::EoEdetails
+
+

EoE details

+ +
+
+ +
+
+ + + + +
ec_fmmut ec_slavet::FMMU[EC_MAXFMMU]
+
+

FMMU structure

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FMMU0func
+
+

FMMU0 function

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FMMU1func
+
+

FMMU1 function

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FMMU2func
+
+

FMMU2 function

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FMMU3func
+
+

FMMU3 function

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FMMUunused
+
+

first unused FMMU

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::FoEdetails
+
+

FoE details

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::group
+
+

group

+ +
+
+ +
+
+ + + + +
boolean ec_slavet::hasdc
+
+

has DC capabillity

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::Ibits
+
+

input bits

+ +
+
+ +
+
+ + + + +
uint32 ec_slavet::Ibytes
+
+

input bytes, if Ibits < 8 then Ibytes = 0

+ +
+
+ +
+
+ + + + +
uint8* ec_slavet::inputs
+
+

input pointer in IOmap buffer

+ +
+
+ +
+
+ + + + +
boolean ec_slavet::islost
+
+

TRUE is slave is not responding at all

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::Istartbit
+
+

startbit in first input byte

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::Itype
+
+

Interface type

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::mbx_cnt
+
+

Counter value of mailbox link layer protocol 1..7

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::mbx_l
+
+

length of write mailbox in bytes, if no mailbox then 0

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::mbx_proto
+
+

mailbox supported protocols

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::mbx_rl
+
+

length of read mailbox in bytes

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::mbx_ro
+
+

mailbox read offset

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::mbx_wo
+
+

mailbox write offset

+ +
+
+ +
+
+ + + + +
char ec_slavet::name[EC_MAXNAME+1]
+
+

readable name

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::Obits
+
+

output bits

+ +
+
+ +
+
+ + + + +
uint32 ec_slavet::Obytes
+
+

output bytes, if Obits < 8 then Obytes = 0

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::Ostartbit
+
+

startbit in first output byte

+ +
+
+ +
+
+ + + + +
uint8* ec_slavet::outputs
+
+

output pointer in IOmap buffer

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::parent
+
+

slave number for parent, 0=master

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::parentport
+
+

port number on parent this slave is connected to

+ +
+
+ +
+
+ + + + +
int32 ec_slavet::pdelay
+
+

propagation delay

+ +
+
+ +
+
+ + + + +
int(* ec_slavet::PO2SOconfig)(uint16 slave)
+
+

registered configuration function PO->SO

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::ptype
+
+

Physical type; Ebus, EtherNet combinations

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::SIIindex
+
+

link to SII config

+ +
+
+ +
+
+ + + + +
ec_smt ec_slavet::SM[EC_MAXSM]
+
+

SM structure

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::SMtype[EC_MAXSM]
+
+

SM type 0=unused 1=MbxWr 2=MbxRd 3=Outputs 4=Inputs

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::SoEdetails
+
+

SoE details

+ +
+
+ +
+
+ + + + +
uint16 ec_slavet::state
+
+

state of slave

+ +
+
+ +
+
+ + + + +
uint8 ec_slavet::topology
+
+

topology: 1 to 3 links

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__smt.html b/doc/html/structec__smt.html new file mode 100644 index 0000000..3a44c78 --- /dev/null +++ b/doc/html/structec__smt.html @@ -0,0 +1,113 @@ + + + + + + +SOEM: ec_smt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_smt Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint16 StartAddr
 
uint16 SMlength
 
uint32 SMflags
 
+

Detailed Description

+

record for sync manager

+

Field Documentation

+ +
+
+ + + + +
uint32 ec_smt::SMflags
+
+ +
+
+ +
+
+ + + + +
uint16 ec_smt::SMlength
+
+ +
+
+ +
+
+ + + + +
uint16 ec_smt::StartAddr
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__soeerrorlist__t.html b/doc/html/structec__soeerrorlist__t.html new file mode 100644 index 0000000..1bab8d5 --- /dev/null +++ b/doc/html/structec__soeerrorlist__t.html @@ -0,0 +1,99 @@ + + + + + + +SOEM: ec_soeerrorlist_t Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_soeerrorlist_t Struct Reference
+
+
+ + + + + + +

+Data Fields

uint16 errorcode
 
char errordescription [EC_MAXERRORNAME+1]
 
+

Detailed Description

+

SoE error list type definition

+

Field Documentation

+ +
+
+ + + + +
uint16 ec_soeerrorlist_t::errorcode
+
+

SoE error code

+ +
+
+ +
+
+ + + + +
char ec_soeerrorlist_t::errordescription[EC_MAXERRORNAME+1]
+
+

Readable description

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structec__state__status.html b/doc/html/structec__state__status.html new file mode 100644 index 0000000..dfc0485 --- /dev/null +++ b/doc/html/structec__state__status.html @@ -0,0 +1,111 @@ + + + + + + +SOEM: ec_state_status Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ec_state_status Struct Reference
+
+
+ +

#include <ethercatmain.h>

+ + + + + + + + +

+Data Fields

uint16 State
 
uint16 Unused
 
uint16 ALstatuscode
 
+

Field Documentation

+ +
+
+ + + + +
uint16 ec_state_status::ALstatuscode
+
+ +
+
+ +
+
+ + + + +
uint16 ec_state_status::State
+
+ +
+
+ +
+
+ + + + +
uint16 ec_state_status::Unused
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structecx__contextt.html b/doc/html/structecx__contextt.html new file mode 100644 index 0000000..8502e7f --- /dev/null +++ b/doc/html/structecx__contextt.html @@ -0,0 +1,386 @@ + + + + + + +SOEM: ecx_contextt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
ecx_contextt Struct Reference
+
+
+ +

#include <ethercatmain.h>

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

+Data Fields

ecx_portt * port
 
ec_slavetslavelist
 
int * slavecount
 
int maxslave
 
ec_grouptgrouplist
 
int maxgroup
 
uint8 * esibuf
 
uint32 * esimap
 
uint16 esislave
 
ec_eringtelist
 
ec_idxstackTidxstack
 
boolean * ecaterror
 
uint16 DCtO
 
uint16 DCl
 
int64 * DCtime
 
ec_SMcommtypetSMcommtype
 
ec_PDOassigntPDOassign
 
ec_PDOdesctPDOdesc
 
ec_eepromSMteepSM
 
ec_eepromFMMUteepFMMU
 
int(* FOEhook )(uint16 slave, int packetnumber, int datasize)
 
+

Detailed Description

+

Context structure , referenced by all ecx functions

+

Field Documentation

+ +
+
+ + + + +
uint16 ecx_contextt::DCl
+
+

internal, length of DC datagram

+ +
+
+ +
+
+ + + + +
int64* ecx_contextt::DCtime
+
+

reference to last DC time from slaves

+ +
+
+ +
+
+ + + + +
uint16 ecx_contextt::DCtO
+
+

internal, position of DC datagram in process data packet

+ +
+
+ +
+
+ + + + +
boolean* ecx_contextt::ecaterror
+
+

reference to ecaterror state

+ +
+
+ +
+
+ + + + +
ec_eepromFMMUt* ecx_contextt::eepFMMU
+
+

internal, FMMU list from eeprom

+ +
+
+ +
+
+ + + + +
ec_eepromSMt* ecx_contextt::eepSM
+
+

internal, SM list from eeprom

+ +
+
+ +
+
+ + + + +
ec_eringt* ecx_contextt::elist
+
+

internal, reference to error list

+ +
+
+ +
+
+ + + + +
uint8* ecx_contextt::esibuf
+
+

internal, reference to eeprom cache buffer

+ +
+
+ +
+
+ + + + +
uint32* ecx_contextt::esimap
+
+

internal, reference to eeprom cache map

+ +
+
+ +
+
+ + + + +
uint16 ecx_contextt::esislave
+
+

internal, current slave for eeprom cache

+ +
+
+ +
+
+ + + + +
int(* ecx_contextt::FOEhook)(uint16 slave, int packetnumber, int datasize)
+
+

registered FoE hook

+ +
+
+ +
+
+ + + + +
ec_groupt* ecx_contextt::grouplist
+
+

grouplist reference

+ +
+
+ +
+
+ + + + +
ec_idxstackT* ecx_contextt::idxstack
+
+

internal, reference to processdata stack buffer info

+ +
+
+ +
+
+ + + + +
int ecx_contextt::maxgroup
+
+

maximum number of groups allowed in grouplist

+ +
+
+ +
+
+ + + + +
int ecx_contextt::maxslave
+
+

maximum number of slaves allowed in slavelist

+ +
+
+ +
+
+ + + + +
ec_PDOassignt* ecx_contextt::PDOassign
+
+

internal, PDO assign list

+ +
+
+ +
+
+ + + + +
ec_PDOdesct* ecx_contextt::PDOdesc
+
+

internal, PDO description list

+ +
+
+ +
+
+ + + + +
ecx_portt* ecx_contextt::port
+
+

port reference, may include red_port

+ +
+
+ +
+
+ + + + +
int* ecx_contextt::slavecount
+
+

number of slaves found in configuration

+ +
+
+ +
+
+ + + + +
ec_slavet* ecx_contextt::slavelist
+
+

slavelist reference

+ +
+
+ +
+
+ + + + +
ec_SMcommtypet* ecx_contextt::SMcommtype
+
+

internal, SM buffer

+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structin__EBOX__streamt.html b/doc/html/structin__EBOX__streamt.html new file mode 100644 index 0000000..195568a --- /dev/null +++ b/doc/html/structin__EBOX__streamt.html @@ -0,0 +1,95 @@ + + + + + + +SOEM: in_EBOX_streamt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
in_EBOX_streamt Struct Reference
+
+
+ + + + + + +

+Data Fields

uint8 counter
 
int16 stream [100]
 
+

Field Documentation

+ +
+
+ + + + +
uint8 in_EBOX_streamt::counter
+
+ +
+
+ +
+
+ + + + +
int16 in_EBOX_streamt::stream[100]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structin__EBOXt.html b/doc/html/structin__EBOXt.html new file mode 100644 index 0000000..25ec9fc --- /dev/null +++ b/doc/html/structin__EBOXt.html @@ -0,0 +1,151 @@ + + + + + + +SOEM: in_EBOXt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
in_EBOXt Struct Reference
+
+
+ + + + + + + + + + + + + + +

+Data Fields

uint8 status
 
uint8 counter
 
uint8 din
 
int32 ain [2]
 
uint32 tsain
 
int32 enc [2]
 
+

Field Documentation

+ +
+
+ + + + +
int32 in_EBOXt::ain[2]
+
+ +
+
+ +
+
+ + + + +
uint8 in_EBOXt::counter
+
+ +
+
+ +
+
+ + + + +
uint8 in_EBOXt::din
+
+ +
+
+ +
+
+ + + + +
int32 in_EBOXt::enc[2]
+
+ +
+
+ +
+
+ + + + +
uint8 in_EBOXt::status
+
+ +
+
+ +
+
+ + + + +
uint32 in_EBOXt::tsain
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structout__EBOX__streamt.html b/doc/html/structout__EBOX__streamt.html new file mode 100644 index 0000000..1dbe9dc --- /dev/null +++ b/doc/html/structout__EBOX__streamt.html @@ -0,0 +1,81 @@ + + + + + + +SOEM: out_EBOX_streamt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
out_EBOX_streamt Struct Reference
+
+
+ + + + +

+Data Fields

uint8 control
 
+

Field Documentation

+ +
+
+ + + + +
uint8 out_EBOX_streamt::control
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/structout__EBOXt.html b/doc/html/structout__EBOXt.html new file mode 100644 index 0000000..110b494 --- /dev/null +++ b/doc/html/structout__EBOXt.html @@ -0,0 +1,123 @@ + + + + + + +SOEM: out_EBOXt Struct Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+ +
+
out_EBOXt Struct Reference
+
+
+ + + + + + + + + + +

+Data Fields

uint8 control
 
uint8 dout
 
int16 aout [2]
 
uint16 pwmout [2]
 
+

Field Documentation

+ +
+
+ + + + +
int16 out_EBOXt::aout[2]
+
+ +
+
+ +
+
+ + + + +
uint8 out_EBOXt::control
+
+ +
+
+ +
+
+ + + + +
uint8 out_EBOXt::dout
+
+ +
+
+ +
+
+ + + + +
uint16 out_EBOXt::pwmout[2]
+
+ +
+
+
The documentation for this struct was generated from the following file: +
+ + + + diff --git a/doc/html/sync_off.png b/doc/html/sync_off.png new file mode 100644 index 0000000..3b443fc Binary files /dev/null and b/doc/html/sync_off.png differ diff --git a/doc/html/sync_on.png b/doc/html/sync_on.png new file mode 100644 index 0000000..e08320f Binary files /dev/null and b/doc/html/sync_on.png differ diff --git a/doc/html/tab_a.png b/doc/html/tab_a.png new file mode 100644 index 0000000..3b725c4 Binary files /dev/null and b/doc/html/tab_a.png differ diff --git a/doc/html/tab_b.png b/doc/html/tab_b.png new file mode 100644 index 0000000..e2b4a86 Binary files /dev/null and b/doc/html/tab_b.png differ diff --git a/doc/html/tab_h.png b/doc/html/tab_h.png new file mode 100644 index 0000000..fd5cb70 Binary files /dev/null and b/doc/html/tab_h.png differ diff --git a/doc/html/tab_s.png b/doc/html/tab_s.png new file mode 100644 index 0000000..ab478c9 Binary files /dev/null and b/doc/html/tab_s.png differ diff --git a/doc/html/tabs.css b/doc/html/tabs.css new file mode 100644 index 0000000..9cf578f --- /dev/null +++ b/doc/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/html/tutorial_8txt.html b/doc/html/tutorial_8txt.html new file mode 100644 index 0000000..17e2896 --- /dev/null +++ b/doc/html/tutorial_8txt.html @@ -0,0 +1,274 @@ + + + + + + +SOEM: tutorial.txt File Reference + + + + + + +
+
+ + + + + + +
+
SOEM +  v1.3.0 +
+
+
+ + + + +
+
+
+
tutorial.txt File Reference
+
+
+

Detailed Description

+

+General

+

The SOEM is a library that provides the user application with the means to send and receive EtherCAT frames. It is up to the application to provide means for:

+
    +
  • Reading and writing process data to be sent/received by SOEM
  • +
  • Keeping local IO data synchronised with the global IOmap
  • +
  • Detecting errors reported by SOEM
  • +
  • Managing errors reported by SOEM
  • +
+

The following sections show some basic examples on how to get the SOEM up and running, as well as making use of the process data and checking for errors. Since all code is local to the application or global variables, it is possible to tweak and optimize when possible.

+

The following example shows how to add a main function that will be called by startup code. In this example main's only purpose is to spawn a new task that executes SOEM.

+
int main (void)
+
{
+
rprintp("SOEM (Simple Open EtherCAT Master)\nSimple test\n");
+
+
task_spawn ("simpletest", simpletest, 9, 8192, NULL);
+

+Configuration

+

Followed by start of the application we need to set up the NIC to be used as EtherCAT Ethernet interface. In a simple setup we call ec_init(ifname) and if SOEM comes with support for cable redundancy we call ec_init_redundant that will open a second port as backup. You can send NULL as ifname if you have a dedicated NIC selected in the nicdrv.c. It returns >0 if succeeded.

+
/* initialise SOEM, bind socket to ifname */
+
if (ec_init(ifname))
+

SOEM is a light weight ethercat master library used in embedded systems, It supports only runtime configuration. It requests a BRD (Broad Cast Read) of address 0, all fully functional slaves in the network will respond to this request, and therefore we will get a working counter equal to the number of slaves in the network. ec_config_init also sets up the mailboxes for slaves that support it. When ec_config_init finishes it will have requested all slaves to state PRE_OP. All data read and configured are stored in a global array which acts as a placeholder for key values, consult ec_slave for detailed information.

+
/* find and auto-config slaves */
+
if ( ec_config_init(FALSE) > 0 )
+
{
+
rprintp("%d slaves found and configured.\n",ec_slavecount);
+

SOEM has now discovered and configured the network it is connected to. Now we can verify that all slaves are present as expected. These definitions could be generated by an external tool in an offline .h file. The definitions could be replaced by a struct keeping slave number.

+
#define EK1100_1 1
+
#define EL4001_1 2
+
...
+
#define EL2622_3 8
+
#define EL2622_4 9
+
#define NUMBER_OF_SLAVES 9
+
+
snippet
+
...
+
+
uint32 network_configuration(void)
+
{
+
/* Do we got expected number of slaves from config */
+
if (ec_slavecount < NUMBER_OF_SLAVES)
+
return 0;
+
+
/* Verify slave by slave that it is correct*/
+
if (strcmp(ec_slave[EK1100_1].name,"EK1100"))
+
return 0;
+
else if (strcmp(ec_slave[EL4001_1].name,"EL4001"))
+
return 0;
+
...
+
else if (strcmp(ec_slave[EL2622_4].name,"EL2622"))
+
return 0;
+
+
return 1;
+
}
+
+ +
...
+
if (network_configuration())
+
...
+
else
+
rprintp("Mismatch of network units!\n");
+

We now have the network up and configured. Mailboxes are up for slaves that support it. Next we will create an IOmap and configure the SyncManager's and FMMU's to link the EtherCAT master and the slaves. The IO mapping is done automatically, SOEM strives to keep the logical process image as compact as possible. It is done by trying to fit Bit oriented slaves together in single bytes. Below is an example of 8 slaves and how they are ordered. During mapping SOEM also calculates an expected WKC for the IO mapped together. That is the primary key to detect errors.

+
    +
  • Outputs are placed together in the beginning of the IOmap
  • +
  • Inputs follow
  • +
+

When the mapping is done SOEM requests slaves to enter SAFE_OP.

+
char IOmap[128];
+
...
+
ec_config_map(&IOmap);
+
...
+
+memory_layout.png +
+memory layout, mapping between physical and logical
+

To enter state OP we need to send valid data to outputs. The EtherCAT frame handling is split into ec_send_processdata and ec_receive_processdata.

+
    +
  • ec_send_processdata sends the frame on the NIC and saves the frame on the stack for receive to fetch.
  • +
  • ec_receive_processdata(EC_TIMEOUTRET) tries to fetch the frames on the stack. We send an argument for how long we will try to fetch the frame. ec_receive_processdata returns the working counter.
  • +
+
/* send one valid process data to make outputs in slaves happy*/
+ + +
...
+ +
/* wait for all slaves to reach OP state */
+ +
    +
  • Now we have a system up and running, all slaves are in state operational.
  • +
+

+Application

+

IO data is accessed through the IOmap, the ec_slave struct keep pointers to the start byte in the IO map on slave level together with start bit within the start byte. This way we can bit mask IO on bit level even though SOEM has combined slave data to minimize the frame size to be sent. We'll use slave 8 in the picture above as an example. From a printout from ec_slave we have the following:

+
    +
  • Slave:8
      +
    • Name:EL2622
    • +
    • Output size: 2bits
    • +
    • Input size: 0bits
    • +
    • Configured address: 1008
    • +
    • Outputs address: 18cf6
    • +
    • Inputs address: 0
    • +
    • FMMU0 Ls:2 Ll: 1 Lsb:4 Leb:5 Ps:f00 Psb:0 Ty:2 Act:1
    • +
    +
  • +
+

The Outputs address: 18cf6 is the pointer to slave 8's start byte. The FMMU's Lsb:4 (LogicalStartBit) = ec_slave.Ostartbit telling us how to mask for the individual bits in the combined byte. The same goes for byte addressed slaves, but byte slaves only need the byte start address since they are byte aligned, the start bit will be 0.

+

Some example on how to access different types of data

+

Set an output int 16 value when memory alignment needs to be considered, arguments is:

+
    +
  • slave number in ethercat network
  • +
  • module index as index internal to the slave in case more than one channel
  • +
  • value to write
  • +
+
#define EL4001_1 2
+
...
+
void set_output_int16 (uint16 slave_no, uint8 module_index, int16 value)
+
{
+
uint8 *data_ptr;
+
+
data_ptr = ec_slave[slave_no].outputs;
+
/* Move pointer to correct module index*/
+
data_ptr += module_index * 2;
+
/* Read value byte by byte since all targets can't handle misaligned
+
addresses
+
*/
+
*data_ptr++ = (value >> 0) & 0xFF;
+
*data_ptr++ = (value >> 8) & 0xFF;
+
}
+
...
+
set_output_int16(EL4001_1,0,slave_EL4001_1.out1);
+

Target can handle non aligned pointers to the IOmap

+
typedef struct PACKED
+
{
+
int16 outvalue1;
+
int16 outvalue2;
+
} out_EL4132t;
+
+
out_EL4132t *out_EL4132;
+
...
+
/* connect struct pointers to slave I/O pointers */
+
out_EL4132 = (out_EL4132t*) ec_slave[3].outputs;
+
out_EL4132->outvalue2 = 0x3FFF;
+
+
...
+

Identify and manage errors. The key is the Working Counter, CRC errors and errors local to the slave causing a state change can be detected by loss of Working Counter since the syncmanagers won't get updated. When returning Working Counter don't match Expected Working Counter something is wrong, then it is up to an error handler to act, locate the erroneous slave and decide what action to perform. The error may not be fatal. Some basic code from simple_test.

+
+
expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
+
+
if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate))
+
{
+
if (needlf)
+
{
+
needlf = FALSE;
+
printf("\n");
+
}
+
/* one ore more slaves are not responding */
+ + +
for (slave = 1; slave <= ec_slavecount; slave++)
+
{
+ +
{
+ + +
{
+
printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
+ + +
}
+
else if(ec_slave[slave].state == EC_STATE_SAFE_OP)
+
{
+
printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
+ + +
}
+
else if(ec_slave[slave].state > 0)
+
{
+ +
{
+
ec_slave[slave].islost = FALSE;
+
printf("MESSAGE : slave %d reconfigured\n",slave);
+
}
+
}
+
else if(!ec_slave[slave].islost)
+
{
+
/* re-check state */
+ +
if (!ec_slave[slave].state)
+
{
+ +
printf("ERROR : slave %d lost\n",slave);
+
}
+
}
+
}
+
if (ec_slave[slave].islost)
+
{
+
if(!ec_slave[slave].state)
+
{
+ +
{
+
ec_slave[slave].islost = FALSE;
+
printf("MESSAGE : slave %d recovered\n",slave);
+
}
+
}
+
else
+
{
+
ec_slave[slave].islost = FALSE;
+
printf("MESSAGE : slave %d found\n",slave);
+
}
+
}
+
}
+
if(!ec_group[currentgroup].docheckstate)
+
printf("OK : all slaves resumed OPERATIONAL.\n");
+
}
+

This tutorial is just one way of doing it. Enjoy and happy coding!

+

Andreas Karlsson, rt-labs AB, www.rt-labs.com

+
+ + + + diff --git a/doc/images/memory_layout.png b/doc/images/memory_layout.png new file mode 100644 index 0000000..ef444ba Binary files /dev/null and b/doc/images/memory_layout.png differ diff --git a/doc/soem.dox b/doc/soem.dox new file mode 100644 index 0000000..da85597 --- /dev/null +++ b/doc/soem.dox @@ -0,0 +1,219 @@ +/** + * \mainpage Simple Open EtherCAT Master or SOEM + * + * \section start Tutorial + * For a tutorial on SOEM See tutorial.txt + * + * \section overview Overview + * SOEM is an EtherCAT master library written in c. Its purpose is to learn and + * to use. All users are invited to study the source to get an understanding + * how an EtherCAT master functions and how it interacts with EtherCAT slaves. + * + * As all applications are different SOEM tries to not impose any design architecture. + * Under Linux it can be used in generic user mode, PREEMPT_RT or Xenomai. under Windows + * it can be used as user mode program. + * + * Preconditions Linux: + * - Linux 2.6 kernel. + * - GCC compiler (others might work, just not tested). + * - One (or two if in redundant mode) 100Mb/s NIC that can connect to a RAW socket. + * - Application must run as root / kernel. + * + * Preconditions Windows: + * - Windows2000 - Windows 7 (8 not tested, might work). + * - VC compiler (others might work, just not tested). + * - One (or two if in redundant mode) 100Mb/s NIC that can connect to a RAW socket. + * - WinPcap installed. + * + * Features as of 1.1.2 : + * - Connects to a standard RAW socket. + * - Full redundancy support. + * - Recovery of "out-of-order" frames. + * - Low level functions, BRD, BWR, APRMW, FPRD, LRW.... + * - Blocking or non blocking transfers. + * - Automatic configuration of slaves. + * - Use of internal configuration table (quick). + * - Use of slave internal data in EEprom and/or CoE. + * - Setting and reading of slave state. + * - Automatic generation of processdata mapping. + * - Mailbox link layer support with resend toggle. + * - CoE, SDO read / write. + * - CoE, Complete Access support. + * - CoE, Segmented transfer support. + * - CoE, Object Description list + * - CoE, Emergency and abort SDO support. + * - Distributed Clock (DC) support. + * - Automatic configuration of DC slaves. + * - Automatic sync of clocks with process data exchange. + * - Flexible settting of sync0 and sync1 firing per slave. + * - Access to slave functions through one slave structure. + * - EEPROM read / write. + * - Local cache for EEPROM access with automatic 4/8 byte reading. + * - SII parsing. + * - Portable code, only standard c, usable for embedded applications. + * - All buffers are static so can be memory locked. + * - Support for Little and Big endian targets. + * + * Features as of 1.1.3 : + * - CoE, TxPDO and RxPDO, master is client (beta). + * - FoE, Read and Write file (beta). + * + * Features as of 1.1.4 : + * - FMMU allocation is floating instead of fixed. If needed more than 2 FMMUs are used. + * - SYNC1 generation supported. + * + * Features as of 1.2.0 : + * - Changed license to GPLv2 only. Adresses leagal concerns about master licensing. + * - Slave init and process data mapping is split in two functions. This allows + * dynamic user reconfiguration of PDO mapping. + * - Eeprom transfer to and from PDI + * - Eeprom is released to PDI when going to SAFEOP. + * + * Features as of 1.2.2 : + * - Redesign of topology and delay measurement. 4 port slaves are fully supported now. + * - Delay measurement of slaves that are reverse connected work too. + * - New ethercatprint unit to display errors in readable text. + * + * Features as of 1.2.4 : + * - SoE, servo over EtherCAT support. + * - SoE read request and write request. + * - SoE segmented transfers. + * - SoE error response. + * - Added SoE errors to print module. + * - Auto config of SoE process data. + * + * Features as of 1.2.5 : + * - Added eepromtool, it can read and write the ESC eeprom of a designated slave. + * - Rewrite of eeprom read/write functions. + * - Added infrastructure change to allow slave groups. + * - Added recovery and reconfiguration of slaves after connection loss. + * - Improved CoE PDO assignment read from slaves, no longer assume assign indexes + * as functionally fixed. + * + * Features as of 1.2.8 : + * - Changed directory structure. + * - Changed make file. + * - Moved hardware / OS dependend part in separate directories. + * - Added firm_update tool to upload firmware to slaves in Boot state, use with care. + * - Added DC for LRD/LWR case. + * - Separated expectedWKC to inputsWKC and outputsWKC. + * - Added PreOP->SafeOP hooks in configuration functions. + * - With CoE use expedited download if mailbox size is very small and object <= 4 bytes. + * - Added mailbox error handling. + * - Rewrite of ec_recover_slave() and ec_reconfigure_slave() + * - Added -map option in slaveinfo, shows SOEM IO mapping of all slaves found. + * + * Features as of 1.3.0 : + * - Added win32 target. + * - Added rtk target. + * - Compiles under gcc / visual-c / borland-c. + * - Multiple port support. One master can run concurrent stacks on multiple network ports. + * - All global vars are encapsulated in context struct. + * - All timing abstracted in osal.c. + * - Linux timing converted to get_clock(CLOCK_MONOTONIC). + * - Error messages updated to latest ETG1020 document. + * - FoE transfers now support busy response. + * + * \section start Getting started + * + * For Linux + * - go to project directory + * - source ./setup.sh linux + * - make all + * + * For examples see simple_test.c in ~/test/linux/simple_test. + * First try (assume EtherCAT on eth0): sudo ./simple_test eth0 + * As SOEM uses RAW sockets it will need to run as root. + * + * For Windows + * - have winpcap installed (included with WireShark) + * - go to project directory + * - for VC, run vcvarsall.bat + * f.e. : C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat x86 + * - run make_test_win32_all.bat + * + * \section bugs Squashed bugs + * Version 1.1.3 + * - Added missing Big-Endian conversion in ethercatconfig.c + * - Fixed bug in segmented SDO transfers in ethercatcoe.c + * + * Version 1.1.4 + * - Changed FMMU algorithm of allocation during configuration. EL4732 supported now. + * - Changed the ec_slave structure around SM en FMMU storage. + * - Fixed bug in FoE write in ethercatfoe.c + * + * Version 1.2.0 + * - Fixed bug in type definition of int32 and uint32 for 64bit OS. + * - Fixed bug in maximum dataframe size calculation. + * + * Version 1.2.2 + * - Fixed bugs in ec_adddatagram. + * - Fixed several bugs in CoE object dictionary read functions. + * - Fixed bug in PDO mapping read function. + * - Changed ec_slave structure around topology and delay variables. + * - Added several constants in ethercattype.c + * + * Version 1.2.3 + * - Clear SM enable if size is 0, even if enable is set in SII. + * - Fixed bug in DC propagation delay calculation. Branches with only non DC slaves + * now correctly close root port. + * - Fixed bug in ec_receive_processdata(), wkc now checks for EC_NOFRAME instead of 0. + * - Fixed bug in makefile. + * + * Version 1.2.5 + * - Fixed bugs in ec_config_map(). + * - Added EC_STATE_BOOT constant. + * - Fixed mailbox size bug, In and Out mailbox can now be of different size. + * - Fixed SM type bug. + * - Fixed FoE bugs. + * - Fixed siigetbyte() unaligned copy. + * - Fixed bug in nicdrv.c, socket handles are 0 included. + * - Fixed bug in ethercatconfig.c causing memory corruption. + * + * Version 1.2.8 + * - Fixed NetX mailbox configuration behaviour. + * - Fixed FoE write bug. + * - Fixed SII string read bug. + * - Fixed bug in table lookup for printing + * + * Version 1.3.0 + * - Fixed NetX100 configuration behaviour. + * - Fixed linux gettimeofday() to get_clock(). + * - Fixed eeprom cache flush on reinit. + * - Fixed make for new gcc linker version. + * + * \section legal Legal notice + * Copyright© 2005-2013 Speciaal Machinefabriek Ketels v.o.f. \n + * Copyright© 2005-2013 Arthur Ketels \n + * Copyright© 2008-2010 TU/e Technische Universiteit Eindhoven \n + * Copyright© 2012-2013 RT-labs AB \n + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstrasse 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ diff --git a/doc/tutorial.txt b/doc/tutorial.txt new file mode 100644 index 0000000..1c7ce15 --- /dev/null +++ b/doc/tutorial.txt @@ -0,0 +1,306 @@ +/** \file + +\section general General + +The SOEM is a library that provides the user application with the means to send +and receive EtherCAT frames. It is up to the application to provide means for: + - Reading and writing process data to be sent/received by SOEM + - Keeping local IO data synchronised with the global IOmap + - Detecting errors reported by SOEM + - Managing errors reported by SOEM + +The following sections show some basic examples on how to get the SOEM up +and running, as well as making use of the process data and checking +for errors. Since all code is local to the application or global +variables, it is possible to tweak and optimize when possible. + +The following example shows how to add a main function that will be +called by startup code. In this example main's only purpose is to +spawn a new task that executes SOEM. + +\code + +int main (void) +{ + rprintp("SOEM (Simple Open EtherCAT Master)\nSimple test\n"); + + task_spawn ("simpletest", simpletest, 9, 8192, NULL); + +\endcode + +\section configuration Configuration +Followed by start of the application we need to set up the NIC to be used as +EtherCAT Ethernet interface. In a simple setup we call ec_init(ifname) and +if SOEM comes with support for cable redundancy we call ec_init_redundant +that will open a second port as backup. You can send NULL as ifname if you +have a dedicated NIC selected in the nicdrv.c. It returns >0 if succeeded. + +\code + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + +\endcode + +SOEM is a light weight ethercat master library used in embedded systems, It +supports only runtime configuration. It requests a BRD (Broad Cast Read) of +address 0, all fully functional slaves in the network will respond to this +request, and therefore we will get a working counter equal to the number of +slaves in the network. ec_config_init also sets up the mailboxes for slaves +that support it. When ec_config_init finishes it will have requested all slaves +to state PRE_OP. All data read and configured are stored in a global array +which acts as a placeholder for key values, consult ec_slave for detailed +information. +\code + /* find and auto-config slaves */ + if ( ec_config_init(FALSE) > 0 ) + { + rprintp("%d slaves found and configured.\n",ec_slavecount); +\endcode + +SOEM has now discovered and configured the network it is connected to. +Now we can verify that all slaves are present as expected. These +definitions could be generated by an external tool in an offline .h file. +The definitions could be replaced by a struct keeping slave number. + +\code + +#define EK1100_1 1 +#define EL4001_1 2 +... +#define EL2622_3 8 +#define EL2622_4 9 +#define NUMBER_OF_SLAVES 9 + +snippet +... + +uint32 network_configuration(void) +{ + /* Do we got expected number of slaves from config */ + if (ec_slavecount < NUMBER_OF_SLAVES) + return 0; + + /* Verify slave by slave that it is correct*/ + if (strcmp(ec_slave[EK1100_1].name,"EK1100")) + return 0; + else if (strcmp(ec_slave[EL4001_1].name,"EL4001")) + return 0; +... + else if (strcmp(ec_slave[EL2622_4].name,"EL2622")) + return 0; + + return 1; +} + +simpletest +... + if (network_configuration()) + ... + else + rprintp("Mismatch of network units!\n"); + + + +\endcode + +We now have the network up and configured. Mailboxes are up for slaves that support +it. Next we will create an IOmap and configure the SyncManager's and +FMMU's to link the EtherCAT master and the slaves. The IO mapping is done +automatically, SOEM strives to keep the logical process image as compact as +possible. It is done by trying to fit Bit oriented slaves together in single +bytes. Below is an example of 8 slaves and how they are ordered. During +mapping SOEM also calculates an expected WKC for the IO mapped together. +That is the primary key to detect errors. + - Outputs are placed together in the beginning of the IOmap + - Inputs follow + + When the mapping is done SOEM requests slaves to enter SAFE_OP. + +\code + +char IOmap[128]; +... + ec_config_map(&IOmap); +... +\endcode + +\image html memory_layout.png "memory layout, mapping between physical and logical" +\image latex memory_layout.png "memory layout, mapping between physical and logical" width=15cm + +To enter state OP we need to send valid data to outputs. The EtherCAT frame +handling is split into ec_send_processdata and ec_receive_processdata. + - ec_send_processdata sends the frame on the NIC and saves the frame on + the stack for receive to fetch. + - ec_receive_processdata(EC_TIMEOUTRET) tries to fetch the frames on the + stack. We send an argument for how long we will try to fetch the frame. + ec_receive_processdata returns the working counter. + +\code + /* send one valid process data to make outputs in slaves happy*/ + ec_send_processdata(); + wkc = ec_receive_processdata(EC_TIMEOUTRET); +... + ec_writestate(0); + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); +\endcode + +- Now we have a system up and running, all slaves are in state operational. + +\section application Application + +IO data is accessed through the IOmap, the ec_slave struct keep pointers +to the start byte in the IO map on slave level together with start bit within +the start byte. This way we can bit mask IO on bit level even though SOEM +has combined slave data to minimize the frame size to be sent. We'll use +slave 8 in the picture above as an example. From a printout from ec_slave we +have the following: + - Slave:8 + - Name:EL2622 + - Output size: 2bits + - Input size: 0bits + - Configured address: 1008 + - Outputs address: 18cf6 + - Inputs address: 0 + - FMMU0 Ls:2 Ll: 1 Lsb:4 Leb:5 Ps:f00 Psb:0 Ty:2 Act:1 + +The Outputs address: 18cf6 is the pointer to slave 8's start byte. The FMMU's +Lsb:4 (LogicalStartBit) = ec_slave.Ostartbit telling us how to mask for the +individual bits in the combined byte. The same goes for byte addressed slaves, +but byte slaves only need the byte start address since they are byte aligned, +the start bit will be 0. + +Some example on how to access different types of data + +Set an output int 16 value when memory alignment needs to be considered, +arguments is: + - slave number in ethercat network + - module index as index internal to the slave in case more than one + channel + - value to write + +\code + +#define EL4001_1 2 +... +void set_output_int16 (uint16 slave_no, uint8 module_index, int16 value) +{ + uint8 *data_ptr; + + data_ptr = ec_slave[slave_no].outputs; + /* Move pointer to correct module index*/ + data_ptr += module_index * 2; + /* Read value byte by byte since all targets can't handle misaligned + * addresses + */ + *data_ptr++ = (value >> 0) & 0xFF; + *data_ptr++ = (value >> 8) & 0xFF; +} +... +set_output_int16(EL4001_1,0,slave_EL4001_1.out1); + +\endcode + +Target can handle non aligned pointers to the IOmap +\code + +typedef struct PACKED +{ + int16 outvalue1; + int16 outvalue2; +} out_EL4132t; + +out_EL4132t *out_EL4132; +... + /* connect struct pointers to slave I/O pointers */ + out_EL4132 = (out_EL4132t*) ec_slave[3].outputs; + out_EL4132->outvalue2 = 0x3FFF; + +... +\endcode + +Identify and manage errors. The key is the Working Counter, CRC errors +and errors local to the slave causing a state change can be detected by loss +of Working Counter since the syncmanagers won't get updated. When returning +Working Counter don't match Expected Working Counter something is wrong, then it +is up to an error handler to act, locate the erroneous slave and decide what action +to perform. The error may not be fatal. Some basic code from simple_test. +\code + +wkc = ec_receive_processdata(EC_TIMEOUTRET); +expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + +if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)) +{ + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > 0) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (!ec_slave[slave].state) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(!ec_slave[slave].state) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); +} +\endcode + + This tutorial is just one way of doing it. + Enjoy and happy coding! + + Andreas Karlsson, rt-labs AB, www.rt-labs.com + */ diff --git a/drvcomment.txt b/drvcomment.txt new file mode 100644 index 0000000..221e89f --- /dev/null +++ b/drvcomment.txt @@ -0,0 +1,2 @@ +For faster irq response through the NIC/NAPI/Socket layer set for TG3 (at eth0) +ethtool -C eth0 rx-usecs 0 rx-frames 1 tx-usecs 0 tx-frames 1 diff --git a/make/app.mk b/make/app.mk new file mode 100644 index 0000000..ac900eb --- /dev/null +++ b/make/app.mk @@ -0,0 +1,58 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: app.mk 452 2013-02-26 21:02:58Z smf.arthur $ +#------------------------------------------------------------------------------ + +OBJDIR = obj/$(ARCH) +LIBS += oshw osal soem + +include $(PRJ_ROOT)/make/rules.mk +include $(PRJ_ROOT)/make/files.mk + +ifeq ($(ARCH),linux) +LIBS += -lpthread -lrt +endif + +SUBDIRS = $(patsubst %/,%,$(dir $(wildcard */Makefile))) + +# Use .PHONY so link step always occurs. This is a simple way +# to avoid computing dependencies on libs +.PHONY: $(APPNAME) +$(APPNAME): $(OBJDIR) $(SUBDIRS) $(OBJDIR_OBJS) $(EXTRA_OBJS) + @echo --- Linking $@ + $(SILENT)$(CC) $(LDFLAGS) $(LD_PATHS) $(OBJDIR)/*.o -o $@ $(LIBS) + +$(OBJDIR): + @test -e $(OBJDIR) || $(MKDIR) $(OBJDIR) + +.PHONY: $(SUBDIRS) +$(SUBDIRS): + @echo --- Entering $(CURDIR)/$@ + @$(MAKE) -C $@ $(MAKECMDGOALS) + @echo --- Leaving $(CURDIR)/$@ + +.PHONY: clean +clean: $(SUBDIRS) + @$(RM) $(OBJDIR)/* + rm -rf obj/ + @$(RM) $(APPNAME) + @$(RM) $(APPNAME).elf + @$(RM) $(APPNAME).map + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPENDS) +endif diff --git a/make/cl_eepromtool.rsp b/make/cl_eepromtool.rsp new file mode 100644 index 0000000..90e9f52 --- /dev/null +++ b/make/cl_eepromtool.rsp @@ -0,0 +1,2 @@ +/c /I "soem" /I "osal" /I "osal\win32" /I "oshw\win32" /I "oshw\win32\wpcap\Include" /ZI /W3 /WX- /Od /Oy- /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"test\win32\eepromtool\obj\\" /Fd"test\win32\simple_test\vc100.pdb" /Gd /TC /analyze- +test\win32\eepromtool\eepromtool.c \ No newline at end of file diff --git a/make/cl_libsoem.rsp b/make/cl_libsoem.rsp new file mode 100644 index 0000000..51688d0 --- /dev/null +++ b/make/cl_libsoem.rsp @@ -0,0 +1,13 @@ +/c /Zi /W3 /WX- /Od /Oy- /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"obj\\" /Fd"obj\vc100.pdb" /Gd /TC /analyze- /Odi /I "oshw\win32\wpcap\include" /I "osal" /I "osal\win32" /I "oshw\win32" /I "soem" +oshw\win32\nicdrv.c +oshw\win32\oshw.c +soem\ecat.c +soem\ethercatbase.c +soem\ethercatcoe.c +soem\ethercatconfig.c +soem\ethercatdc.c +soem\ethercatfoe.c +soem\ethercatmain.c +soem\ethercatprint.c +soem\ethercatsoe.c +osal\win32\osal.c diff --git a/make/cl_simple_test.rsp b/make/cl_simple_test.rsp new file mode 100644 index 0000000..a086de1 --- /dev/null +++ b/make/cl_simple_test.rsp @@ -0,0 +1,2 @@ +/c /I "soem" /I "osal" /I "osal\win32" /I "oshw\win32" /I "oshw\win32\wpcap\Include" /ZI /W3 /WX- /Od /Oy- /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"test\win32\simple_test\obj\\" /Fd"test\win32\simple_test\vc100.pdb" /Gd /TC /analyze- +test\win32\simple_test\simple_test.c \ No newline at end of file diff --git a/make/cl_slaveinfo.rsp b/make/cl_slaveinfo.rsp new file mode 100644 index 0000000..9719749 --- /dev/null +++ b/make/cl_slaveinfo.rsp @@ -0,0 +1,2 @@ +/c /I "soem" /I "osal" /I "osal\win32" /I "oshw\win32" /I "oshw\win32\wpcap\Include" /ZI /W3 /WX- /Od /Oy- /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"test\win32\slaveinfo\obj\\" /Fd"test\win32\slaveinfo\vc100.pdb" /Gd /TC /analyze- +test\win32\slaveinfo\slaveinfo.c \ No newline at end of file diff --git a/make/cl_status_test.rsp b/make/cl_status_test.rsp new file mode 100644 index 0000000..19fb4e3 --- /dev/null +++ b/make/cl_status_test.rsp @@ -0,0 +1,2 @@ +/c /I "soem" /I "osal" /I "osal\win32" /I "oshw\win32" /I "oshw\win32\wpcap\Include" /ZI /W3 /WX- /Od /Oy- /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"test\win32\status_test\obj\\" /Fd"test\win32\status_test\vc100.pdb" /Gd /TC /analyze- +test\win32\status_test\status_test.c diff --git a/make/compilers/arm-eabi-gcc.mk b/make/compilers/arm-eabi-gcc.mk new file mode 100644 index 0000000..865322d --- /dev/null +++ b/make/compilers/arm-eabi-gcc.mk @@ -0,0 +1,34 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: arm-eabi-gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Prefix of the cross-compiler +CROSS_GCC := arm-eabi + +# Common settings +include $(PRJ_ROOT)/make/compilers/gcc.mk + +# Machine settings +-include $(PRJ_ROOT)/make/compilers/$(ARCH).mk + +# Default machine settings +MACHINE ?= -mthumb-interwork -mlittle-endian -mthumb + +# Compiler flags +CFLAGS += $(MACHINE) +LDFLAGS += $(MACHINE) -Wl,--no-wchar-size-warning diff --git a/make/compilers/bfin-elf-gcc.mk b/make/compilers/bfin-elf-gcc.mk new file mode 100644 index 0000000..f067d9a --- /dev/null +++ b/make/compilers/bfin-elf-gcc.mk @@ -0,0 +1,34 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: bfin-elf-gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Prefix of the cross-compiler +CROSS_GCC := bfin-elf + +# Common settings +include $(PRJ_ROOT)/make/compilers/gcc.mk + +# Machine settings +-include $(PRJ_ROOT)/make/compilers/$(ARCH).mk + +# Default machine settings +MACHINE ?= -mcpu=bf537 + +# Compiler flags +CFLAGS += $(MACHINE) +LDFLAGS += $(MACHINE) diff --git a/make/compilers/gcc.mk b/make/compilers/gcc.mk new file mode 100644 index 0000000..ebcbb2a --- /dev/null +++ b/make/compilers/gcc.mk @@ -0,0 +1,64 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2008. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Compiler executables +ifeq ($(ARCH),linux) +CC := $(GCC_PATH)/gcc +AS := $(GCC_PATH)/as +LD := $(GCC_PATH)/ld +AR := $(GCC_PATH)/ar +SIZE := $(GCC_PATH)/size +CPP :=$(CC) -E -xc -P +OBJCOPY := $(GCC_PATH)/objcopy +else +CC := $(GCC_PATH)/bin/$(CROSS_GCC)-gcc +AS := $(GCC_PATH)/bin/$(CROSS_GCC)-as +LD := $(GCC_PATH)/bin/$(CROSS_GCC)-ld +AR := $(GCC_PATH)/bin/$(CROSS_GCC)-ar +SIZE := $(GCC_PATH)/bin/$(CROSS_GCC)-size +CPP :=$(CC) -E -xc -P +OBJCOPY := $(GCC_PATH)/bin/$(CROSS_GCC)-objcopy +LDFLAGS = -nostartfiles -T"$(LD_SCRIPT)" +endif + +# Host executables (TODO: move to host-specific settings) +RM := rm -f +MKDIR := mkdir -p + +# Include paths +CC_INC_PATH = $(GCC_PATH)/$(CROSS_GCC)/include + +# Compiler flags +CFLAGS = -Wall -Wextra -Wno-unused-parameter #-Werror +CFLAGS += -fomit-frame-pointer -fno-strict-aliasing -fshort-wchar +CFLAGS += -B$(GCC_PATH)/libexec/gcc + +# Compiler C++ flags +CPPFLAGS = -fno-rtti -fno-exceptions + +# Linker flags +LDFLAGS += -Wl,-Map=$(APPNAME).map + +# Libraries +LLIBS = $(patsubst %,-l%,$(LIBS)) +LIBS := -Wl,--start-group $(LLIBS) -lc -lm -Wl,--end-group + +# Directories +LIBDIR = "$(PRJ_ROOT)/lib/$(ARCH)" + diff --git a/make/compilers/linux-gcc.mk b/make/compilers/linux-gcc.mk new file mode 100644 index 0000000..cb3d7e9 --- /dev/null +++ b/make/compilers/linux-gcc.mk @@ -0,0 +1,27 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: linux-gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Prefix of the cross-compiler + +# Common settings +include $(PRJ_ROOT)/make/compilers/gcc.mk + +# Compiler flags +CFLAGS += $(MACHINE) +LDFLAGS += $(MACHINE) diff --git a/make/compilers/powerpc-eabi-gcc.mk b/make/compilers/powerpc-eabi-gcc.mk new file mode 100644 index 0000000..0e03971 --- /dev/null +++ b/make/compilers/powerpc-eabi-gcc.mk @@ -0,0 +1,39 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: powerpc-eabi-gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Prefix of the cross-compiler +CROSS_GCC := powerpc-eabi + +# Common settings +include $(PRJ_ROOT)/make/compilers/gcc.mk + +# Machine settings +-include $(PRJ_ROOT)/make/compilers/$(ARCH).mk + +# Default machine settings +# mcpu 750 use an 603,604 specific instuction stfiwx +# this inst is not implemnted OK in QEMU, cause a program expection 7 +# mcpu=powerpc is a generic type used for now +#MACHINE ?= -mbig -mregnames -mcpu=750 -mcall-sysv -meabi +MACHINE ?= -mbig -mregnames -mcpu=powerpc -mcall-sysv -meabi + +# Compiler flags +CFLAGS += $(MACHINE) +LDFLAGS += $(MACHINE) + diff --git a/make/compilers/powerpc-eabispe-gcc.mk b/make/compilers/powerpc-eabispe-gcc.mk new file mode 100644 index 0000000..39c4bba --- /dev/null +++ b/make/compilers/powerpc-eabispe-gcc.mk @@ -0,0 +1,35 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2007. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: powerpc-eabispe-gcc.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +# Prefix of the cross-compiler +CROSS_GCC := powerpc-eabispe + +# Common settings +include $(PRJ_ROOT)/make/compilers/gcc.mk + +# Machine settings +-include $(PRJ_ROOT)/make/compilers/$(ARCH).mk + +# Default machine settings +MACHINE ?= -mcpu=8540 -mregnames -mmultiple -mabi=spe + +# Compiler flags +CFLAGS += $(MACHINE) +LDFLAGS += $(MACHINE) + diff --git a/make/files.mk b/make/files.mk new file mode 100644 index 0000000..10d1c34 --- /dev/null +++ b/make/files.mk @@ -0,0 +1,30 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: files.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +S_SRC ?= $(wildcard *.S) +C_SRC ?= $(wildcard *.c) +CPP_SRC ?= $(wildcard *.cpp) + +S_OBJS := $(patsubst %.S,%.o,$(S_SRC)) +C_OBJS := $(patsubst %.c,%.o,$(C_SRC)) +CPP_OBJS := $(patsubst %.cpp,%.o,$(CPP_SRC)) + +OBJS := $(S_OBJS) $(C_OBJS) $(CPP_OBJS) $(TT_OBJS) +OBJDIR_OBJS = $(patsubst %,$(OBJDIR)/%,$(OBJS)) +DEPENDS := $(patsubst %.o,%.d,$(OBJDIR_OBJS)) diff --git a/make/lib.mk b/make/lib.mk new file mode 100644 index 0000000..c9aa7ce --- /dev/null +++ b/make/lib.mk @@ -0,0 +1,51 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: lib.mk 452 2013-02-26 21:02:58Z smf.arthur $ +#------------------------------------------------------------------------------ + +OBJDIR = ./obj/$(ARCH) + +include $(PRJ_ROOT)/make/rules.mk +include $(PRJ_ROOT)/make/files.mk + +SUBDIRS = $(patsubst %/,%,$(dir $(wildcard */Makefile))) + +all: lib$(LIBNAME).a + +lib$(LIBNAME).a: $(OBJDIR) $(SUBDIRS) $(OBJDIR_OBJS) + @echo --- Create library $@ + @test -e $(LIBDIR) || $(MKDIR) $(LIBDIR) + $(SILENT)$(AR) crus $(LIBDIR)/$@ $(OBJDIR)/*.o + +$(OBJDIR): + @test -e $(OBJDIR) || $(MKDIR) $(OBJDIR) + +.PHONY: $(SUBDIRS) +$(SUBDIRS): + @echo --- Entering $(CURDIR)/$@ + @$(MAKE) -C $@ $(MAKECMDGOALS) + @echo --- Leaving $(CURDIR)/$@ + +.PHONY: clean +clean: $(SUBDIRS) + $(RM) $(OBJDIR)/* + rm -rf ./obj + $(RM) $(LIBDIR)/lib$(LIBNAME).a + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPENDS) +endif diff --git a/make/lib_libsoem.rsp b/make/lib_libsoem.rsp new file mode 100644 index 0000000..cf134f3 --- /dev/null +++ b/make/lib_libsoem.rsp @@ -0,0 +1,13 @@ +/OUT:lib\win32\libsoem.lib +.\obj\nicdrv.obj +.\obj\oshw.obj +.\obj\ecat.obj +.\obj\ethercatbase.obj +.\obj\ethercatcoe.obj +.\obj\ethercatconfig.obj +.\obj\ethercatdc.obj +.\obj\ethercatfoe.obj +.\obj\ethercatmain.obj +.\obj\ethercatprint.obj +.\obj\ethercatsoe.obj +.\obj\osal.obj diff --git a/make/link_eepromtool.rsp b/make/link_eepromtool.rsp new file mode 100644 index 0000000..3391776 --- /dev/null +++ b/make/link_eepromtool.rsp @@ -0,0 +1,3 @@ +/OUT:"test\win32\eepromtool\eepromtool.exe" /LIBPATH:"oshw\win32\wpcap\Lib" /LIBPATH:"lib\win32" Ws2_32.lib Winmm.lib Packet.lib wpcap.lib libsoem.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEBUG /PDB:"test\win32\eepromtool\eepromtool.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 +"test\win32\eepromtool\obj\eepromtool.obj" + diff --git a/make/link_simple_test.rsp b/make/link_simple_test.rsp new file mode 100644 index 0000000..d192f3e --- /dev/null +++ b/make/link_simple_test.rsp @@ -0,0 +1,3 @@ +/OUT:"test\win32\simple_test\simple_test.exe" /LIBPATH:"oshw\win32\wpcap\Lib" /LIBPATH:"lib\win32" Ws2_32.lib Winmm.lib Packet.lib wpcap.lib libsoem.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEBUG /PDB:"test\win32\simple_test\simple_test.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 +"test\win32\simple_test\obj\simple_test.obj" + diff --git a/make/link_slaveinfo.rsp b/make/link_slaveinfo.rsp new file mode 100644 index 0000000..5ef5c70 --- /dev/null +++ b/make/link_slaveinfo.rsp @@ -0,0 +1,3 @@ +/OUT:"test\win32\slaveinfo\slaveinfo.exe" /LIBPATH:"oshw\win32\wpcap\Lib" /LIBPATH:"lib\win32" Ws2_32.lib Winmm.lib Packet.lib wpcap.lib libsoem.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEBUG /PDB:"test\win32\slaveinfo\slaveinfo.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 +"test\win32\slaveinfo\obj\slaveinfo.obj" + diff --git a/make/link_status_test.rsp b/make/link_status_test.rsp new file mode 100644 index 0000000..ee21262 --- /dev/null +++ b/make/link_status_test.rsp @@ -0,0 +1,3 @@ +/OUT:"test\win32\status_test\status_test.exe" /LIBPATH:"oshw\win32\wpcap\Lib" /LIBPATH:"lib\win32" Ws2_32.lib Winmm.lib Packet.lib wpcap.lib libsoem.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEBUG /PDB:"test\win32\status_test\status_test.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 +"test\win32\status_test\obj\status_test.obj" + diff --git a/make/rules.mk b/make/rules.mk new file mode 100644 index 0000000..88f0cee --- /dev/null +++ b/make/rules.mk @@ -0,0 +1,68 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: rules.mk 414 2012-12-03 10:48:42Z rtlaka $ +#------------------------------------------------------------------------------ + +# Compiler specific settings +include $(PRJ_ROOT)/make/compilers/$(CROSS_GCC)-gcc.mk + +# Include paths +DEFAULT_INC_PATH += $(PRJ_ROOT)/osal +DEFAULT_INC_PATH += $(PRJ_ROOT)/osal/$(BSP) +DEFAULT_INC_PATH += $(PRJ_ROOT)/oshw/$(BSP) +DEFAULT_INC_PATH += $(PRJ_ROOT)/soem + +INC_PATH = $(DEFAULT_INC_PATH) $(CC_INC_PATH) $(EXTRA_INCLUDES) +INC_PATHS = $(patsubst %,-I"%",$(INC_PATH)) + +# Library paths +LD_PATH += $(LIBDIR) +LD_PATH += $(EXTRA_LD_PATHS) + +LD_PATHS = $(patsubst %,-L%,$(LD_PATH)) + +# Dependency generation +CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" + +# Common settings +CFLAGS += -g -O0 -ffunction-sections +LDFLAGS += -Wl,--gc-sections + +# Command-line overrides +CFLAGS += $(EXTRA_CFLAGS) +CPPFLAGS += $(EXTRA_CPPFLAGS) +LDFLAGS += $(EXTRA_LDFLAGS) + + +SILENT=@ + +# Rules + +.SUFFIXES: + +$(OBJDIR)/%.o: %.S + @echo --- Assembling $< + $(SILENT)$(CC) $(CFLAGS) $(INC_PATHS) -c $< -o $@ + +$(OBJDIR)/%.o: %.c + @echo --- Compiling $< + $(SILENT)$(CC) $(CFLAGS) $(INC_PATHS) -c $< -o $@ + +$(OBJDIR)/%.o: %.cpp + @echo --- Compiling $< + $(SILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(INC_PATHS) -c $< -o $@ + diff --git a/make/subdir.mk b/make/subdir.mk new file mode 100644 index 0000000..bd56aaa --- /dev/null +++ b/make/subdir.mk @@ -0,0 +1,54 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: subdir.mk 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +OBJDIR ?= ../obj/$(ARCH) + +include $(PRJ_ROOT)/make/rules.mk +include $(PRJ_ROOT)/make/files.mk + +SUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile))) +LATEDIRS ?= $(patsubst %/,%,$(dir $(wildcard */.late))) +EARLYDIRS ?= $(filter-out $(LATEDIRS), $(SUBDIRS)) +ALLDIRS = $(EARLYDIRS) $(LATEDIRS) + +ifneq ($(strip $(OBJS)),) +all: $(OBJDIR) $(ALLDIRS) $(OBJDIR_OBJS) +else +all: $(ALLDIRS) $(OBJDIR_OBJS) +endif + +$(LATEDIRS): $(EARLYDIRS) + +$(OBJDIR): + @test -e $(OBJDIR) || $(MKDIR) $(OBJDIR) + +.PHONY: $(ALLDIRS) +$(ALLDIRS): + @echo --- Entering $(CURDIR)/$@ + @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) + @echo --- Leaving $(CURDIR)/$@ + +.PHONY: clean +clean: $(ALLDIRS) + $(RM) $(OBJDIR)/* + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPENDS) +endif + diff --git a/make_libsoem_lib.bat b/make_libsoem_lib.bat new file mode 100644 index 0000000..edb2691 --- /dev/null +++ b/make_libsoem_lib.bat @@ -0,0 +1,40 @@ +REM @echo off + +rem give path as arg +if "%~1"=="" goto exit_err_arg +if NOT EXIST %1 goto exit_err_arg + +rem call cvarsall to load the env +call "%~1\vcvarsall.bat" %2 + +rem cd to folder containing .bat file +cd /d "%0\.." + +rem compile and build library +if EXIST obj goto skip_obj +MKDIR obj +:skip_obj +cl.exe @make\cl_libsoem.rsp /errorReport:prompt +if EXIST lib\win32 goto skip_lib +MKDIR lib\win32 +:skip_lib +lib.exe @make\lib_libsoem.rsp /nologo /errorReport:prompt + +echo make done +goto :eof + +:exit_err_arg +echo supply path to MSVC folder that contain vcvarsall.bat as ARG to batch file and ARCH +echo "Ex. make_libsoem_lib.bat "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC" x86 +goto :eof + +:usage +echo Error in script usage. The correct usage is: +echo %0 [option] +echo where [option] is: x86 ^| ia64 ^| amd64 ^| x86_amd64 ^| x86_ia64 +echo: +echo For example: +echo %0 x86_ia64 +goto :eof + + diff --git a/make_status_test_win32.bat b/make_status_test_win32.bat new file mode 100644 index 0000000..a0b5ef3 --- /dev/null +++ b/make_status_test_win32.bat @@ -0,0 +1,10 @@ +@echo off + +if EXIST test\win32\status_test\obj goto skip_obj2 +MKDIR test\win32\status_test\obj +:skip_obj2 +cl.exe @make\cl_status_test.rsp /errorReport:prompt +link.exe @make\link_status_test.rsp /nologo /errorReport:prompt + +echo make done +goto :eof diff --git a/make_test_win32.bat b/make_test_win32.bat new file mode 100644 index 0000000..2cd4bfb --- /dev/null +++ b/make_test_win32.bat @@ -0,0 +1,35 @@ +REM @echo off + +rem give path as arg +if "%~1"=="" goto exit_err_arg +if NOT EXIST %1 goto exit_err_arg + +rem call cvarsall to load the env +call "%~1\vcvarsall.bat" %2 + +rem cd to folder containing .bat file +cd /d "%0\.." + +rem compile and build library +if EXIST test\win32\slaveinfo\obj goto skip_obj +MKDIR test\win32\slaveinfo\obj +:skip_obj +cl.exe @make\cl_slaveinfo.rsp /errorReport:prompt +link.exe @make\link_slaveinfo.rsp /nologo /errorReport:prompt + +echo make done +goto :eof + +:exit_err_arg +echo supply path to MSVC folder that contain vcvarsall.bat as ARG to batch file and ARCH +echo "Ex. make_libsoem_lib.bat "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC" x86 +goto :eof + +:usage +echo Error in script usage. The correct usage is: +echo %0 [option] +echo where [option] is: x86 ^| ia64 ^| amd64 ^| x86_amd64 ^| x86_ia64 +echo: +echo For example: +echo %0 x86_ia64 +goto :eof \ No newline at end of file diff --git a/make_test_win32_all.bat b/make_test_win32_all.bat new file mode 100644 index 0000000..c4adb79 --- /dev/null +++ b/make_test_win32_all.bat @@ -0,0 +1,39 @@ +@echo off + +rem compile and build library +if EXIST obj goto skip_obj +MKDIR obj +:skip_obj +cl.exe @make\cl_libsoem.rsp /errorReport:prompt +if EXIST lib\win32 goto skip_lib +MKDIR lib\win32 +:skip_lib +lib.exe @make\lib_libsoem.rsp /nologo /errorReport:prompt + +rem compile and build test applications +if EXIST test\win32\slaveinfo\obj goto skip_obj +MKDIR test\win32\slaveinfo\obj +:skip_obj +cl.exe @make\cl_slaveinfo.rsp /errorReport:prompt +link.exe @make\link_slaveinfo.rsp /nologo /errorReport:prompt + +if EXIST test\win32\simple_test\obj goto skip_obj2 +MKDIR test\win32\simple_test\obj +:skip_obj2 +cl.exe @make\cl_simple_test.rsp /errorReport:prompt +link.exe @make\link_simple_test.rsp /nologo /errorReport:prompt + +if EXIST test\win32\status_test\obj goto skip_obj2 +MKDIR test\win32\status_test\obj +:skip_obj2 +cl.exe @make\cl_status_test.rsp /errorReport:prompt +link.exe @make\link_status_test.rsp /nologo /errorReport:prompt + +if EXIST test\win32\eepromtool\obj goto skip_obj3 +MKDIR test\win32\eepromtool\obj +:skip_obj3 +cl.exe @make\cl_eepromtool.rsp /errorReport:prompt +link.exe @make\link_eepromtool.rsp /nologo /errorReport:prompt + +echo make done +goto :eof diff --git a/osal/Makefile b/osal/Makefile new file mode 100644 index 0000000..9098eb9 --- /dev/null +++ b/osal/Makefile @@ -0,0 +1,23 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 175 2012-06-21 07:14:12Z rtlaka $ +#------------------------------------------------------------------------------ + +SUBDIRS = $(BSP) +include $(PRJ_ROOT)/make/subdir.mk + + diff --git a/osal/linux/Makefile b/osal/linux/Makefile new file mode 100644 index 0000000..de930d3 --- /dev/null +++ b/osal/linux/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = osal +include $(PRJ_ROOT)/make/lib.mk diff --git a/osal/linux/osal.c b/osal/linux/osal.c new file mode 100644 index 0000000..b9ec1dc --- /dev/null +++ b/osal/linux/osal.c @@ -0,0 +1,157 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal.c 464 2013-03-13 20:40:25Z smf.arthur $ + *------------------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include + +#define USECS_PER_SEC 1000000 + +int osal_usleep (uint32 usec) +{ + struct timespec ts; + ts.tv_sec = usec / USECS_PER_SEC; + ts.tv_nsec = (usec % USECS_PER_SEC) * 1000; + /* usleep is depricated, use nanosleep instead */ + return nanosleep(&ts, NULL); +} + +int osal_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + struct timespec ts; + int return_value; + + /* Use clock_gettime to prevent possible live-lock. + * Gettimeofday uses CLOCK_REALTIME that can get NTP timeadjust. + * If this function preempts timeadjust and it uses vpage it live-locks. + * Also when using XENOMAI, only clock_gettime is RT safe */ + return_value = clock_gettime(CLOCK_MONOTONIC, &ts), 0; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + return return_value; +} + +ec_timet osal_current_time(void) +{ + struct timeval current_time; + ec_timet return_value; + + osal_gettimeofday(¤t_time, 0); + return_value.sec = current_time.tv_sec; + return_value.usec = current_time.tv_usec; + return return_value; +} + +void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff) +{ + diff->sec = end->sec - start->sec; + diff->usec = end->usec - start->usec; + if (diff->usec < 0) { + --diff->sec; + diff->usec += 1000000; + } +} + +void osal_timer_start(osal_timert * self, uint32 timeout_usec) +{ + struct timeval start_time; + struct timeval timeout; + struct timeval stop_time; + + osal_gettimeofday(&start_time, 0); + timeout.tv_sec = timeout_usec / USECS_PER_SEC; + timeout.tv_usec = timeout_usec % USECS_PER_SEC; + timeradd(&start_time, &timeout, &stop_time); + + self->stop_time.sec = stop_time.tv_sec; + self->stop_time.usec = stop_time.tv_usec; +} + +boolean osal_timer_is_expired (osal_timert * self) +{ + struct timeval current_time; + struct timeval stop_time; + int is_not_yet_expired; + + osal_gettimeofday(¤t_time, 0); + stop_time.tv_sec = self->stop_time.sec; + stop_time.tv_usec = self->stop_time.usec; + is_not_yet_expired = timercmp(¤t_time, &stop_time, <); + + return is_not_yet_expired == FALSE; +} + +void *osal_malloc(size_t size) +{ + return malloc(size); +} + +void osal_free(void *ptr) +{ + free(ptr); +} + +int osal_thread_create(void *thandle, int stacksize, void *func, void *param) +{ + int ret; + pthread_attr_t attr; + pthread_t *threadp; + + threadp = thandle; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, stacksize); + ret = pthread_create(threadp, &attr, func, param); + if(ret < 0) + { + return 0; + } + return 1; +} + +int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param) +{ + int ret; + pthread_attr_t attr; + struct sched_param schparam; + pthread_t *threadp; + + threadp = thandle; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, stacksize); + ret = pthread_create(threadp, &attr, func, param); + pthread_attr_destroy(&attr); + if(ret < 0) + { + return 0; + } + memset(&schparam, 0, sizeof(schparam)); + schparam.sched_priority = 40; + ret = pthread_setschedparam(*threadp, SCHED_FIFO, &schparam); + if(ret < 0) + { + return 0; + } + + return 1; +} + diff --git a/osal/linux/osal_defs.h b/osal/linux/osal_defs.h new file mode 100644 index 0000000..40fe2a4 --- /dev/null +++ b/osal/linux/osal_defs.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal_defs.h 472 2013-04-08 11:39:51Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#ifndef _osal_defs_ +#define _osal_defs_ + +#ifndef PACKED +#define PACKED_BEGIN +#define PACKED __attribute__((__packed__)) +#define PACKED_END +#endif + +#include +#define OSAL_THREAD_HANDLE pthread_t * +#define OSAL_THREAD_FUNC void +#define OSAL_THREAD_FUNC_RT void + +#endif diff --git a/osal/osal.h b/osal/osal.h new file mode 100644 index 0000000..c6eca5e --- /dev/null +++ b/osal/osal.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + */ + +#ifndef _osal_ +#define _osal_ + +#include +#include + +/* General types */ +typedef uint8_t boolean; +#define TRUE 1 +#define FALSE 0 +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; +typedef float float32; +typedef double float64; + +typedef struct +{ + uint32 sec; /*< Seconds elapsed since the Epoch (Jan 1, 1970) */ + uint32 usec; /*< Microseconds elapsed since last second boundary */ +} ec_timet; + +typedef struct osal_timer +{ + ec_timet stop_time; +} osal_timert; + +void osal_timer_start(osal_timert * self, uint32 timeout_usec); +boolean osal_timer_is_expired(osal_timert * self); +int osal_usleep(uint32 usec); +ec_timet osal_current_time(void); +void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff); +int osal_thread_create(void *thandle, int stacksize, void *func, void *param); +int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param); + +#endif diff --git a/osal/rtk/Makefile b/osal/rtk/Makefile new file mode 100644 index 0000000..a620dc2 --- /dev/null +++ b/osal/rtk/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 411 2012-12-02 20:16:39Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = osal +include $(PRJ_ROOT)/make/lib.mk diff --git a/osal/rtk/osal.c b/osal/rtk/osal.c new file mode 100644 index 0000000..488ce74 --- /dev/null +++ b/osal/rtk/osal.c @@ -0,0 +1,131 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal.c 452 2013-02-26 21:02:58Z smf.arthur $ + *------------------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +#define timercmp(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_usec CMP (b)->tv_usec) : \ + ((a)->tv_sec CMP (b)->tv_sec)) +#define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) + +#define USECS_PER_SEC 1000000 +#define USECS_PER_TICK (USECS_PER_SEC / CFG_TICKS_PER_SECOND) + + +/* Workaround for rt-labs defect 776. + * Default implementation of udelay() didn't work correctly when tick was + * shorter than one millisecond. + */ +void udelay (uint32_t us) +{ + tick_t ticks = (us / USECS_PER_TICK) + 1; + task_delay (ticks); +} + +int gettimeofday(struct timeval *tp, void *tzp) +{ + tick_t tick = tick_get(); + tick_t ticks_left; + + ASSERT (tp != NULL); + + tp->tv_sec = tick / CFG_TICKS_PER_SECOND; + + ticks_left = tick % CFG_TICKS_PER_SECOND; + tp->tv_usec = ticks_left * USECS_PER_TICK; + ASSERT (tp->tv_usec < USECS_PER_SEC); + + return 0; +} + +int osal_usleep (uint32 usec) +{ + udelay(usec); + return 0; +} + +int osal_gettimeofday(struct timeval *tv, struct timezone *tz) +{ + return gettimeofday(tv, tz); +} + +ec_timet osal_current_time (void) +{ + struct timeval current_time; + ec_timet return_value; + + gettimeofday (¤t_time, 0); + return_value.sec = current_time.tv_sec; + return_value.usec = current_time.tv_usec; + return return_value; +} + +void osal_timer_start (osal_timert * self, uint32 timeout_usec) +{ + struct timeval start_time; + struct timeval timeout; + struct timeval stop_time; + + gettimeofday (&start_time, 0); + timeout.tv_sec = timeout_usec / USECS_PER_SEC; + timeout.tv_usec = timeout_usec % USECS_PER_SEC; + timeradd (&start_time, &timeout, &stop_time); + + self->stop_time.sec = stop_time.tv_sec; + self->stop_time.usec = stop_time.tv_usec; +} + +boolean osal_timer_is_expired (osal_timert * self) +{ + struct timeval current_time; + struct timeval stop_time; + int is_not_yet_expired; + + gettimeofday (¤t_time, 0); + stop_time.tv_sec = self->stop_time.sec; + stop_time.tv_usec = self->stop_time.usec; + is_not_yet_expired = timercmp (¤t_time, &stop_time, <); + + return is_not_yet_expired == false; +} + diff --git a/osal/rtk/osal_defs.h b/osal/rtk/osal_defs.h new file mode 100644 index 0000000..c8efe5f --- /dev/null +++ b/osal/rtk/osal_defs.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal_defs.h 472 2013-04-08 11:39:51Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#ifndef _osal_defs_ +#define _osal_defs_ + +#ifndef PACKED +#define PACKED_BEGIN +#define PACKED __attribute__((__packed__)) +#define PACKED_END +#endif + +#define OSAL_THREAD_HANDLE task_t * +#define OSAL_THREAD_FUNC void +#define OSAL_THREAD_FUNC_RT void + +#endif diff --git a/osal/win32/Makefile b/osal/win32/Makefile new file mode 100644 index 0000000..e29df23 --- /dev/null +++ b/osal/win32/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = osal +include $(PRJ_ROOT)/make/lib.mk diff --git a/osal/win32/inttypes.h b/osal/win32/inttypes.h new file mode 100644 index 0000000..4b3828a --- /dev/null +++ b/osal/win32/inttypes.h @@ -0,0 +1,305 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// 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 the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff --git a/osal/win32/osal.c b/osal/win32/osal.c new file mode 100644 index 0000000..06cc466 --- /dev/null +++ b/osal/win32/osal.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal.c 464 2013-03-13 20:40:25Z smf.arthur $ + *------------------------------------------------------------------------------ + */ + +#include +#include +#include "osal_win32.h" + +static int64_t sysfrequency; +static double qpc2usec; + +#define USECS_PER_SEC 1000000 + +int osal_gettimeofday (struct timeval *tv, struct timezone *tz) +{ + int64_t wintime, usecs; + if(!sysfrequency) + { + timeBeginPeriod(1); + QueryPerformanceFrequency((LARGE_INTEGER *)&sysfrequency); + qpc2usec = 1000000.0 / sysfrequency; + } + QueryPerformanceCounter((LARGE_INTEGER *)&wintime); + usecs = (int64_t)((double)wintime * qpc2usec); + tv->tv_sec = (long)(usecs / 1000000); + tv->tv_usec = (long)(usecs - (tv->tv_sec * 1000000)); + + return 1; +} + +ec_timet osal_current_time (void) +{ + struct timeval current_time; + ec_timet return_value; + + osal_gettimeofday (¤t_time, 0); + return_value.sec = current_time.tv_sec; + return_value.usec = current_time.tv_usec; + return return_value; +} + +void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff) +{ + diff->sec = end->sec - start->sec; + diff->usec = end->usec - start->usec; + if (diff->usec < 0) { + --diff->sec; + diff->usec += 1000000; + } +} + +void osal_timer_start (osal_timert *self, uint32 timeout_usec) +{ + struct timeval start_time; + struct timeval timeout; + struct timeval stop_time; + + osal_gettimeofday (&start_time, 0); + timeout.tv_sec = timeout_usec / USECS_PER_SEC; + timeout.tv_usec = timeout_usec % USECS_PER_SEC; + timeradd (&start_time, &timeout, &stop_time); + + self->stop_time.sec = stop_time.tv_sec; + self->stop_time.usec = stop_time.tv_usec; +} + +boolean osal_timer_is_expired (osal_timert *self) +{ + struct timeval current_time; + struct timeval stop_time; + int is_not_yet_expired; + + osal_gettimeofday (¤t_time, 0); + stop_time.tv_sec = self->stop_time.sec; + stop_time.tv_usec = self->stop_time.usec; + is_not_yet_expired = timercmp (¤t_time, &stop_time, <); + + return is_not_yet_expired == FALSE; +} + +int osal_usleep(uint32 usec) +{ + osal_timert qtime; + osal_timer_start(&qtime, usec); + if(usec >= 1000) + { + SleepEx(usec / 1000, FALSE); + } + while(!osal_timer_is_expired(&qtime)); + return 1; +} + +void *osal_malloc(size_t size) +{ + return malloc(size); +} + +void osal_free(void *ptr) +{ + free(ptr); +} + +int osal_thread_create(void **thandle, int stacksize, void *func, void *param) +{ + *thandle = CreateThread(NULL, stacksize, func, param, 0, NULL); + if(!thandle) + { + return 0; + } + return 1; +} + +int osal_thread_create_rt(void **thandle, int stacksize, void *func, void *param) +{ + int ret; + ret = osal_thread_create(thandle, stacksize, func, param); + if (ret) + { + ret = SetThreadPriority(*thandle, THREAD_PRIORITY_TIME_CRITICAL); + } + return ret; +} + diff --git a/osal/win32/osal_defs.h b/osal/win32/osal_defs.h new file mode 100644 index 0000000..ec125b0 --- /dev/null +++ b/osal/win32/osal_defs.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal_defs.h 472 2013-04-08 11:39:51Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#ifndef _osal_defs_ +#define _osal_defs_ + +#ifndef PACKED +#define PACKED_BEGIN __pragma(pack(push, 1)) +#define PACKED +#define PACKED_END __pragma(pack(pop)) +#endif + +#define OSAL_THREAD_HANDLE HANDLE +#define OSAL_THREAD_FUNC int WINAPI +#define OSAL_THREAD_FUNC_RT void + +#endif diff --git a/osal/win32/osal_win32.h b/osal/win32/osal_win32.h new file mode 100644 index 0000000..334d2f7 --- /dev/null +++ b/osal/win32/osal_win32.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: osal_win32.h 414 2012-12-03 10:48:42Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#ifndef _osal_win32_ +#define _osal_win32_ + +/* Convenience macros for operations on timevals. + NOTE: `timercmp' does not work for >= or <=. */ +# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +# define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +# define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) + +int osal_gettimeofday (struct timeval *tv, struct timezone *tz); + +#endif diff --git a/osal/win32/stdint.h b/osal/win32/stdint.h new file mode 100644 index 0000000..d02608a --- /dev/null +++ b/osal/win32/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// 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 the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/oshw/Makefile b/oshw/Makefile new file mode 100644 index 0000000..6cf8eee --- /dev/null +++ b/oshw/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 175 2012-06-21 07:14:12Z rtlaka $ +#------------------------------------------------------------------------------ + +SUBDIRS = $(BSP) +include $(PRJ_ROOT)/make/subdir.mk diff --git a/oshw/linux/Makefile b/oshw/linux/Makefile new file mode 100644 index 0000000..06e786b --- /dev/null +++ b/oshw/linux/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = oshw +include $(PRJ_ROOT)/make/lib.mk diff --git a/oshw/linux/nicdrv.c b/oshw/linux/nicdrv.c new file mode 100644 index 0000000..795c5d4 --- /dev/null +++ b/oshw/linux/nicdrv.c @@ -0,0 +1,680 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * EtherCAT RAW socket driver. + * + * Low level interface functions to send and receive EtherCAT packets. + * EtherCAT has the property that packets are only send by the master, + * and the send packets allways return in the receive buffer. + * There can be multiple packets "on the wire" before they return. + * To combine the received packets with the original send packets a buffer + * system is installed. The identifier is put in the index item of the + * EtherCAT header. The index is stored and compared when a frame is recieved. + * If there is a match the packet can be combined with the transmit packet + * and returned to the higher level function. + * + * The socket layer can exhibit a reversal in the packet order (rare). + * If the Tx order is A-B-C the return order could be A-C-B. The indexed buffer + * will reorder the packets automatically. + * + * The "redundant" option will configure two sockets and two NIC interfaces. + * Slaves are connected to both interfaces, one on the IN port and one on the + * OUT port. Packets are send via both interfaces. Any one of the connections + * (also an interconnect) can be removed and the slaves are still serviced with + * packets. The software layer will detect the possible failure modes and + * compensate. If needed the packets from interface A are resend through interface B. + * This layer if fully transparent for the higher layers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oshw.h" +#include "osal.h" + +/** Redundancy modes */ +enum +{ + /** No redundancy, single NIC mode */ + ECT_RED_NONE, + /** Double redundant NIC connecetion */ + ECT_RED_DOUBLE +}; + + +/** Primary source MAC address used for EtherCAT. + * This address is not the MAC address used from the NIC. + * EtherCAT does not care about MAC addressing, but it is used here to + * differentiate the route the packet traverses through the EtherCAT + * segment. This is needed to find out the packet flow in redundant + * configurations. */ +const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 }; +/** Secondary source MAC address used for EtherCAT. */ +const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 }; + +/** second MAC word is used for identification */ +#define RX_PRIM priMAC[1] +/** second MAC word is used for identification */ +#define RX_SEC secMAC[1] + +static void ecx_clear_rxbufstat(int *rxbufstat) +{ + int i; + for(i = 0; i < EC_MAXBUF; i++) + { + rxbufstat[i] = EC_BUF_EMPTY; + } +} + +/** Basic setup to connect NIC to socket. + * @param[in] port = port context struct + * @param[in] ifname = Name of NIC device, f.e. "eth0" + * @param[in] secondary = if >0 then use secondary stack instead of primary + * @return >0 if succeeded + */ +int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary) +{ + int i; + int r, rval, ifindex; + struct timeval timeout; + struct ifreq ifr; + struct sockaddr_ll sll; + int *psock; + + rval = 0; + if (secondary) + { + /* secondary port stuct available? */ + if (port->redport) + { + /* when using secondary socket it is automatically a redundant setup */ + psock = &(port->redport->sockhandle); + *psock = -1; + port->redstate = ECT_RED_DOUBLE; + port->redport->stack.sock = &(port->redport->sockhandle); + port->redport->stack.txbuf = &(port->txbuf); + port->redport->stack.txbuflength = &(port->txbuflength); + port->redport->stack.tempbuf = &(port->redport->tempinbuf); + port->redport->stack.rxbuf = &(port->redport->rxbuf); + port->redport->stack.rxbufstat = &(port->redport->rxbufstat); + port->redport->stack.rxsa = &(port->redport->rxsa); + ecx_clear_rxbufstat(&(port->redport->rxbufstat[0])); + } + else + { + /* fail */ + return 0; + } + } + else + { + pthread_mutex_init(&(port->getindex_mutex), NULL); + pthread_mutex_init(&(port->tx_mutex) , NULL); + pthread_mutex_init(&(port->rx_mutex) , NULL); + port->sockhandle = -1; + port->lastidx = 0; + port->redstate = ECT_RED_NONE; + port->stack.sock = &(port->sockhandle); + port->stack.txbuf = &(port->txbuf); + port->stack.txbuflength = &(port->txbuflength); + port->stack.tempbuf = &(port->tempinbuf); + port->stack.rxbuf = &(port->rxbuf); + port->stack.rxbufstat = &(port->rxbufstat); + port->stack.rxsa = &(port->rxsa); + ecx_clear_rxbufstat(&(port->rxbufstat[0])); + psock = &(port->sockhandle); + } + /* we use RAW packet socket, with packet type ETH_P_ECAT */ + *psock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT)); + + timeout.tv_sec = 0; + timeout.tv_usec = 1; + r = setsockopt(*psock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + r = setsockopt(*psock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + i = 1; + r = setsockopt(*psock, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)); + /* connect socket to NIC by name */ + strcpy(ifr.ifr_name, ifname); + r = ioctl(*psock, SIOCGIFINDEX, &ifr); + ifindex = ifr.ifr_ifindex; + strcpy(ifr.ifr_name, ifname); + ifr.ifr_flags = 0; + /* reset flags of NIC interface */ + r = ioctl(*psock, SIOCGIFFLAGS, &ifr); + /* set flags of NIC interface, here promiscuous and broadcast */ + ifr.ifr_flags = ifr.ifr_flags | IFF_PROMISC | IFF_BROADCAST; + r = ioctl(*psock, SIOCGIFFLAGS, &ifr); + /* bind socket to protocol, in this case RAW EtherCAT */ + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifindex; + sll.sll_protocol = htons(ETH_P_ECAT); + r = bind(*psock, (struct sockaddr *)&sll, sizeof(sll)); + /* setup ethernet headers in tx buffers so we don't have to repeat it */ + for (i = 0; i < EC_MAXBUF; i++) + { + ec_setupheader(&(port->txbuf[i])); + port->rxbufstat[i] = EC_BUF_EMPTY; + } + ec_setupheader(&(port->txbuf2)); + if (r == 0) rval = 1; + + return rval; +} + +/** Close sockets used + * @param[in] port = port context struct + * @return 0 + */ +int ecx_closenic(ecx_portt *port) +{ + if (port->sockhandle >= 0) + close(port->sockhandle); + if ((port->redport) && (port->redport->sockhandle >= 0)) + close(port->redport->sockhandle); + + return 0; +} + +/** Fill buffer with ethernet header structure. + * Destination MAC is allways broadcast. + * Ethertype is allways ETH_P_ECAT. + * @param[out] p = buffer + */ +void ec_setupheader(void *p) +{ + ec_etherheadert *bp; + bp = p; + bp->da0 = htons(0xffff); + bp->da1 = htons(0xffff); + bp->da2 = htons(0xffff); + bp->sa0 = htons(priMAC[0]); + bp->sa1 = htons(priMAC[1]); + bp->sa2 = htons(priMAC[2]); + bp->etype = htons(ETH_P_ECAT); +} + +/** Get new frame identifier index and allocate corresponding rx buffer. + * @param[in] port = port context struct + * @return new index. + */ +int ecx_getindex(ecx_portt *port) +{ + int idx; + int cnt; + + pthread_mutex_lock( &(port->getindex_mutex) ); + + idx = port->lastidx + 1; + /* index can't be larger than buffer array */ + if (idx >= EC_MAXBUF) + { + idx = 0; + } + cnt = 0; + /* try to find unused index */ + while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF)) + { + idx++; + cnt++; + if (idx >= EC_MAXBUF) + { + idx = 0; + } + } + port->rxbufstat[idx] = EC_BUF_ALLOC; + if (port->redstate != ECT_RED_NONE) + port->redport->rxbufstat[idx] = EC_BUF_ALLOC; + port->lastidx = idx; + + pthread_mutex_unlock( &(port->getindex_mutex) ); + + return idx; +} + +/** Set rx buffer status. + * @param[in] port = port context struct + * @param[in] idx = index in buffer array + * @param[in] bufstat = status to set + */ +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat) +{ + port->rxbufstat[idx] = bufstat; + if (port->redstate != ECT_RED_NONE) + port->redport->rxbufstat[idx] = bufstat; +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @param[in] stacknumber = 0=Primary 1=Secondary stack + * @return socket send result + */ +int ecx_outframe(ecx_portt *port, int idx, int stacknumber) +{ + int lp, rval; + ec_stackT *stack; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = (*stack->txbuflength)[idx]; + rval = send(*stack->sock, (*stack->txbuf)[idx], lp, 0); + (*stack->rxbufstat)[idx] = EC_BUF_TX; + + return rval; +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @return socket send result + */ +int ecx_outframe_red(ecx_portt *port, int idx) +{ + ec_comt *datagramP; + ec_etherheadert *ehp; + int rval; + + ehp = (ec_etherheadert *)&(port->txbuf[idx]); + /* rewrite MAC source address 1 to primary */ + ehp->sa1 = htons(priMAC[1]); + /* transmit over primary socket*/ + rval = ecx_outframe(port, idx, 0); + if (port->redstate != ECT_RED_NONE) + { + pthread_mutex_lock( &(port->tx_mutex) ); + ehp = (ec_etherheadert *)&(port->txbuf2); + /* use dummy frame for secondary socket transmit (BRD) */ + datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]); + /* write index to frame */ + datagramP->index = idx; + /* rewrite MAC source address 1 to secondary */ + ehp->sa1 = htons(secMAC[1]); + /* transmit over secondary socket */ + send(port->redport->sockhandle, &(port->txbuf2), port->txbuflength2 , 0); + pthread_mutex_unlock( &(port->tx_mutex) ); + port->redport->rxbufstat[idx] = EC_BUF_TX; + } + + return rval; +} + +/** Non blocking read of socket. Put frame in temporary buffer. + * @param[in] port = port context struct + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return >0 if frame is available and read + */ +static int ecx_recvpkt(ecx_portt *port, int stacknumber) +{ + int lp, bytesrx; + ec_stackT *stack; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = sizeof(port->tempinbuf); + bytesrx = recv(*stack->sock, (*stack->tempbuf), lp, 0); + port->tempinbufs = bytesrx; + + return (bytesrx > 0); +} + +/** Non blocking receive frame function. Uses RX buffer and index to combine + * read frame with transmitted frame. To compensate for received frames that + * are out-of-order all frames are stored in their respective indexed buffer. + * If a frame was placed in the buffer previously, the function retreives it + * from that buffer index without calling ec_recvpkt. If the requested index + * is not already in the buffer it calls ec_recvpkt to fetch it. There are + * three options now, 1 no frame read, so exit. 2 frame read but other + * than requested index, store in buffer and exit. 3 frame read with matching + * index, store in buffer, set completed flag in buffer status and exit. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME or EC_OTHERFRAME. + */ +int ecx_inframe(ecx_portt *port, int idx, int stacknumber) +{ + uint16 l; + int rval; + int idxf; + ec_etherheadert *ehp; + ec_comt *ecp; + ec_stackT *stack; + ec_bufT *rxbuf; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + rval = EC_NOFRAME; + rxbuf = &(*stack->rxbuf)[idx]; + /* check if requested index is already in buffer ? */ + if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD)) + { + l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + } + else + { + pthread_mutex_lock(&(port->rx_mutex)); + /* non blocking call to retrieve frame from socket */ + if (ecx_recvpkt(port, stacknumber)) + { + rval = EC_OTHERFRAME; + ehp =(ec_etherheadert*)(stack->tempbuf); + /* check if it is an EtherCAT frame */ + if (ehp->etype == htons(ETH_P_ECAT)) + { + ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]); + l = etohs(ecp->elength) & 0x0fff; + idxf = ecp->index; + /* found index equals reqested index ? */ + if (idxf == idx) + { + /* yes, put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + /* store MAC source word 1 for redundant routing info */ + (*stack->rxsa)[idx] = ntohs(ehp->sa1); + } + else + { + /* check if index exist? */ + if (idxf < EC_MAXBUF) + { + rxbuf = &(*stack->rxbuf)[idxf]; + /* put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE); + /* mark as received */ + (*stack->rxbufstat)[idxf] = EC_BUF_RCVD; + (*stack->rxsa)[idxf] = ntohs(ehp->sa1); + } + else + { + /* strange things happend */ + } + } + } + } + pthread_mutex_unlock( &(port->rx_mutex) ); + + } + + /* WKC if mathing frame found */ + return rval; +} + +/** Blocking redundant receive frame function. If redundant mode is not active then + * it skips the secondary stack and redundancy functions. In redundant mode it waits + * for both (primary and secondary) frames to come in. The result goes in an decision + * tree that decides, depending on the route of the packet and its possible missing arrival, + * how to reroute the original packet to get the data in an other try. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] timer = absolute timeout time + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer) +{ + osal_timert timer2; + int wkc = EC_NOFRAME; + int wkc2 = EC_NOFRAME; + int primrx, secrx; + + /* if not in redundant mode then always assume secondary is OK */ + if (port->redstate == ECT_RED_NONE) + wkc2 = 0; + do + { + /* only read frame if not already in */ + if (wkc <= EC_NOFRAME) + wkc = ecx_inframe(port, idx, 0); + /* only try secondary if in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* only read frame if not already in */ + if (wkc2 <= EC_NOFRAME) + wkc2 = ecx_inframe(port, idx, 1); + } + /* wait for both frames to arrive or timeout */ + } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer)); + /* only do redundant functions when in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* primrx if the reveived MAC source on primary socket */ + primrx = 0; + if (wkc > EC_NOFRAME) primrx = port->rxsa[idx]; + /* secrx if the reveived MAC source on psecondary socket */ + secrx = 0; + if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx]; + + /* primary socket got secondary frame and secondary socket got primary frame */ + /* normal situation in redundant mode */ + if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) ) + { + /* copy secondary buffer to primary */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + /* primary socket got nothing or primary frame, and secondary socket got secondary frame */ + /* we need to resend TX packet */ + if ( ((primrx == 0) && (secrx == RX_SEC)) || + ((primrx == RX_PRIM) && (secrx == RX_SEC)) ) + { + /* If both primary and secondary have partial connection retransmit the primary received + * frame over the secondary socket. The result from the secondary received frame is a combined + * frame that traversed all slaves in standard order. */ + if ( (primrx == RX_PRIM) && (secrx == RX_SEC) ) + { + /* copy primary rx to tx buffer */ + memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + } + osal_timer_start (&timer2, EC_TIMEOUTRET); + /* resend secondary tx */ + ecx_outframe(port, idx, 1); + do + { + /* retrieve frame */ + wkc2 = ecx_inframe(port, idx, 1); + } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2)); + if (wkc2 > EC_NOFRAME) + { + /* copy secondary result to primary rx buffer */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + } + } + + /* return WKC or EC_NOFRAME */ + return wkc; +} + +/** Blocking receive frame function. Calls ec_waitinframe_red(). + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] timeout = timeout in us + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +int ecx_waitinframe(ecx_portt *port, int idx, int timeout) +{ + int wkc; + osal_timert timer; + + osal_timer_start (&timer, timeout); + wkc = ecx_waitinframe_red(port, idx, &timer); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + } + + return wkc; +} + +/** Blocking send and recieve frame function. Used for non processdata frames. + * A datagram is build into a frame and transmitted via this function. It waits + * for an answer and returns the workcounter. The function retries if time is + * left and the result is WKC=0 or no frame received. + * + * The function calls ec_outframe_red() and ec_waitinframe_red(). + * + * @param[in] port = port context struct + * @param[in] idx = index of frame + * @param[in] timeout = timeout in us + * @return Workcounter or EC_NOFRAME + */ +int ecx_srconfirm(ecx_portt *port, int idx, int timeout) +{ + int wkc = EC_NOFRAME; + osal_timert timer1, timer2; + + osal_timer_start (&timer1, timeout); + do + { + /* tx frame on primary and if in redundant mode a dummy on secondary */ + ecx_outframe_red(port, idx); + if (timeout < EC_TIMEOUTRET) + { + osal_timer_start (&timer2, timeout); + } + else + { + /* normally use partial timout for rx */ + osal_timer_start (&timer2, EC_TIMEOUTRET); + } + /* get frame from primary or if in redundant mode possibly from secondary */ + wkc = ecx_waitinframe_red(port, idx, &timer2); + /* wait for answer with WKC>=0 or otherwise retry until timeout */ + } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1)); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + } + + return wkc; +} + +#ifdef EC_VER1 +int ec_setupnic(const char *ifname, int secondary) +{ + return ecx_setupnic(&ecx_port, ifname, secondary); +} + +int ec_closenic(void) +{ + return ecx_closenic(&ecx_port); +} + +int ec_getindex(void) +{ + return ecx_getindex(&ecx_port); +} + +void ec_setbufstat(int idx, int bufstat) +{ + ecx_setbufstat(&ecx_port, idx, bufstat); +} + +int ec_outframe(int idx, int stacknumber) +{ + return ecx_outframe(&ecx_port, idx, stacknumber); +} + +int ec_outframe_red(int idx) +{ + return ecx_outframe_red(&ecx_port, idx); +} + +int ec_inframe(int idx, int stacknumber) +{ + return ecx_inframe(&ecx_port, idx, stacknumber); +} + +int ec_waitinframe(int idx, int timeout) +{ + return ecx_waitinframe(&ecx_port, idx, timeout); +} + +int ec_srconfirm(int idx, int timeout) +{ + return ecx_srconfirm(&ecx_port, idx, timeout); +} +#endif diff --git a/oshw/linux/nicdrv.h b/oshw/linux/nicdrv.h new file mode 100644 index 0000000..294c871 --- /dev/null +++ b/oshw/linux/nicdrv.h @@ -0,0 +1,155 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for nicdrv.c + */ + +#ifndef _nicdrvh_ +#define _nicdrvh_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +/** pointer structure to Tx and Rx stacks */ +typedef struct +{ + /** socket connection used */ + int *sock; + /** tx buffer */ + ec_bufT (*txbuf)[EC_MAXBUF]; + /** tx buffer lengths */ + int (*txbuflength)[EC_MAXBUF]; + /** temporary receive buffer */ + ec_bufT *tempbuf; + /** rx buffers */ + ec_bufT (*rxbuf)[EC_MAXBUF]; + /** rx buffer status fields */ + int (*rxbufstat)[EC_MAXBUF]; + /** received MAC source address (middle word) */ + int (*rxsa)[EC_MAXBUF]; +} ec_stackT; + +/** pointer structure to buffers for redundant port */ +typedef struct +{ + ec_stackT stack; + int sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; +} ecx_redportt; + +/** pointer structure to buffers, vars and mutexes for port instantiation */ +typedef struct +{ + ec_stackT stack; + int sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; + /** temporary rx buffer status */ + int tempinbufs; + /** transmit buffers */ + ec_bufT txbuf[EC_MAXBUF]; + /** transmit buffer lenghts */ + int txbuflength[EC_MAXBUF]; + /** temporary tx buffer */ + ec_bufT txbuf2; + /** temporary tx buffer length */ + int txbuflength2; + /** last used frame index */ + int lastidx; + /** current redundancy state */ + int redstate; + /** pointer to redundancy port and buffers */ + ecx_redportt *redport; + pthread_mutex_t getindex_mutex; + pthread_mutex_t tx_mutex; + pthread_mutex_t rx_mutex; +} ecx_portt; + +extern const uint16 priMAC[3]; +extern const uint16 secMAC[3]; + +#ifdef EC_VER1 +extern ecx_portt ecx_port; +extern ecx_redportt ecx_redport; + +int ec_setupnic(const char * ifname, int secondary); +int ec_closenic(void); +void ec_setbufstat(int idx, int bufstat); +int ec_getindex(void); +int ec_outframe(int idx, int sock); +int ec_outframe_red(int idx); +int ec_waitinframe(int idx, int timeout); +int ec_srconfirm(int idx,int timeout); +#endif + +void ec_setupheader(void *p); +int ecx_setupnic(ecx_portt *port, const char * ifname, int secondary); +int ecx_closenic(ecx_portt *port); +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat); +int ecx_getindex(ecx_portt *port); +int ecx_outframe(ecx_portt *port, int idx, int sock); +int ecx_outframe_red(ecx_portt *port, int idx); +int ecx_waitinframe(ecx_portt *port, int idx, int timeout); +int ecx_srconfirm(ecx_portt *port, int idx,int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oshw/linux/oshw.c b/oshw/linux/oshw.c new file mode 100644 index 0000000..315a7af --- /dev/null +++ b/oshw/linux/oshw.c @@ -0,0 +1,138 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: oshw.c 282 2012-09-25 10:52:42Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "oshw.h" + +/** + * Host to Network byte order (i.e. to big endian). + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_htons(uint16 host) +{ + uint16 network = htons (host); + return network; +} + +/** + * Network (i.e. big endian) to Host byte order. + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_ntohs(uint16 network) +{ + uint16 host = ntohs (network); + return host; +} + +/** Create list over available network adapters. + * @return First element in linked list of adapters + */ +ec_adaptert * oshw_find_adapters(void) +{ + int i; + int string_len; + struct if_nameindex *ids; + ec_adaptert * adapter; + ec_adaptert * prev_adapter; + ec_adaptert * ret_adapter = NULL; + + + /* Iterate all devices and create a local copy holding the name and + * decsription. + */ + + ids = if_nameindex (); + for(i = 0; ids[i].if_index != 0; i++) + { + adapter = (ec_adaptert *)malloc(sizeof(ec_adaptert)); + /* If we got more than one adapter save link list pointer to previous + * adapter. + * Else save as pointer to return. + */ + if (i) + { + prev_adapter->next = adapter; + } + else + { + ret_adapter = adapter; + } + + /* fetch description and name, in linux we use the same on both */ + adapter->next = NULL; + + if (ids[i].if_name) + { + string_len = strlen(ids[i].if_name); + if (string_len > (EC_MAXLEN_ADAPTERNAME - 1)) + { + string_len = EC_MAXLEN_ADAPTERNAME - 1; + } + strncpy(adapter->name, ids[i].if_name,string_len); + adapter->name[string_len] = '\0'; + strncpy(adapter->desc, ids[i].if_name,string_len); + adapter->desc[string_len] = '\0'; + } + else + { + adapter->name[0] = '\0'; + adapter->desc[0] = '\0'; + } + + prev_adapter = adapter; + } + + if_freenameindex (ids); + + return ret_adapter; +} + +/** Free memory allocated memory used by adapter collection. + * @param[in] adapter = First element in linked list of adapters + * EC_NOFRAME. + */ +void oshw_free_adapters(ec_adaptert * adapter) +{ + ec_adaptert * next_adapter; + /* Iterate the linked list and free all elemnts holding + * adapter information + */ + if(adapter) + { + next_adapter = adapter->next; + free (adapter); + while (next_adapter) + { + adapter = next_adapter; + next_adapter = adapter->next; + free (adapter); + } + } +} diff --git a/oshw/linux/oshw.h b/oshw/linux/oshw.h new file mode 100644 index 0000000..a0cc898 --- /dev/null +++ b/oshw/linux/oshw.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: oshw.h 452 2013-02-26 21:02:58Z smf.arthur $ + *------------------------------------------------------------------------------ + */ + +/** \file + * \brief + * Headerfile for ethercatbase.c + */ + +#ifndef _oshw_ +#define _oshw_ + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatmain.h" + +uint16 oshw_htons(uint16 hostshort); +uint16 oshw_ntohs(uint16 networkshort); +ec_adaptert * oshw_find_adapters(void); +void oshw_free_adapters(ec_adaptert * adapter); + +#endif diff --git a/oshw/rtk/lw_mac/lw_emac.c b/oshw/rtk/lw_mac/lw_emac.c new file mode 100644 index 0000000..474e63a --- /dev/null +++ b/oshw/rtk/lw_mac/lw_emac.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: lw_emac.c 348 2012-10-18 16:41:14Z rtlfrm $ + * + * + *------------------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include + +#include "lw_emac.h" + +/* MII standard registers. + See IEEE Std 802.3-2005 clause 22: + "Reconciliation Sublayer (RS) and Media Independent Interface (MII)", + section 2.4.1 to 3. + http://standards.ieee.org/getieee802/download/802.3-2005_section2.pdf */ +#define MII_BMCR 0x00 /* Basic Mode Control Register */ +#define MII_BMSR 0x01 /* Basic Mode Status Register */ +#define MII_PHYIDR1 0x02 /* PHY Identifier Register 1 */ +#define MII_PHYIDR2 0x03 /* PHY Identifier Register 2 */ +#define MII_LPAR 0x05 /* Auto-Negotiation Link Partner Ability Register */ + +/* MII basic mode control register */ +#define MII_BMCR_RST BIT (15) +#define MII_BMCR_ANEG_EN BIT (12) +#define MII_BMCR_ANEG_RST BIT (9) + +/* MII basic mode status register */ +#define MII_BMSR_ANEGACK BIT (5) +#define MII_BMSR_LINK BIT (2) + +/* MII auto-negotiation advertisement register */ +#define MII_ANAR_100_FD BIT (8) /* Can do 100BASE-TX full duplex */ +#define MII_ANAR_10_FD BIT (6) /* Can do 10BASE-T full duplex */ + +/* Management Data Clock (MDC) frequency. + * 2.5Mz corresponds to the minimum period for MDC as defined by the standard. + * This is independent of whether the PHY is in 10Mbit/s or 100Mbit/s mode. + * See Std. IEEE 802.3 (Ethernet) Clause 22.2.2.11 ("management data clock"). */ +#define PHY_MDC_Hz 2500000 +#define PHY_RETRIES 3000 +/* TODO: This might need changing for different boards. Fix? */ +#define PHY_ADDR 0 + +#define ETH_RX_BUF_SIZE 2 +#define ETH_TX_BUF_SIZE 1 +#define ETH_FRAME_SIZE 0x614 + +/* Ethernet MAC register structure */ +typedef struct bfin_emac_regs +{ + /* Control-Status Register Group */ + uint32_t opmode; /* operating mode */ + uint32_t addrlo; /* address low */ + uint32_t addrhi; /* address high */ + uint32_t hashlo; /* multicast hash table low */ + uint32_t hashhi; /* multicast hash table high */ + uint32_t staadd; /* station management address */ + uint32_t stadat; /* station management data */ + uint32_t flc; /* flow control */ + uint32_t vlan1; /* VLAN1 tag */ + uint32_t vlan2; /* VLAN2 tag */ + uint32_t _reserved1; + uint32_t wkup_ctl; /* wakeup frame control and status */ + uint32_t wkup_ffmsk[4]; /* wakeup frame n byte mask (n == 0,..,3) */ + uint32_t wkup_ffcmd; /* wakeup frame filter commands */ + uint32_t wkup_ffoff; /* wakeup frame filter offsets */ + uint32_t wkup_ffcrc0; /* wakeup frame filter CRC0/1 */ + uint32_t wkup_ffcrc1; /* wakeup frame filter CRC2/3 */ + uint32_t _reserved2[4]; + /* System Interface Register Group */ + uint32_t sysctl; /* system control */ + uint32_t systat; /* system status */ + /* Ethernet Frame Status Register Group */ + uint32_t rx_stat; /* RX Current Frame Status */ + uint32_t rx_stky; /* RX Sticky Frame Status */ + uint32_t rx_irqe; /* RX Frame Status Interrupt Enable */ + uint32_t tx_stat; /* TX Current Frame Status Register */ + uint32_t tx_stky; /* TT Sticky Frame Status */ + uint32_t tx_irqe; /* TX Frame Status Interrupt Enable */ + /* MAC Management Counter Register Group */ + uint32_t mmc_ctl; /* Management Counters Control */ + uint32_t mmc_rirqs; /* MMC RX Interrupt Status */ + uint32_t mmc_rirqe; /* MMC RX Interrupt Enable */ + uint32_t mmc_tirqs; /* MMC TX Interrupt Status */ + uint32_t mmc_tirqe; /* MMC TX Interrupt Enable */ + uint32_t _reserved3[27]; + uint32_t mmc_rxc_ok; /* FramesReceivedOK */ + uint32_t mmc_rxc_fcs; /* FrameCheckSequenceErrors */ + uint32_t mmc_rxc_align; /* AlignmentErrors */ + uint32_t mmc_rxc_octet; /* OctetsReceivedOK */ + uint32_t mmc_rxc_dmaovf; /* FramesLostDueToIntMACRcvError */ + uint32_t mmc_rxc_unicst; /* UnicastFramesReceivedOK */ + uint32_t mmc_rxc_multi; /* MulticastFramesReceivedOK */ + uint32_t mmc_rxc_broad; /* BroadcastFramesReceivedOK */ + uint32_t mmc_rxc_lnerri; /* InRangeLengthErrors */ + uint32_t mmc_rxc_lnerro; /* OutOfRangeLengthField */ + uint32_t mmc_rxc_long; /* FrameTooLongErrors */ + uint32_t mmc_rxc_macctl; /* MACControlFramesReceived */ + uint32_t mmc_rxc_opcode; /* UnsupportedOpcodesReceived */ + uint32_t mmc_rxc_pause; /* PAUSEMACCtrlFramesReceived */ + uint32_t mmc_rxc_allfrm; /* FramesReceivedAll */ + uint32_t mmc_rxc_alloct; /* OctetsReceivedAll */ + uint32_t mmc_rxc_typed; /* TypedFramesReceived */ + uint32_t mmc_rxc_short; /* FramesLenLt64Received */ + uint32_t mmc_rxc_eq64; /* FramesLenEq64Received */ + uint32_t mmc_rxc_lt128; /* FramesLen65_127Received */ + uint32_t mmc_rxc_lt256; /* FramesLen128_255Received */ + uint32_t mmc_rxc_lt512; /* FramesLen256_511Received */ + uint32_t mmc_rxc_lt1024; /* FramesLen512_1023Received */ + uint32_t mmc_rxc_ge1024; /* FramesLen1024_MaxReceived */ + /* TODO: add all registers */ +} bfin_emac_regs_t; + +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, opmode) == 0x0); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, staadd) == 0x14); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, wkup_ctl) == 0x2c); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, wkup_ffcrc1) == 0x4c); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, sysctl) == 0x60); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, rx_stat) == 0x68); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, mmc_ctl) == 0x80); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, mmc_tirqe) == 0x90); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, mmc_rxc_ok) == 0x100); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, mmc_rxc_dmaovf) == 0x110); +COMPILETIME_ASSERT (offsetof (bfin_emac_regs_t, mmc_rxc_ge1024) == 0x15c); + +/* 32-bit aligned struct for ethernet data */ +typedef struct ethernet_data { + uint16_t length; /* When TX = frame data length in bytes, not including 'length' + * When RX = 0x0000 padding when using RXDWA + */ + uint8_t data[ETH_FRAME_SIZE]; /* Hold the ethernet frame */ + uint16_t padding; /* To make the struct 32-bit aligned */ +} ethernet_data_t; + +COMPILETIME_ASSERT (sizeof (ethernet_data_t) == 0x618) ; + +static volatile bfin_emac_regs_t * pEth = (bfin_emac_regs_t *) EMAC_OPMODE; + +/* Buffers for rx and tx DMA operations */ +static ethernet_data_t rxBuffer[ETH_RX_BUF_SIZE] __attribute__((section(".dma"))); +static ethernet_data_t txBuffer[ETH_TX_BUF_SIZE] __attribute__((section(".dma"))); +static volatile uint32_t rxStatusWord[ETH_RX_BUF_SIZE] __attribute__((section(".dma"))); +static volatile uint32_t txStatusWord[ETH_TX_BUF_SIZE] __attribute__((section(".dma"))); +static bfin_dma_descriptor_t rxDMADesc[ETH_RX_BUF_SIZE * 2] __attribute__((section(".dma"))); +static bfin_dma_descriptor_t txDMADesc[ETH_TX_BUF_SIZE * 2] __attribute__((section(".dma"))); + +/* Hold the current index of rx and tx buffers */ +static uint8_t rxIdx, txIdx; + + +/* Internal function that writes to a PHY register */ +static void lw_emac_write_phy_reg(uint8_t phy_addr, uint8_t reg_addr, uint32_t data) { + /* Set the flags that should be set reg_addr on PHY */ + pEth->stadat = data; + + /* Wait for our turn then initiate writing of stadat to PHY register */ + pEth->staadd = SET_PHYAD(phy_addr) | SET_REGAD(reg_addr) | STAOP | STABUSY; + while (pEth->staadd & STABUSY) ; +} + +/* Internal function that reads from; and returns a PHY register */ +static uint32_t lw_emac_read_phy_reg(uint8_t phy_addr, uint8_t reg_addr) { + pEth->staadd = SET_PHYAD(phy_addr) | SET_REGAD(reg_addr) | STABUSY; + while (pEth->staadd & STABUSY) ; + + return pEth->stadat; +} + +/* Internal function that sets the MAC address */ +static void lw_emac_set_mac_addr(uint8_t * ethAddr) +{ + pEth->addrlo = + ethAddr[0] | + ethAddr[1] << 8 | + ethAddr[2] << 16 | + ethAddr[3] << 24; + pEth->addrhi = + ethAddr[4] | + ethAddr[5] << 8; +} + +static uint8_t lw_emac_init_registers(uint8_t * ethAddr) { + uint32_t clock_divisor, sysctl_mdcdiv, phy_stadat, counter; + + /* CONFIGURE MAC MII PINS */ + + /* Enable PHY Clock Output */ + *(volatile uint16_t *) VR_CTL |= PHYCLKOE; + + /* Set all bits to 1 to use MII mode */ + *(uint16_t *) PORTH_FER = 0xFFFF; + + /* CONFIGURE MAC REGISTERS */ + + /* + * Set the MMC (MAC Management Counter) control register + * RTSC = Clear all counters + * + * Note that counters are not enabled at this time + */ + pEth->mmc_ctl = RSTC; + + /* Set MAC address */ + lw_emac_set_mac_addr (ethAddr); + + clock_divisor = SCLK / PHY_MDC_Hz; + sysctl_mdcdiv = clock_divisor / 2 - 1; + ASSERT (sysctl_mdcdiv <= 0x3f); + + rprintp ("PHY ID: %04x %04x\n", + lw_emac_read_phy_reg (PHY_ADDR, MII_PHYIDR1), + lw_emac_read_phy_reg (PHY_ADDR, MII_PHYIDR2) + ); + + /* + * Set the system control register + * SET_MDCDIV(x) = Set MDC to 2.5 MHz + * RXDWA = Pad incoming frame with 0x0000 as to make the data-part 32-bit aligned + * RXCKS = Enable Receive Frame TCP/UDP Checksum Computation + */ + pEth->sysctl = SET_MDCDIV(sysctl_mdcdiv) | RXDWA ; + + /* CONFIGURE PHY */ + + /* + * Set the PHY basic control register + * MII_BMCR_ANEG_EN = Auto negotiation on + * MII_BMCR_ANEG_RST = Restart the auto-neg process by setting + * Speed handled by auto negotiation + */ + phy_stadat = MII_BMCR_ANEG_EN | MII_BMCR_ANEG_RST; + lw_emac_write_phy_reg(PHY_ADDR, MII_BMCR, phy_stadat); + + /* Loop until link is up or time out after PHY_RETRIES */ + counter = 0; + do { + if (counter > PHY_RETRIES) { + rprintp("Ethernet link is down\n"); + return -1; + } + + task_delay (tick_from_ms (10)); + phy_stadat = lw_emac_read_phy_reg(PHY_ADDR, MII_BMSR); + + ++counter; + } while (!(phy_stadat & MII_BMSR_LINK)) ; + + /* Check whether link partner can do full duplex or not */ + phy_stadat = lw_emac_read_phy_reg(PHY_ADDR, MII_LPAR); + + if (phy_stadat & (MII_ANAR_100_FD | MII_ANAR_10_FD) ) { + pEth->opmode = FDMODE; + } + else { + pEth->opmode = 0; + } + + /* + * Setup DMA MAC receive/transfer channels with XCOUNT 0 (which we use + * together with description based DMA) and XMODIFY 4 (bytes per transfer) + */ + bfin_dma_channel_init(DMA_CHANNEL_EMAC_RX, 0, 4); + bfin_dma_channel_init(DMA_CHANNEL_EMAC_TX, 0, 4); + + return 0; +} + +int bfin_EMAC_init (uint8_t *ethAddr) +{ + rxIdx = txIdx = 0; + + if (lw_emac_init_registers(ethAddr) != 0) { + return -1; + } + + // Reset status words + memset ((uint8_t *)rxStatusWord, 0, sizeof(rxStatusWord)); + memset ((uint8_t *)txStatusWord, 0, sizeof(txStatusWord)); + + txDMADesc[0].next = &txDMADesc[1]; + txDMADesc[0].start_addr = &txBuffer[0]; + txDMADesc[0].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(5) | + DMA_CONFIG_FLOW(DMA_FLOW_DESCRIPTOR_LIST_LARGE); + + txDMADesc[1].next = &txDMADesc[0]; + txDMADesc[1].start_addr = &txStatusWord[0]; + txDMADesc[1].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WNR | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(0) | + DMA_CONFIG_FLOW(DMA_FLOW_STOP); + + rxDMADesc[0].next = &rxDMADesc[1]; + rxDMADesc[0].start_addr = &rxBuffer[0]; + rxDMADesc[0].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WNR | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(5) | + DMA_CONFIG_FLOW(DMA_FLOW_DESCRIPTOR_LIST_LARGE); + + rxDMADesc[1].next = &rxDMADesc[2]; + rxDMADesc[1].start_addr = &rxStatusWord[0]; + rxDMADesc[1].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WNR | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(5) | + DMA_CONFIG_FLOW(DMA_FLOW_DESCRIPTOR_LIST_LARGE); + + rxDMADesc[2].next = &rxDMADesc[3]; + rxDMADesc[2].start_addr = &rxBuffer[1]; + rxDMADesc[2].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WNR | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(5) | + DMA_CONFIG_FLOW(DMA_FLOW_DESCRIPTOR_LIST_LARGE); + + rxDMADesc[3].next = &rxDMADesc[0]; + rxDMADesc[3].start_addr = &rxStatusWord[1]; + rxDMADesc[3].config = DMA_CONFIG_DMA_EN | + DMA_CONFIG_WNR | + DMA_CONFIG_WDSIZE(DMA_WDSIZE_32BIT) | + DMA_CONFIG_NDSIZE(5) | + DMA_CONFIG_FLOW(DMA_FLOW_DESCRIPTOR_LIST_LARGE); + + bfin_dma_channel_enable(DMA_CHANNEL_EMAC_RX, &rxDMADesc[0]); + + /* Enable Receiving, Automatic Pad Stripping and receiving of frames with length < 64 butes */ + pEth->opmode |= ASTP | PSF | RE; + + return 0; +} +int bfin_EMAC_send (void *packet, int length) +{ + UASSERT(length > 0, EARG); + UASSERT(length < ETH_FRAME_SIZE, EARG); + + /* TODO: Check DMA Error in IRQ status */ + + while (bfin_dma_channel_interrupt_is_active (DMA_CHANNEL_EMAC_TX)); + + txBuffer[txIdx].length = length; + memcpy(txBuffer[txIdx].data, packet, length); + + bfin_dma_channel_enable(DMA_CHANNEL_EMAC_TX, txDMADesc); + pEth->opmode |= TE; + + while ((txStatusWord[txIdx] & TX_COMP) == 0); + + ASSERT(txStatusWord[txIdx] & TX_OK); + + txStatusWord[txIdx] = 0; + + ++txIdx; + + if (txIdx == ETH_TX_BUF_SIZE) { + txIdx = 0; + } + + return 0; +} + +int bfin_EMAC_recv (uint8_t * packet, size_t size) +{ + uint32_t length; + uint32_t status = rxStatusWord[rxIdx]; + + /* Check if rx frame is completed */ + if ((status & RX_COMP) == 0) { + return -1; + } + else if ((status & RX_OK) == 0) { + ASSERT(0); + /* TODO: Handle error */ + return -1; + } + else if (status & RX_DMAO) { + ASSERT(0); + /* TODO: Handle overrun */ + return -1; + } + + length = status & RX_FRLEN; + + if (size < length) { + length = size; + } + + memcpy(packet, rxBuffer[rxIdx].data, length); + + bfin_dma_channel_interrupt_clear (DMA_CHANNEL_EMAC_RX); + rxStatusWord[rxIdx] = 0; + + ++rxIdx; + + if (rxIdx == ETH_RX_BUF_SIZE) { + rxIdx = 0; + } + + return length; +} + diff --git a/oshw/rtk/lw_mac/lw_emac.h b/oshw/rtk/lw_mac/lw_emac.h new file mode 100644 index 0000000..24f98df --- /dev/null +++ b/oshw/rtk/lw_mac/lw_emac.h @@ -0,0 +1,12 @@ +/* + * author: Tomas Vestelind + */ + +#ifndef LWIP_MAC_H +#define LWIP_MAC_H + +int bfin_EMAC_init(uint8_t *enetaddr); +int bfin_EMAC_send(void *packet, int length); +int bfin_EMAC_recv(uint8_t * packet, size_t size); + +#endif /* LWIP_MAC_H */ diff --git a/oshw/rtk/nicdrv.c b/oshw/rtk/nicdrv.c new file mode 100644 index 0000000..f8cb758 --- /dev/null +++ b/oshw/rtk/nicdrv.c @@ -0,0 +1,673 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * EtherCAT RAW socket driver. + * + * Low level interface functions to send and receive EtherCAT packets. + * EtherCAT has the property that packets are only send by the master, + * and the send packets allways return in the receive buffer. + * There can be multiple packets "on the wire" before they return. + * To combine the received packets with the original send packets a buffer + * system is installed. The identifier is put in the index item of the + * EtherCAT header. The index is stored and compared when a frame is recieved. + * If there is a match the packet can be combined with the transmit packet + * and returned to the higher level function. + * + * The socket layer can exhibit a reversal in the packet order (rare). + * If the Tx order is A-B-C the return order could be A-C-B. The indexed buffer + * will reorder the packets automatically. + * + * The "redundant" option will configure two sockets and two NIC interfaces. + * Slaves are connected to both interfaces, one on the IN port and one on the + * OUT port. Packets are send via both interfaces. Any one of the connections + * (also an interconnect) can be removed and the slaves are still serviced with + * packets. The software layer will detect the possible failure modes and + * compensate. If needed the packets from interface A are resend through interface B. + * This layer is fully transparent for the higher layers. + */ + +#include +#include +#include +#include + +#include "osal.h" +#include "oshw.h" + + +#include "lw_mac/lw_emac.h" + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/** Redundancy modes */ +enum +{ + /** No redundancy, single NIC mode */ + ECT_RED_NONE, + /** Double redundant NIC connecetion */ + ECT_RED_DOUBLE +}; + +/** Primary source MAC address used for EtherCAT. + * This address is not the MAC address used from the NIC. + * EtherCAT does not care about MAC addressing, but it is used here to + * differentiate the route the packet traverses through the EtherCAT + * segment. This is needed to find out the packet flow in redundant + * configurations. */ +const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 }; +/** Secondary source MAC address used for EtherCAT. */ +const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 }; + +/** second MAC word is used for identification */ +#define RX_PRIM priMAC[1] +/** second MAC word is used for identification */ +#define RX_SEC secMAC[1] + +static void ecx_clear_rxbufstat(int *rxbufstat) +{ + int i; + for(i = 0; i < EC_MAXBUF; i++) + { + rxbufstat[i] = EC_BUF_EMPTY; + } +} + +/** Basic setup to connect NIC to socket. + * @param[in] port = port context struct + * @param[in] ifname = Name of NIC device, f.e. "eth0" + * @param[in] secondary = if >0 then use secondary stack instead of primary + * @return >0 if succeeded + */ +int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary) +{ + int i; + int rVal; + int *psock; + + port->getindex_mutex = mtx_create(); + port->tx_mutex = mtx_create(); + port->rx_mutex = mtx_create(); + + rVal = bfin_EMAC_init((uint8_t *)priMAC); + if (rVal != 0) + return 0; + + if (secondary) + { + /* secondary port stuct available? */ + if (port->redport) + { + /* when using secondary socket it is automatically a redundant setup */ + psock = &(port->redport->sockhandle); + *psock = -1; + port->redstate = ECT_RED_DOUBLE; + port->redport->stack.sock = &(port->redport->sockhandle); + port->redport->stack.txbuf = &(port->txbuf); + port->redport->stack.txbuflength = &(port->txbuflength); + port->redport->stack.tempbuf = &(port->redport->tempinbuf); + port->redport->stack.rxbuf = &(port->redport->rxbuf); + port->redport->stack.rxbufstat = &(port->redport->rxbufstat); + port->redport->stack.rxsa = &(port->redport->rxsa); + ecx_clear_rxbufstat(&(port->redport->rxbufstat[0])); + } + else + { + /* fail */ + return 0; + } + } + else + { + port->getindex_mutex = mtx_create(); + port->tx_mutex = mtx_create(); + port->rx_mutex = mtx_create(); + port->sockhandle = -1; + port->lastidx = 0; + port->redstate = ECT_RED_NONE; + port->stack.sock = &(port->sockhandle); + port->stack.txbuf = &(port->txbuf); + port->stack.txbuflength = &(port->txbuflength); + port->stack.tempbuf = &(port->tempinbuf); + port->stack.rxbuf = &(port->rxbuf); + port->stack.rxbufstat = &(port->rxbufstat); + port->stack.rxsa = &(port->rxsa); + ecx_clear_rxbufstat(&(port->rxbufstat[0])); + psock = &(port->sockhandle); + } + + /* setup ethernet headers in tx buffers so we don't have to repeat it */ + for (i = 0; i < EC_MAXBUF; i++) + { + ec_setupheader(&(port->txbuf[i])); + port->rxbufstat[i] = EC_BUF_EMPTY; + } + ec_setupheader(&(port->txbuf2)); + + return 1; +} + +/** Close sockets used + * @param[in] port = port context struct + * @return 0 + */ +int ecx_closenic(ecx_portt *port) +{ + if (port->sockhandle >= 0) + { + close(port->sockhandle); + } + if ((port->redport) && (port->redport->sockhandle >= 0)) + { + close(port->redport->sockhandle); + } + return 0; +} + +/** Fill buffer with ethernet header structure. + * Destination MAC is allways broadcast. + * Ethertype is allways ETH_P_ECAT. + * @param[out] p = buffer + */ +void ec_setupheader(void *p) +{ + ec_etherheadert *bp; + bp = p; + bp->da0 = oshw_htons(0xffff); + bp->da1 = oshw_htons(0xffff); + bp->da2 = oshw_htons(0xffff); + bp->sa0 = oshw_htons(priMAC[0]); + bp->sa1 = oshw_htons(priMAC[1]); + bp->sa2 = oshw_htons(priMAC[2]); + bp->etype = oshw_htons(ETH_P_ECAT); +} + +/** Get new frame identifier index and allocate corresponding rx buffer. + * @param[in] port = port context struct + * @return new index. + */ +int ecx_getindex(ecx_portt *port) +{ + int idx; + int cnt; + + mtx_lock (port->getindex_mutex); + + idx = port->lastidx + 1; + /* index can't be larger than buffer array */ + if (idx >= EC_MAXBUF) + { + idx = 0; + } + cnt = 0; + /* try to find unused index */ + while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF)) + { + idx++; + cnt++; + if (idx >= EC_MAXBUF) + { + idx = 0; + } + } + port->rxbufstat[idx] = EC_BUF_ALLOC; + if (port->redstate != ECT_RED_NONE) + { + port->redport->rxbufstat[idx] = EC_BUF_ALLOC; + } + port->lastidx = idx; + + mtx_unlock (port->getindex_mutex); + + return idx; +} + +/** Set rx buffer status. + * @param[in] port = port context struct + * @param[in] idx = index in buffer array + * @param[in] bufstat = status to set + */ +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat) +{ + port->rxbufstat[idx] = bufstat; + if (port->redstate != ECT_RED_NONE) + { + port->redport->rxbufstat[idx] = bufstat; + } +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @param[in] stacknumber = 0=Primary 1=Secondary stack + * @return socket send result + */ +int ecx_outframe(ecx_portt *port, int idx, int stacknumber) +{ + int lp, rval; + ec_stackT *stack; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = (*stack->txbuflength)[idx]; + rval = bfin_EMAC_send((*stack->txbuf)[idx], lp); + (*stack->rxbufstat)[idx] = EC_BUF_TX; + + return rval; +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @return socket send result + */ +int ecx_outframe_red(ecx_portt *port, int idx) +{ + ec_comt *datagramP; + ec_etherheadert *ehp; + int rval; + + ehp = (ec_etherheadert *)&(port->txbuf[idx]); + /* rewrite MAC source address 1 to primary */ + ehp->sa1 = oshw_htons(priMAC[1]); + /* transmit over primary socket*/ + rval = ecx_outframe(port, idx, 0); + if (port->redstate != ECT_RED_NONE) + { + mtx_lock (port->tx_mutex); + ehp = (ec_etherheadert *)&(port->txbuf2); + /* use dummy frame for secondary socket transmit (BRD) */ + datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]); + /* write index to frame */ + datagramP->index = idx; + /* rewrite MAC source address 1 to secondary */ + ehp->sa1 = oshw_htons(secMAC[1]); + /* transmit over secondary socket */ + //send(sockhandle2, &ec_txbuf2, ec_txbuflength2 , 0); + // OBS! redundant not ACTIVE for BFIN, just added to compile + ASSERT (0); + bfin_EMAC_send(&(port->txbuf2), port->txbuflength2); + mtx_unlock (port->tx_mutex); + port->redport->rxbufstat[idx] = EC_BUF_TX; + } + + return rval; +} + +/** Non blocking read of socket. Put frame in temporary buffer. + * @param[in] port = port context struct + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return >0 if frame is available and read + */ +static int ecx_recvpkt(ecx_portt *port, int stacknumber) +{ + int lp, bytesrx; + ec_stackT *stack; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = sizeof(port->tempinbuf); + bytesrx = bfin_EMAC_recv((*stack->tempbuf), lp); + port->tempinbufs = bytesrx; + + return (bytesrx > 0); +} + +/** Non blocking receive frame function. Uses RX buffer and index to combine + * read frame with transmitted frame. To compensate for received frames that + * are out-of-order all frames are stored in their respective indexed buffer. + * If a frame was placed in the buffer previously, the function retreives it + * from that buffer index without calling ec_recvpkt. If the requested index + * is not already in the buffer it calls ec_recvpkt to fetch it. There are + * three options now, 1 no frame read, so exit. 2 frame read but other + * than requested index, store in buffer and exit. 3 frame read with matching + * index, store in buffer, set completed flag in buffer status and exit. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME or EC_OTHERFRAME. + */ +int ecx_inframe(ecx_portt *port, int idx, int stacknumber) +{ + uint16 l; + int rval; + uint8 idxf; + ec_etherheadert *ehp; + ec_comt *ecp; + ec_stackT *stack; + ec_bufT *rxbuf; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + rval = EC_NOFRAME; + rxbuf = &(*stack->rxbuf)[idx]; + /* check if requested index is already in buffer ? */ + if ((idx < EC_MAXBUF) && ( (*stack->rxbufstat)[idx] == EC_BUF_RCVD)) + { + l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + } + else + { + mtx_lock (port->rx_mutex); + /* non blocking call to retrieve frame from socket */ + if (ecx_recvpkt(port, stacknumber)) + { + rval = EC_OTHERFRAME; + ehp =(ec_etherheadert*)(stack->tempbuf); + /* check if it is an EtherCAT frame */ + if (ehp->etype == oshw_htons(ETH_P_ECAT)) + { + ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]); + l = etohs(ecp->elength) & 0x0fff; + idxf = ecp->index; + /* found index equals reqested index ? */ + if (idxf == idx) + { + /* yes, put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + /* store MAC source word 1 for redundant routing info */ + (*stack->rxsa)[idx] = oshw_ntohs(ehp->sa1); + } + else + { + /* check if index exist? */ + if (idxf < EC_MAXBUF) + { + rxbuf = &(*stack->rxbuf)[idxf]; + /* put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE); + /* mark as received */ + (*stack->rxbufstat)[idxf] = EC_BUF_RCVD; + (*stack->rxsa)[idxf] = oshw_ntohs(ehp->sa1); + } + else + { + /* strange things happend */ + } + } + } + } + mtx_unlock (port->rx_mutex); + + } + + /* WKC if mathing frame found */ + return rval; +} + +/** Blocking redundant receive frame function. If redundant mode is not active then + * it skips the secondary stack and redundancy functions. In redundant mode it waits + * for both (primary and secondary) frames to come in. The result goes in an decision + * tree that decides, depending on the route of the packet and its possible missing arrival, + * how to reroute the original packet to get the data in an other try. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] timer = absolute timeout time + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert timer) +{ + int wkc = EC_NOFRAME; + int wkc2 = EC_NOFRAME; + int primrx, secrx; + + /* if not in redundant mode then always assume secondary is OK */ + if (port->redstate == ECT_RED_NONE) + { + wkc2 = 0; + } + do + { + /* only read frame if not already in */ + if (wkc <= EC_NOFRAME) + { + wkc = ecx_inframe(port, idx, 0); + } + /* only try secondary if in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* only read frame if not already in */ + if (wkc2 <= EC_NOFRAME) + wkc2 = ecx_inframe(port, idx, 1); + } + /* wait for both frames to arrive or timeout */ + } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && (osal_timer_is_expired(&timer) == FALSE)); + /* only do redundant functions when in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* primrx if the reveived MAC source on primary socket */ + primrx = 0; + if (wkc > EC_NOFRAME) + { + primrx = port->rxsa[idx]; + } + /* secrx if the reveived MAC source on psecondary socket */ + secrx = 0; + if (wkc2 > EC_NOFRAME) + { + secrx = port->redport->rxsa[idx]; + } + /* primary socket got secondary frame and secondary socket got primary frame */ + /* normal situation in redundant mode */ + if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) ) + { + /* copy secondary buffer to primary */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + /* primary socket got nothing or primary frame, and secondary socket got secondary frame */ + /* we need to resend TX packet */ + if ( ((primrx == 0) && (secrx == RX_SEC)) || + ((primrx == RX_PRIM) && (secrx == RX_SEC)) ) + { + osal_timert read_timer; + + /* If both primary and secondary have partial connection retransmit the primary received + * frame over the secondary socket. The result from the secondary received frame is a combined + * frame that traversed all slaves in standard order. */ + if ( (primrx == RX_PRIM) && (secrx == RX_SEC) ) + { + /* copy primary rx to tx buffer */ + memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + } + osal_timer_start(&read_timer, EC_TIMEOUTRET); + /* resend secondary tx */ + ecx_outframe(port, idx, 1); + do + { + /* retrieve frame */ + wkc2 = ecx_inframe(port, idx, 1); + } while ((wkc2 <= EC_NOFRAME) && (osal_timer_is_expired(&read_timer) == FALSE)); + if (wkc2 > EC_NOFRAME) + { + /* copy secondary result to primary rx buffer */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + } + } + + /* return WKC or EC_NOFRAME */ + return wkc; +} + +/** Blocking receive frame function. Calls ec_waitinframe_red(). + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] timeout = timeout in us + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +int ecx_waitinframe(ecx_portt *port, int idx, int timeout) +{ + int wkc; + osal_timert timer; + + osal_timer_start (&timer, timeout); + wkc = ecx_waitinframe_red(port, idx, timer); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + } + + return wkc; +} + +/** Blocking send and recieve frame function. Used for non processdata frames. + * A datagram is build into a frame and transmitted via this function. It waits + * for an answer and returns the workcounter. The function retries if time is + * left and the result is WKC=0 or no frame received. + * + * The function calls ec_outframe_red() and ec_waitinframe_red(). + * + * @param[in] port = port context struct + * @param[in] idx = index of frame + * @param[in] timeout = timeout in us + * @return Workcounter or EC_NOFRAME + */ +int ecx_srconfirm(ecx_portt *port, int idx, int timeout) +{ + int wkc = EC_NOFRAME; + osal_timert timer; + + osal_timer_start(&timer, timeout); + do + { + osal_timert read_timer; + + /* tx frame on primary and if in redundant mode a dummy on secondary */ + ecx_outframe_red(port, idx); + osal_timer_start(&read_timer, MIN(timeout, EC_TIMEOUTRET)); + /* get frame from primary or if in redundant mode possibly from secondary */ + wkc = ecx_waitinframe_red(port, idx, read_timer); + /* wait for answer with WKC>0 or otherwise retry until timeout */ + } while ((wkc <= EC_NOFRAME) && (osal_timer_is_expired(&timer) == FALSE)); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + } + + return wkc; +} + + +#ifdef EC_VER1 +int ec_setupnic(const char *ifname, int secondary) +{ + return ecx_setupnic(&ecx_port, ifname, secondary); +} + +int ec_closenic(void) +{ + return ecx_closenic(&ecx_port); +} + +int ec_getindex(void) +{ + return ecx_getindex(&ecx_port); +} + +void ec_setbufstat(int idx, int bufstat) +{ + ecx_setbufstat(&ecx_port, idx, bufstat); +} + +int ec_outframe(int idx, int stacknumber) +{ + return ecx_outframe(&ecx_port, idx, stacknumber); +} + +int ec_outframe_red(int idx) +{ + return ecx_outframe_red(&ecx_port, idx); +} + +int ec_inframe(int idx, int stacknumber) +{ + return ecx_inframe(&ecx_port, idx, stacknumber); +} + +int ec_waitinframe(int idx, int timeout) +{ + return ecx_waitinframe(&ecx_port, idx, timeout); +} + +int ec_srconfirm(int idx, int timeout) +{ + return ecx_srconfirm(&ecx_port, idx, timeout); +} +#endif + diff --git a/oshw/rtk/nicdrv.h b/oshw/rtk/nicdrv.h new file mode 100644 index 0000000..0a23a28 --- /dev/null +++ b/oshw/rtk/nicdrv.h @@ -0,0 +1,144 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for nicdrv.c + */ + +#ifndef _nicdrvh_ +#define _nicdrvh_ + +/** pointer structure to Tx and Rx stacks */ +typedef struct +{ + /** socket connection used */ + int *sock; + /** tx buffer */ + ec_bufT (*txbuf)[EC_MAXBUF]; + /** tx buffer lengths */ + int (*txbuflength)[EC_MAXBUF]; + /** temporary receive buffer */ + ec_bufT *tempbuf; + /** rx buffers */ + ec_bufT (*rxbuf)[EC_MAXBUF]; + /** rx buffer status fields */ + int (*rxbufstat)[EC_MAXBUF]; + /** received MAC source address (middle word) */ + int (*rxsa)[EC_MAXBUF]; +} ec_stackT; + +/** pointer structure to buffers for redundant port */ +typedef struct +{ + ec_stackT stack; + int sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; +} ecx_redportt; + +/** pointer structure to buffers, vars and mutexes for port instantiation */ +typedef struct +{ + ec_stackT stack; + int sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; + /** temporary rx buffer status */ + int tempinbufs; + /** transmit buffers */ + ec_bufT txbuf[EC_MAXBUF]; + /** transmit buffer lenghts */ + int txbuflength[EC_MAXBUF]; + /** temporary tx buffer */ + ec_bufT txbuf2; + /** temporary tx buffer length */ + int txbuflength2; + /** last used frame index */ + int lastidx; + /** current redundancy state */ + int redstate; + /** pointer to redundancy port and buffers */ + ecx_redportt *redport; + mtx_t * getindex_mutex; + mtx_t * tx_mutex; + mtx_t * rx_mutex; +} ecx_portt; + +extern const uint16 priMAC[3]; +extern const uint16 secMAC[3]; + +#ifdef EC_VER1 +extern ecx_portt ecx_port; +extern ecx_redportt ecx_redport; + +int ec_setupnic(const char * ifname, int secondary); +int ec_closenic(void); +void ec_setbufstat(int idx, int bufstat); +int ec_getindex(void); +int ec_outframe(int idx, int stacknumber); +int ec_outframe_red(int idx); +int ec_waitinframe(int idx, int timeout); +int ec_srconfirm(int idx,int timeout); +#endif + +void ec_setupheader(void *p); +int ecx_setupnic(ecx_portt *port, const char * ifname, int secondary); +int ecx_closenic(ecx_portt *port); +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat); +int ecx_getindex(ecx_portt *port); +int ecx_outframe(ecx_portt *port, int idx, int stacknumber); +int ecx_outframe_red(ecx_portt *port, int idx); +int ecx_waitinframe(ecx_portt *port, int idx, int timeout); +int ecx_srconfirm(ecx_portt *port, int idx,int timeout); + +#endif diff --git a/oshw/rtk/oshw.c b/oshw/rtk/oshw.c new file mode 100644 index 0000000..58489f6 --- /dev/null +++ b/oshw/rtk/oshw.c @@ -0,0 +1,68 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: oshw.c 411 2012-12-02 20:16:39Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#include "oshw.h" +#include +#include + +/** + * Host to Network byte order (i.e. to big endian). + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_htons(const uint16 host) +{ + uint16 network = htons (host); + return network; +} + +/** + * Network (i.e. big endian) to Host byte order. + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_ntohs(const uint16 network) +{ + uint16 host = ntohs (network); + return host; +} + +/* Create list over available network adapters. + * @return First element in linked list of adapters + */ +ec_adaptert * oshw_find_adapters(void) +{ + ec_adaptert * ret_adapter = NULL; + + /* TODO if needed */ + + return ret_adapter; +} + +/** Free memory allocated memory used by adapter collection. + * @param[in] adapter = First element in linked list of adapters + * EC_NOFRAME. + */ +void oshw_free_adapters(ec_adaptert * adapter) +{ + /* TODO if needed */ +} diff --git a/oshw/rtk/oshw.h b/oshw/rtk/oshw.h new file mode 100644 index 0000000..fff5475 --- /dev/null +++ b/oshw/rtk/oshw.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + */ + +/** \file + * \brief + * Headerfile for oshw.c + */ + +#ifndef _oshw_ +#define _oshw_ + + +#include +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatmain.h" + + +uint16 oshw_htons(uint16 host); +uint16 oshw_ntohs(uint16 network); + +ec_adaptert * oshw_find_adapters(void); +void oshw_free_adapters(ec_adaptert * adapter); + +#endif diff --git a/oshw/win32/Makefile b/oshw/win32/Makefile new file mode 100644 index 0000000..1ee40f6 --- /dev/null +++ b/oshw/win32/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = oshw +include $(PRJ_ROOT)/make/lib.mk diff --git a/oshw/win32/nicdrv.c b/oshw/win32/nicdrv.c new file mode 100644 index 0000000..624a3aa --- /dev/null +++ b/oshw/win32/nicdrv.c @@ -0,0 +1,687 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * EtherCAT RAW socket driver. + * + * Low level interface functions to send and receive EtherCAT packets. + * EtherCAT has the property that packets are only send by the master, + * and the send packets allways return in the receive buffer. + * There can be multiple packets "on the wire" before they return. + * To combine the received packets with the original send packets a buffer + * system is installed. The identifier is put in the index item of the + * EtherCAT header. The index is stored and compared when a frame is recieved. + * If there is a match the packet can be combined with the transmit packet + * and returned to the higher level function. + * + * The socket layer can exhibit a reversal in the packet order (rare). + * If the Tx order is A-B-C the return order could be A-C-B. The indexed buffer + * will reorder the packets automatically. + * + * The "redundant" option will configure two sockets and two NIC interfaces. + * Slaves are connected to both interfaces, one on the IN port and one on the + * OUT port. Packets are send via both interfaces. Any one of the connections + * (also an interconnect) can be removed and the slaves are still serviced with + * packets. The software layer will detect the possible failure modes and + * compensate. If needed the packets from interface A are resend through interface B. + * This layer is fully transparent for the higher layers. + */ + +#ifdef WIN32 + + +#include +#include +#include +#include + +#include +#include "ethercattype.h" +#include +#include "nicdrv.h" +#include "osal_win32.h" + +#endif + +/** Redundancy modes */ +enum +{ + /** No redundancy, single NIC mode */ + ECT_RED_NONE, + /** Double redundant NIC connecetion */ + ECT_RED_DOUBLE +}; + +/** Primary source MAC address used for EtherCAT. + * This address is not the MAC address used from the NIC. + * EtherCAT does not care about MAC addressing, but it is used here to + * differentiate the route the packet traverses through the EtherCAT + * segment. This is needed to fund out the packet flow in redundant + * confihurations. */ +const uint16 priMAC[3] = { 0x0101, 0x0101, 0x0101 }; +/** Secondary source MAC address used for EtherCAT. */ +const uint16 secMAC[3] = { 0x0404, 0x0404, 0x0404 }; + +/** second MAC word is used for identification */ +#define RX_PRIM priMAC[1] +/** second MAC word is used for identification */ +#define RX_SEC secMAC[1] + +static char errbuf[PCAP_ERRBUF_SIZE]; + +static void ecx_clear_rxbufstat(int *rxbufstat) +{ + int i; + for(i = 0; i < EC_MAXBUF; i++) + { + rxbufstat[i] = EC_BUF_EMPTY; + } +} + +/** Basic setup to connect NIC to socket. + * @param[in] port = port context struct + * @param[in] ifname = Name of NIC device, f.e. "eth0" + * @param[in] secondary = if >0 then use secondary stack instead of primary + * @return >0 if succeeded + */ +int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary) +{ + int i, rval; + pcap_t **psock; + + rval = 0; + if (secondary) + { + /* secondary port stuct available? */ + if (port->redport) + { + /* when using secondary socket it is automatically a redundant setup */ + psock = &(port->redport->sockhandle); + *psock = NULL; + port->redstate = ECT_RED_DOUBLE; + port->redport->stack.sock = &(port->redport->sockhandle); + port->redport->stack.txbuf = &(port->txbuf); + port->redport->stack.txbuflength = &(port->txbuflength); + port->redport->stack.tempbuf = &(port->redport->tempinbuf); + port->redport->stack.rxbuf = &(port->redport->rxbuf); + port->redport->stack.rxbufstat = &(port->redport->rxbufstat); + port->redport->stack.rxsa = &(port->redport->rxsa); + ecx_clear_rxbufstat(&(port->redport->rxbufstat[0])); + } + else + { + /* fail */ + return 0; + } + } + else + { + InitializeCriticalSection(&(port->getindex_mutex)); + InitializeCriticalSection(&(port->tx_mutex)); + InitializeCriticalSection(&(port->rx_mutex)); + port->sockhandle = NULL; + port->lastidx = 0; + port->redstate = ECT_RED_NONE; + port->stack.sock = &(port->sockhandle); + port->stack.txbuf = &(port->txbuf); + port->stack.txbuflength = &(port->txbuflength); + port->stack.tempbuf = &(port->tempinbuf); + port->stack.rxbuf = &(port->rxbuf); + port->stack.rxbufstat = &(port->rxbufstat); + port->stack.rxsa = &(port->rxsa); + ecx_clear_rxbufstat(&(port->rxbufstat[0])); + psock = &(port->sockhandle); + } + /* we use pcap socket to send RAW packets in windows user mode*/ + *psock = pcap_open(ifname, 65536, PCAP_OPENFLAG_PROMISCUOUS | + PCAP_OPENFLAG_MAX_RESPONSIVENESS | + PCAP_OPENFLAG_NOCAPTURE_LOCAL, -1, NULL , errbuf); + if (NULL == *psock) + { + printf("interface %s could not open with pcap\n", ifname); + return 0; + } + + for (i = 0; i < EC_MAXBUF; i++) + { + ec_setupheader(&(port->txbuf[i])); + port->rxbufstat[i] = EC_BUF_EMPTY; + } + ec_setupheader(&(port->txbuf2)); + + return 1; +} + +/** Close sockets used + * @param[in] port = port context struct + * @return 0 + */ +int ecx_closenic(ecx_portt *port) +{ + timeEndPeriod(15); + + if (port->sockhandle != NULL) + { + DeleteCriticalSection(&(port->getindex_mutex)); + DeleteCriticalSection(&(port->tx_mutex)); + DeleteCriticalSection(&(port->rx_mutex)); + pcap_close(port->sockhandle); + port->sockhandle = NULL; + } + if ((port->redport) && (port->redport->sockhandle != NULL)) + { + pcap_close(port->redport->sockhandle); + port->redport->sockhandle = NULL; + } + + return 0; +} + +/** Fill buffer with ethernet header structure. + * Destination MAC is allways broadcast. + * Ethertype is allways ETH_P_ECAT. + * @param[out] p = buffer + */ +void ec_setupheader(void *p) +{ + ec_etherheadert *bp; + bp = p; + bp->da0 = htons(0xffff); + bp->da1 = htons(0xffff); + bp->da2 = htons(0xffff); + bp->sa0 = htons(priMAC[0]); + bp->sa1 = htons(priMAC[1]); + bp->sa2 = htons(priMAC[2]); + bp->etype = htons(ETH_P_ECAT); +} + +/** Get new frame identifier index and allocate corresponding rx buffer. + * @param[in] port = port context struct + * @return new index. + */ +int ecx_getindex(ecx_portt *port) +{ + int idx; + int cnt; + + EnterCriticalSection(&(port->getindex_mutex)); + + idx = port->lastidx + 1; + /* index can't be larger than buffer array */ + if (idx >= EC_MAXBUF) + { + idx = 0; + } + cnt = 0; + /* try to find unused index */ + while ((port->rxbufstat[idx] != EC_BUF_EMPTY) && (cnt < EC_MAXBUF)) + { + idx++; + cnt++; + if (idx >= EC_MAXBUF) + { + idx = 0; + } + } + port->rxbufstat[idx] = EC_BUF_ALLOC; + if (port->redstate != ECT_RED_NONE) + port->redport->rxbufstat[idx] = EC_BUF_ALLOC; + port->lastidx = idx; + + LeaveCriticalSection(&(port->getindex_mutex)); + + return idx; +} + +/** Set rx buffer status. + * @param[in] port = port context struct + * @param[in] idx = index in buffer array + * @param[in] bufstat = status to set + */ +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat) +{ + port->rxbufstat[idx] = bufstat; + if (port->redstate != ECT_RED_NONE) + port->redport->rxbufstat[idx] = bufstat; +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @param[in] stacknumber = 0=Primary 1=Secondary stack + * @return socket send result + */ +int ecx_outframe(ecx_portt *port, int idx, int stacknumber) +{ + int lp, rval; + ec_stackT *stack; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = (*stack->txbuflength)[idx]; + rval = pcap_sendpacket(*stack->sock, (*stack->txbuf)[idx], lp); + (*stack->rxbufstat)[idx] = EC_BUF_TX; + + return rval; +} + +/** Transmit buffer over socket (non blocking). + * @param[in] port = port context struct + * @param[in] idx = index in tx buffer array + * @return socket send result + */ +int ecx_outframe_red(ecx_portt *port, int idx) +{ + ec_comt *datagramP; + ec_etherheadert *ehp; + int rval; + + ehp = (ec_etherheadert *)&(port->txbuf[idx]); + /* rewrite MAC source address 1 to primary */ + ehp->sa1 = htons(priMAC[1]); + /* transmit over primary socket*/ + rval = ecx_outframe(port, idx, 0); + if (port->redstate != ECT_RED_NONE) + { + EnterCriticalSection( &(port->tx_mutex) ); + ehp = (ec_etherheadert *)&(port->txbuf2); + /* use dummy frame for secondary socket transmit (BRD) */ + datagramP = (ec_comt*)&(port->txbuf2[ETH_HEADERSIZE]); + /* write index to frame */ + datagramP->index = idx; + /* rewrite MAC source address 1 to secondary */ + ehp->sa1 = htons(secMAC[1]); + /* transmit over secondary socket */ + pcap_sendpacket(port->redport->sockhandle, (u_char const *)&(port->txbuf2), port->txbuflength2); + LeaveCriticalSection( &(port->tx_mutex) ); + port->redport->rxbufstat[idx] = EC_BUF_TX; + } + + return rval; +} + +/** Non blocking read of socket. Put frame in temporary buffer. + * @param[in] port = port context struct + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return >0 if frame is available and read + */ +static int ecx_recvpkt(ecx_portt *port, int stacknumber) +{ + int lp, bytesrx; + ec_stackT *stack; + struct pcap_pkthdr * header; + unsigned char const * pkt_data; + int res; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + lp = sizeof(port->tempinbuf); + + res = pcap_next_ex(*stack->sock, &header, &pkt_data); + if (res <=0 ) + { + port->tempinbufs = 0; + return 0; + } + bytesrx = header->len; + if (bytesrx > lp) + { + bytesrx = lp; + } + memcpy(*stack->tempbuf, pkt_data, bytesrx); + port->tempinbufs = bytesrx; + return (bytesrx > 0); +} + +/** Non blocking receive frame function. Uses RX buffer and index to combine + * read frame with transmitted frame. To compensate for received frames that + * are out-of-order all frames are stored in their respective indexed buffer. + * If a frame was placed in the buffer previously, the function retreives it + * from that buffer index without calling ec_recvpkt. If the requested index + * is not already in the buffer it calls ec_recvpkt to fetch it. There are + * three options now, 1 no frame read, so exit. 2 frame read but other + * than requested index, store in buffer and exit. 3 frame read with matching + * index, store in buffer, set completed flag in buffer status and exit. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] stacknumber = 0=primary 1=secondary stack + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME or EC_OTHERFRAME. + */ +int ecx_inframe(ecx_portt *port, int idx, int stacknumber) +{ + uint16 l; + int rval; + int idxf; + ec_etherheadert *ehp; + ec_comt *ecp; + ec_stackT *stack; + ec_bufT *rxbuf; + + if (!stacknumber) + { + stack = &(port->stack); + } + else + { + stack = &(port->redport->stack); + } + rval = EC_NOFRAME; + rxbuf = &(*stack->rxbuf)[idx]; + /* check if requested index is already in buffer ? */ + if ((idx < EC_MAXBUF) && ((*stack->rxbufstat)[idx] == EC_BUF_RCVD)) + { + l = (*rxbuf)[0] + ((uint16)((*rxbuf)[1] & 0x0f) << 8); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)(*rxbuf)[l + 1] << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + } + else + { + EnterCriticalSection(&(port->rx_mutex)); + /* non blocking call to retrieve frame from socket */ + if (ecx_recvpkt(port, stacknumber)) + { + rval = EC_OTHERFRAME; + ehp =(ec_etherheadert*)(stack->tempbuf); + /* check if it is an EtherCAT frame */ + if (ehp->etype == htons(ETH_P_ECAT)) + { + ecp =(ec_comt*)(&(*stack->tempbuf)[ETH_HEADERSIZE]); + l = etohs(ecp->elength) & 0x0fff; + idxf = ecp->index; + /* found index equals reqested index ? */ + if (idxf == idx) + { + /* yes, put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idx] - ETH_HEADERSIZE); + /* return WKC */ + rval = ((*rxbuf)[l] + ((uint16)((*rxbuf)[l + 1]) << 8)); + /* mark as completed */ + (*stack->rxbufstat)[idx] = EC_BUF_COMPLETE; + /* store MAC source word 1 for redundant routing info */ + (*stack->rxsa)[idx] = ntohs(ehp->sa1); + } + else + { + /* check if index exist? */ + if (idxf < EC_MAXBUF) + { + rxbuf = &(*stack->rxbuf)[idxf]; + /* put it in the buffer array (strip ethernet header) */ + memcpy(rxbuf, &(*stack->tempbuf)[ETH_HEADERSIZE], (*stack->txbuflength)[idxf] - ETH_HEADERSIZE); + /* mark as received */ + (*stack->rxbufstat)[idxf] = EC_BUF_RCVD; + (*stack->rxsa)[idxf] = ntohs(ehp->sa1); + } + else + { + /* strange things happend */ + } + } + } + } + LeaveCriticalSection( &(port->rx_mutex) ); + + } + + /* WKC if mathing frame found */ + return rval; +} + +/** Blocking redundant receive frame function. If redundant mode is not active then + * it skips the secondary stack and redundancy functions. In redundant mode it waits + * for both (primary and secondary) frames to come in. The result goes in an decision + * tree that decides, depending on the route of the packet and its possible missing arrival, + * how to reroute the original packet to get the data in an other try. + * + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] tvs = timeout + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +static int ecx_waitinframe_red(ecx_portt *port, int idx, osal_timert *timer) +{ + osal_timert timer2; + int wkc = EC_NOFRAME; + int wkc2 = EC_NOFRAME; + int primrx, secrx; + + /* if not in redundant mode then always assume secondary is OK */ + if (port->redstate == ECT_RED_NONE) + wkc2 = 0; + do + { + /* only read frame if not already in */ + if (wkc <= EC_NOFRAME) + wkc = ecx_inframe(port, idx, 0); + /* only try secondary if in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* only read frame if not already in */ + if (wkc2 <= EC_NOFRAME) + wkc2 = ecx_inframe(port, idx, 1); + } + /* wait for both frames to arrive or timeout */ + } while (((wkc <= EC_NOFRAME) || (wkc2 <= EC_NOFRAME)) && !osal_timer_is_expired(timer)); + /* only do redundant functions when in redundant mode */ + if (port->redstate != ECT_RED_NONE) + { + /* primrx if the reveived MAC source on primary socket */ + primrx = 0; + if (wkc > EC_NOFRAME) primrx = port->rxsa[idx]; + /* secrx if the reveived MAC source on psecondary socket */ + secrx = 0; + if (wkc2 > EC_NOFRAME) secrx = port->redport->rxsa[idx]; + + /* primary socket got secondary frame and secondary socket got primary frame */ + /* normal situation in redundant mode */ + if ( ((primrx == RX_SEC) && (secrx == RX_PRIM)) ) + { + /* copy secondary buffer to primary */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + /* primary socket got nothing or primary frame, and secondary socket got secondary frame */ + /* we need to resend TX packet */ + if ( ((primrx == 0) && (secrx == RX_SEC)) || + ((primrx == RX_PRIM) && (secrx == RX_SEC)) ) + { + /* If both primary and secondary have partial connection retransmit the primary received + * frame over the secondary socket. The result from the secondary received frame is a combined + * frame that traversed all slaves in standard order. */ + if ( (primrx == RX_PRIM) && (secrx == RX_SEC) ) + { + /* copy primary rx to tx buffer */ + memcpy(&(port->txbuf[idx][ETH_HEADERSIZE]), &(port->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + } + osal_timer_start (&timer2, EC_TIMEOUTRET); + /* resend secondary tx */ + ecx_outframe(port, idx, 1); + do + { + /* retrieve frame */ + wkc2 = ecx_inframe(port, idx, 1); + } while ((wkc2 <= EC_NOFRAME) && !osal_timer_is_expired(&timer2)); + if (wkc2 > EC_NOFRAME) + { + /* copy secondary result to primary rx buffer */ + memcpy(&(port->rxbuf[idx]), &(port->redport->rxbuf[idx]), port->txbuflength[idx] - ETH_HEADERSIZE); + wkc = wkc2; + } + } + } + + /* return WKC or EC_NOFRAME */ + return wkc; +} + +/** Blocking receive frame function. Calls ec_waitinframe_red(). + * @param[in] port = port context struct + * @param[in] idx = requested index of frame + * @param[in] timeout = timeout in us + * @return Workcounter if a frame is found with corresponding index, otherwise + * EC_NOFRAME. + */ +int ecx_waitinframe(ecx_portt *port, int idx, int timeout) +{ + int wkc; + osal_timert timer; + + osal_timer_start (&timer, timeout); + wkc = ecx_waitinframe_red(port, idx, &timer); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ec_setbufstat(idx, EC_BUF_EMPTY); + } + + return wkc; +} + +/** Blocking send and recieve frame function. Used for non processdata frames. + * A datagram is build into a frame and transmitted via this function. It waits + * for an answer and returns the workcounter. The function retries if time is + * left and the result is WKC=0 or no frame received. + * + * The function calls ec_outframe_red() and ec_waitinframe_red(). + * + * @param[in] port = port context struct + * @param[in] idx = index of frame + * @param[in] timeout = timeout in us + * @return Workcounter or EC_NOFRAME + */ +int ecx_srconfirm(ecx_portt *port, int idx, int timeout) +{ + int wkc = EC_NOFRAME; + osal_timert timer1, timer2; + + osal_timer_start (&timer1, timeout); + do + { + /* tx frame on primary and if in redundant mode a dummy on secondary */ + ecx_outframe_red(port, idx); + if (timeout < EC_TIMEOUTRET) + { + osal_timer_start (&timer2, timeout); + } + else + { + /* normally use partial timout for rx */ + osal_timer_start (&timer2, EC_TIMEOUTRET); + } + /* get frame from primary or if in redundant mode possibly from secondary */ + wkc = ecx_waitinframe_red(port, idx, &timer2); + /* wait for answer with WKC>=0 or otherwise retry until timeout */ + } while ((wkc <= EC_NOFRAME) && !osal_timer_is_expired (&timer1)); + /* if nothing received, clear buffer index status so it can be used again */ + if (wkc <= EC_NOFRAME) + { + ec_setbufstat(idx, EC_BUF_EMPTY); + } + + return wkc; +} + + +#ifdef EC_VER1 + +int ec_setupnic(const char *ifname, int secondary) +{ + return ecx_setupnic(&ecx_port, ifname, secondary); +} + +int ec_closenic(void) +{ + return ecx_closenic(&ecx_port); +} + +int ec_getindex(void) +{ + return ecx_getindex(&ecx_port); +} + +void ec_setbufstat(int idx, int bufstat) +{ + ecx_setbufstat(&ecx_port, idx, bufstat); +} + +int ec_outframe(int idx, int stacknumber) +{ + return ecx_outframe(&ecx_port, idx, stacknumber); +} + +int ec_outframe_red(int idx) +{ + return ecx_outframe_red(&ecx_port, idx); +} + +int ec_inframe(int idx, int stacknumber) +{ + return ecx_inframe(&ecx_port, idx, stacknumber); +} + +int ec_waitinframe(int idx, int timeout) +{ + return ecx_waitinframe(&ecx_port, idx, timeout); +} + +int ec_srconfirm(int idx, int timeout) +{ + return ecx_srconfirm(&ecx_port, idx, timeout); +} + +#endif diff --git a/oshw/win32/nicdrv.h b/oshw/win32/nicdrv.h new file mode 100644 index 0000000..5679bee --- /dev/null +++ b/oshw/win32/nicdrv.h @@ -0,0 +1,158 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : nicdrv.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for nicdrv.c + */ + +#ifndef _nicdrvh_ +#define _nicdrvh_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define HAVE_REMOTE + +#include +#include + +/** pointer structure to Tx and Rx stacks */ +typedef struct +{ + /** socket connection used */ + pcap_t **sock; + /** tx buffer */ + ec_bufT (*txbuf)[EC_MAXBUF]; + /** tx buffer lengths */ + int (*txbuflength)[EC_MAXBUF]; + /** temporary receive buffer */ + ec_bufT *tempbuf; + /** rx buffers */ + ec_bufT (*rxbuf)[EC_MAXBUF]; + /** rx buffer status fields */ + int (*rxbufstat)[EC_MAXBUF]; + /** received MAC source address (middle word) */ + int (*rxsa)[EC_MAXBUF]; +} ec_stackT; + +/** pointer structure to buffers for redundant port */ +typedef struct +{ + ec_stackT stack; + pcap_t *sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; +} ecx_redportt; + +/** pointer structure to buffers, vars and mutexes for port instantiation */ +typedef struct +{ + ec_stackT stack; + pcap_t *sockhandle; + /** rx buffers */ + ec_bufT rxbuf[EC_MAXBUF]; + /** rx buffer status */ + int rxbufstat[EC_MAXBUF]; + /** rx MAC source address */ + int rxsa[EC_MAXBUF]; + /** temporary rx buffer */ + ec_bufT tempinbuf; + /** temporary rx buffer status */ + int tempinbufs; + /** transmit buffers */ + ec_bufT txbuf[EC_MAXBUF]; + /** transmit buffer lenghts */ + int txbuflength[EC_MAXBUF]; + /** temporary tx buffer */ + ec_bufT txbuf2; + /** temporary tx buffer length */ + int txbuflength2; + /** last used frame index */ + int lastidx; + /** current redundancy state */ + int redstate; + /** pointer to redundancy port and buffers */ + ecx_redportt *redport; + CRITICAL_SECTION getindex_mutex; + CRITICAL_SECTION tx_mutex; + CRITICAL_SECTION rx_mutex; +} ecx_portt; + +extern const uint16 priMAC[3]; +extern const uint16 secMAC[3]; + +#ifdef EC_VER1 +extern ecx_portt ecx_port; +extern ecx_redportt ecx_redport; + +int ec_setupnic(const char * ifname, int secondary); +int ec_closenic(void); +void ec_setbufstat(int idx, int bufstat); +int ec_getindex(void); +int ec_outframe(int idx, int sock); +int ec_outframe_red(int idx); +int ec_waitinframe(int idx, int timeout); +int ec_srconfirm(int idx,int timeout); +#endif + +void ec_setupheader(void *p); +int ecx_setupnic(ecx_portt *port, const char * ifname, int secondary); +int ecx_closenic(ecx_portt *port); +void ecx_setbufstat(ecx_portt *port, int idx, int bufstat); +int ecx_getindex(ecx_portt *port); +int ecx_outframe(ecx_portt *port, int idx, int sock); +int ecx_outframe_red(ecx_portt *port, int idx); +int ecx_waitinframe(ecx_portt *port, int idx, int timeout); +int ecx_srconfirm(ecx_portt *port, int idx,int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oshw/win32/oshw.c b/oshw/win32/oshw.c new file mode 100644 index 0000000..388bc2b --- /dev/null +++ b/oshw/win32/oshw.c @@ -0,0 +1,147 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: oshw.c 411 2012-12-02 20:16:39Z rtlaka $ + *------------------------------------------------------------------------------ + */ + +#include "oshw.h" + +/** + * Host to Network byte order (i.e. to big endian). + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_htons (uint16 host) +{ + uint16 network = htons (host); + return network; +} + +/** + * Network (i.e. big endian) to Host byte order. + * + * Note that Ethercat uses little endian byte order, except for the Ethernet + * header which is big endian as usual. + */ +uint16 oshw_ntohs (uint16 network) +{ + uint16 host = ntohs (network); + return host; +} + +/* Create list over available network adapters. + * @return First element in linked list of adapters + */ +ec_adaptert * oshw_find_adapters (void) +{ + int i = 0; + int ret = 0; + pcap_if_t *alldevs; + pcap_if_t *d; + ec_adaptert * adapter; + ec_adaptert * prev_adapter; + ec_adaptert * ret_adapter = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + size_t string_len; + + /* find all devices */ + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); + return (NULL); + } + /* Iterate all devices and create a local copy holding the name and + * decsription. + */ + for(d= alldevs; d != NULL; d= d->next) + { + adapter = (ec_adaptert *)malloc(sizeof(ec_adaptert)); + /* If we got more than one adapter save link list pointer to previous + * adapter. + * Else save as pointer to return. + */ + if (i) + { + prev_adapter->next = adapter; + } + else + { + ret_adapter = adapter; + } + + /* fetch description and name of the divice from libpcap */ + adapter->next = NULL; + if (d->name) + { + string_len = strlen(d->name); + if (string_len > (EC_MAXLEN_ADAPTERNAME - 1)) + { + string_len = EC_MAXLEN_ADAPTERNAME - 1; + } + strncpy(adapter->name, d->name,string_len); + adapter->name[string_len] = '\0'; + } + else + { + adapter->name[0] = '\0'; + } + if (d->description) + { + string_len = strlen(d->description); + if (string_len > (EC_MAXLEN_ADAPTERNAME - 1)) + { + string_len = EC_MAXLEN_ADAPTERNAME - 1; + } + strncpy(adapter->desc, d->description,string_len); + adapter->desc[string_len] = '\0'; + } + else + { + adapter->desc[0] = '\0'; + } + prev_adapter = adapter; + i++; + } + /* free all devices allocated */ + pcap_freealldevs(alldevs); + + return ret_adapter; +} + +/** Free memory allocated memory used by adapter collection. + * @param[in] adapter = First element in linked list of adapters + * EC_NOFRAME. + */ +void oshw_free_adapters (ec_adaptert * adapter) +{ + ec_adaptert * next_adapter; + /* Iterate the linked list and free all elemnts holding + * adapter information + */ + if(adapter) + { + next_adapter = adapter->next; + free (adapter); + while (next_adapter) + { + adapter = next_adapter; + next_adapter = adapter->next; + free (adapter); + } + } +} \ No newline at end of file diff --git a/oshw/win32/oshw.h b/oshw/win32/oshw.h new file mode 100644 index 0000000..81a7879 --- /dev/null +++ b/oshw/win32/oshw.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * * *** *** + * *** *** *** + * *** **** ********** *** ***** *** **** ***** + * ********* ********** *** ********* ************ ********* + * **** *** *** *** *** **** *** + * *** *** ****** *** *********** *** **** ***** + * *** *** ****** *** ************* *** **** ***** + * *** **** **** *** *** *** **** *** + * *** ******* ***** ************** ************* ********* + * *** ***** *** ******* ** ** ****** ***** + * t h e r e a l t i m e t a r g e t e x p e r t s + * + * http://www.rt-labs.com + * Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. + *------------------------------------------------------------------------------ + * $Id: oshw.h 452 2013-02-26 21:02:58Z smf.arthur $ + *------------------------------------------------------------------------------ + */ + +/** \file + * \brief + * Headerfile for ethercatbase.c + */ + +#ifndef _oshw_ +#define _oshw_ + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatmain.h" + +uint16 oshw_htons (uint16 hostshort); +uint16 oshw_ntohs (uint16 networkshort); +ec_adaptert * oshw_find_adapters (void); +void oshw_free_adapters (ec_adaptert * adapter); + +#endif diff --git a/oshw/win32/wpcap/Include/Packet32.h b/oshw/win32/wpcap/Include/Packet32.h new file mode 100644 index 0000000..64be055 --- /dev/null +++ b/oshw/win32/wpcap/Include/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * 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. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/oshw/win32/wpcap/Include/Win32-Extensions.h b/oshw/win32/wpcap/Include/Win32-Extensions.h new file mode 100644 index 0000000..ad3be25 --- /dev/null +++ b/oshw/win32/wpcap/Include/Win32-Extensions.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * 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. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/oshw/win32/wpcap/Include/bittypes.h b/oshw/win32/wpcap/Include/bittypes.h new file mode 100644 index 0000000..558a0b5 --- /dev/null +++ b/oshw/win32/wpcap/Include/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * All rights reserved. + * + * 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. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/oshw/win32/wpcap/Include/ip6_misc.h b/oshw/win32/wpcap/Include/ip6_misc.h new file mode 100644 index 0000000..562fa61 --- /dev/null +++ b/oshw/win32/wpcap/Include/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/oshw/win32/wpcap/Include/pcap-bpf.h b/oshw/win32/wpcap/Include/pcap-bpf.h new file mode 100644 index 0000000..5fe129d --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/oshw/win32/wpcap/Include/pcap-namedb.h b/oshw/win32/wpcap/Include/pcap-namedb.h new file mode 100644 index 0000000..80a2f00 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/oshw/win32/wpcap/Include/pcap-stdinc.h b/oshw/win32/wpcap/Include/pcap-stdinc.h new file mode 100644 index 0000000..4176041 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * All rights reserved. + * + * 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. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/oshw/win32/wpcap/Include/pcap.h b/oshw/win32/wpcap/Include/pcap.h new file mode 100644 index 0000000..935f949 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/oshw/win32/wpcap/Include/pcap/bluetooth.h b/oshw/win32/wpcap/Include/pcap/bluetooth.h new file mode 100644 index 0000000..7bf65df --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * 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 the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/bpf.h b/oshw/win32/wpcap/Include/pcap/bpf.h new file mode 100644 index 0000000..9f4ca33 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/namedb.h b/oshw/win32/wpcap/Include/pcap/namedb.h new file mode 100644 index 0000000..9002c75 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/pcap.h b/oshw/win32/wpcap/Include/pcap/pcap.h new file mode 100644 index 0000000..ad8fc40 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/sll.h b/oshw/win32/wpcap/Include/pcap/sll.h new file mode 100644 index 0000000..e9d5452 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/usb.h b/oshw/win32/wpcap/Include/pcap/usb.h new file mode 100644 index 0000000..adcd19c --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * 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 the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/oshw/win32/wpcap/Include/pcap/vlan.h b/oshw/win32/wpcap/Include/pcap/vlan.h new file mode 100644 index 0000000..b0cb794 --- /dev/null +++ b/oshw/win32/wpcap/Include/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/oshw/win32/wpcap/Include/remote-ext.h b/oshw/win32/wpcap/Include/remote-ext.h new file mode 100644 index 0000000..35a2fff --- /dev/null +++ b/oshw/win32/wpcap/Include/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * 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. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/oshw/win32/wpcap/Lib/Packet.lib b/oshw/win32/wpcap/Lib/Packet.lib new file mode 100644 index 0000000..81618bc Binary files /dev/null and b/oshw/win32/wpcap/Lib/Packet.lib differ diff --git a/oshw/win32/wpcap/Lib/libpacket.a b/oshw/win32/wpcap/Lib/libpacket.a new file mode 100644 index 0000000..4d49131 Binary files /dev/null and b/oshw/win32/wpcap/Lib/libpacket.a differ diff --git a/oshw/win32/wpcap/Lib/libwpcap.a b/oshw/win32/wpcap/Lib/libwpcap.a new file mode 100644 index 0000000..65b1870 Binary files /dev/null and b/oshw/win32/wpcap/Lib/libwpcap.a differ diff --git a/oshw/win32/wpcap/Lib/wpcap.lib b/oshw/win32/wpcap/Lib/wpcap.lib new file mode 100644 index 0000000..f832e04 Binary files /dev/null and b/oshw/win32/wpcap/Lib/wpcap.lib differ diff --git a/oshw/win32/wpcap/Lib/x64/Packet.lib b/oshw/win32/wpcap/Lib/x64/Packet.lib new file mode 100644 index 0000000..30c1540 Binary files /dev/null and b/oshw/win32/wpcap/Lib/x64/Packet.lib differ diff --git a/oshw/win32/wpcap/Lib/x64/wpcap.lib b/oshw/win32/wpcap/Lib/x64/wpcap.lib new file mode 100644 index 0000000..d5559f8 Binary files /dev/null and b/oshw/win32/wpcap/Lib/x64/wpcap.lib differ diff --git a/setup.sh b/setup.sh new file mode 100644 index 0000000..5644173 --- /dev/null +++ b/setup.sh @@ -0,0 +1,62 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2007. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: setup.sh 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +arch=$1 +bsp=$2 + +case $arch in + +arm9e|lpc21xx|lpc23xx|lpc31xx|lpc32xx|at91|stm32|omapl1xx|efm32| \ + imx53|kinetis|imx28|am37xx|lpc17xx) + export CROSS_GCC=arm-eabi + ;; + bfin) + export CROSS_GCC=bfin-elf + ;; + ppc604) + export CROSS_GCC=powerpc-eabi + ;; + mpc55xx|mpc551x) + export CROSS_GCC=powerpc-eabispe + ;; + linux) + bsp=$arch + export CROSS_GCC=linux + ;; + win32) + ;; + + *) + echo "Unknown architecture $arch" + ;; +esac + +export PRJ_ROOT=`pwd` +if [ "$arch" == "linux" ]; then +export GCC_PATH=${COMPILERS:-/usr/bin} +else +export GCC_PATH=${COMPILERS:-/opt/rt-tools/compilers}/$CROSS_GCC +fi +export ARCH=$arch +export BSP=$bsp + +# Set path for binaries +export PATH=$GCC_PATH/bin:$PATH + + diff --git a/soem/Makefile b/soem/Makefile new file mode 100644 index 0000000..1e4e2c7 --- /dev/null +++ b/soem/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2009. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 126 2012-04-01 17:40:22Z rtlaka $ +#------------------------------------------------------------------------------ + +LIBNAME = soem +include $(PRJ_ROOT)/make/lib.mk diff --git a/soem/ecat.c b/soem/ecat.c new file mode 100644 index 0000000..04aa38e --- /dev/null +++ b/soem/ecat.c @@ -0,0 +1,654 @@ + +#include "ecat.h" +#include +#include +#include + +ecat_net_t * ecat_net_init(char * ifname) +{ + /* allocate memory */ + ecat_net_t * net = calloc (1, sizeof(ecat_net_t)); + if (!net) + { + printf ("[%s] Could not allocate memory for ecat_net_t\n", ifname); + return NULL; + } + + /* TODO: fix */ + net->ifname = strdup (ifname); + net->ctx.port = calloc (1, sizeof(ecx_portt)); + net->ctx.slavelist = calloc (1, sizeof(ec_slavet) * EC_MAXSLAVE); + net->ctx.slavecount = calloc (1, sizeof(int)); + net->ctx.grouplist = calloc (1, sizeof(ec_groupt) * EC_MAXGROUP); + net->ctx.esibuf = calloc (1, sizeof(uint8) * EC_MAXEEPBUF); + net->ctx.esimap = calloc (1, sizeof(uint32) * EC_MAXEEPBITMAP); + net->ctx.elist = calloc (1, sizeof(ec_eringt)); + net->ctx.idxstack = calloc (1, sizeof(ec_idxstackT)); + net->ctx.ecaterror = calloc (1, sizeof(boolean)); + net->ctx.DCtime = calloc (1, sizeof(int64)); + net->ctx.SMcommtype = calloc (1, sizeof(ec_SMcommtypet)); + net->ctx.PDOassign = calloc (1, sizeof(ec_PDOassignt)); + net->ctx.PDOdesc = calloc (1, sizeof(ec_PDOdesct)); + net->ctx.eepSM = calloc (1, sizeof(ec_eepromSMt)); + net->ctx.eepFMMU = calloc (1, sizeof(ec_eepromFMMUt)); + + net->ctx.maxslave = EC_MAXSLAVE; + net->ctx.maxgroup = EC_MAXGROUP; + net->ctx.esislave = 0; + net->ctx.DCtO = 0; + net->ctx.DCl = 0; + net->ctx.FOEhook = 0; + + net->io_map = calloc (1, 4096); + if (!net->io_map) + { + printf ("[%s] Could not allocate memory for IO map\n", ifname); + goto cleanup; + } + + return net; + +cleanup: + // TODO: cleanup + if (net->io_map) + { + free (net->io_map); + } + + if (net) + { + free (net); + } + return NULL; +} + +int ecat_net_scan(ecat_net_t * net) +{ + int status, i; + //int i, chk; + + status = ecx_init (&net->ctx, net->ifname); + if (status <= 0) + { + printf ("[%s] ecx_init failed\n", net->ifname); + return -1; + } + + status = ecx_config_init (&net->ctx, FALSE); + if (status <= 0) + { + printf ("[%s] no slaves found\n", net->ifname); + return -1; + } + + ecx_config_map_group (&net->ctx, net->io_map, 0); + ecx_configdc (&net->ctx); + + while (*(net->ctx.ecaterror)) + { + printf ("[%s] error: %s\n", net->ifname, ecx_elist2string (&net->ctx)); + } + + printf ("[%s] %d slaves found and configured\n", net->ifname, *(net->ctx.slavecount)); + net->expected_wc = (net->ctx.grouplist[0].outputsWKC * 2) + + net->ctx.grouplist[0].inputsWKC; + printf ("[%s] calculated workcounter %d\n", net->ifname, net->expected_wc); + + /* wait for all slaves to reach SAFE_OP state */ + ecx_statecheck (&net->ctx, 0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 3); + if (net->ctx.slavelist[0].state != EC_STATE_SAFE_OP ) + { + // TODO: fix + printf ("[%s] not all slaves reached safe operational state.\n", net->ifname); + ecx_readstate (&net->ctx); + for (i = 1; i <= *(net->ctx.slavecount) ; i++) + { + + if (net->ctx.slavelist[i].state != EC_STATE_SAFE_OP) + { + printf ("[%s] slave:%d, state:%2x, statuscode:%4x : %s\n", net->ifname, + i, net->ctx.slavelist[i].state, net->ctx.slavelist[i].ALstatuscode, + ec_ALstatuscode2string (net->ctx.slavelist[i].ALstatuscode)); + } + } + } + + /* ecx_readstate (&net->ctx); */ + /* for(i = 1; i <= *(net->ctx.slavecount); i++) */ + /* { */ + /* printf ("[%s] slave:%d, name:%s, output:%d, input:%d\n", ifname, i, */ + /* net->ctx.slavelist[i].name, net->ctx.slavelist[i].Obits, */ + /* net->ctx.slavelist[i].Ibits); */ + /* } */ + +#if 0 + printf ("[%s] Request operational state for all slaves\n", ifname); + net->expected_wc = (net->ctx.grouplist[0].outputsWKC * 2) + + net->ctx.grouplist[0].inputsWKC; + printf ("[%s] calculated workcounter %d\n", ifname, net->expected_wc); + net->ctx.slavelist[0].state = EC_STATE_OPERATIONAL; + + /* send one valid process data to make outputs in slaves happy*/ + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + /* request OP state for all slaves */ + ecx_writestate (&net->ctx, 0); + + chk = 40; + /* wait for all slaves to reach OP state */ + do + { + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_statecheck (&net->ctx, 0, EC_STATE_OPERATIONAL, 50000); + } while (chk-- && (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL)); + + if (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL) + { + printf ("[%s] not all slaves reached safe operational state.\n", ifname); + ecx_readstate (&net->ctx); + for(i = 1; i <= *(net->ctx.slavecount); i++) + { + if(net->ctx.slavelist[i].state != EC_STATE_SAFE_OP) + { + printf ("[%s] slave:%d, state:%2x, statuscode:%4x : %s\n", ifname, + i, net->ctx.slavelist[i].state, net->ctx.slavelist[i].ALstatuscode, + ec_ALstatuscode2string(net->ctx.slavelist[i].ALstatuscode)); + } + } + goto cleanup; + } + + printf("[%s] operational state reached for all slaves\n", ifname); + +#endif + return 0; +} + + +/* //if, size, callbacks, link_cb, etc.); */ +/* int ecat_net_scan(ecat_net_t * net); */ +/* //int ecat_net_verify(...); */ +int ecat_net_set_state(ecat_net_t * net, ecat_state_t state) +{ + int ret = -1; + ecx_readstate (&net->ctx); + + printf ("ecat_net_set_state: %s -> %s\n", + ecat_util_state_to_str (net->ctx.slavelist[0].state), + ecat_util_state_to_str (state)); + + // TODO: clear errors? + + /* check if it's a valid transision */ + switch (net->ctx.slavelist[0].state) { + /* + case EC_STATE_INIT: + if (state == ECAT_STATE_PRE_OP) + { + net->ctx.slavelist[0].state = EC_STATE_PRE_OP; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + break; + + case EC_STATE_PRE_OP: + if (state == ECAT_STATE_SAFE_OP) + { + net->ctx.slavelist[0].state = EC_STATE_SAFE_OP; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + else if (state == ECAT_STATE_INIT) + { + net->ctx.slavelist[0].state = EC_STATE_INIT; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + break; + */ + case EC_STATE_SAFE_OP: + if (state == ECAT_STATE_OP) + { + int chk = 40; + net->ctx.slavelist[0].state = EC_STATE_OPERATIONAL; + + /* send one valid process data to make outputs in slaves happy*/ + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_writestate (&net->ctx, 0); + do + { + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_statecheck (&net->ctx, 0, EC_STATE_OPERATIONAL, 50000); + } while (chk-- && (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL)); + + /* if (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL) */ + /* { */ + /* printf ("[%s] not all slaves reached safe operational state.\n", net->ifname); */ + /* ecx_readstate (&net->ctx); */ + /* for(i = 1; i <= *(net->ctx.slavecount); i++) */ + /* { */ + /* if(net->ctx.slavelist[i].state != EC_STATE_SAFE_OP) */ + /* { */ + /* printf ("[%s] slave:%d, state:%2x, statuscode:%4x : %s\n", net->ifname, */ + /* i, net->ctx.slavelist[i].state, net->ctx.slavelist[i].ALstatuscode, */ + /* ec_ALstatuscode2string(net->ctx.slavelist[i].ALstatuscode)); */ + /* } */ + /* } */ + /* ret = -1; */ + /* } */ + /* else { */ + /* ret = 0; */ + /* } */ + ret = 0; + } + break; + + case EC_STATE_OPERATIONAL: + if (state == ECAT_STATE_SAFE_OP) + { + int chk = 40; + net->ctx.slavelist[0].state = EC_STATE_SAFE_OP; + ecx_writestate (&net->ctx, 0); + do + { + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_statecheck (&net->ctx, 0, EC_STATE_SAFE_OP, 50000); + } while (chk-- && (net->ctx.slavelist[0].state != EC_STATE_SAFE_OP)); + + ret = 0; + } + break; + + default: + break; + } + return ret; +} + +ecat_state_t ecat_net_get_state(ecat_net_t * net) //, ecat_net_state_t * state) +{ + ecx_readstate (&net->ctx); + switch (net->ctx.slavelist[0].state) + { + case EC_STATE_INIT: + return ECAT_STATE_INIT; + + case EC_STATE_PRE_OP: + return ECAT_STATE_PRE_OP; + + case EC_STATE_SAFE_OP: + return ECAT_STATE_SAFE_OP; + + case EC_STATE_OPERATIONAL: + return ECAT_STATE_OP; + + case EC_STATE_BOOT: + return ECAT_STATE_BOOT; + + default: + return -1; + } +} +/* int ecat_net_send(ecat_net_t * net); */ +/* int ecat_net_receive(ecat_net_t * net); */ + +void ecat_net_print_slave_states (ecat_net_t * net) +{ + int i; + ecx_readstate (&net->ctx); + + printf ("[%s] ix. status name outp inpb error\n", net->ifname); + printf ("[%s] - %-7s system - - %s\n", net->ifname, + ecat_util_state_to_str (net->ctx.slavelist[0].state), + net->ctx.slavelist[0].ALstatuscode ? "yes" : "no"); + + for (i = 1; i <= *(net->ctx.slavecount) ; i++) + { + if (net->ctx.slavelist[i].ALstatuscode) + { + printf ("[%s] %2u. %-7s %-15s %4u %4d %s (%x)\n", net->ifname, + i, ecat_util_state_to_str (net->ctx.slavelist[i].state), + net->ctx.slavelist[i].name, + net->ctx.slavelist[i].Obits, + net->ctx.slavelist[i].Ibits, + ec_ALstatuscode2string (net->ctx.slavelist[i].ALstatuscode), + net->ctx.slavelist[i].ALstatuscode); + } + else + { + printf ("[%s] %2u. %-7s %-15s %4u %4u\n", net->ifname, + i, ecat_util_state_to_str (net->ctx.slavelist[i].state), + net->ctx.slavelist[i].name, + net->ctx.slavelist[i].Obits, + net->ctx.slavelist[i].Ibits); + } + } +} + + +typedef struct { + uint8_t state; + char name[8]; +} _ecat_state_name_t; + +#define ECAT_END_MARKER 0xffff +#define ECAT_ERR 0x10 + +const _ecat_state_name_t _ecat_state_name[] = { + { ECAT_STATE_INIT & 0xff, "INIT" }, + { ECAT_STATE_PRE_OP & 0xff, "PRE" }, + { ECAT_STATE_SAFE_OP & 0xff, "SAFE" }, + { ECAT_STATE_OP & 0xff, "OPER" }, + { ECAT_STATE_BOOT & 0xff, "BOOT" }, + { ECAT_STATE_INIT | ECAT_STATE_ERROR & 0xff, "INIT(E)" }, + { ECAT_STATE_PRE_OP | ECAT_STATE_ERROR & 0xff, "PRE (E)" }, + { ECAT_STATE_SAFE_OP | ECAT_STATE_ERROR & 0xff, "SAFE(E)" }, + { ECAT_STATE_OP | ECAT_STATE_ERROR & 0xff, "OPER(E)" }, + { ECAT_STATE_BOOT | ECAT_STATE_ERROR & 0xff, "BOOT(E)" }, + { ECAT_END_MARKER & 0xff, "UNKN" } +}; + + +char * ecat_util_state_to_str(ecat_state_t state) +{ + int i = 0; + + while ((_ecat_state_name[i].state != (uint8_t)ECAT_END_MARKER) && + (_ecat_state_name[i].state != (uint8_t)state) ) + { + i++; + } + + return (char *) _ecat_state_name[i].name; +} + + +int ecat_net_send(ecat_net_t * net) +{ + int status; + + status = ecx_send_processdata(&net->ctx); + if (status >= 0) { + // TODO: increase send error counter + // failed to send frame + return -1; + } + else + { + // TODO: increase number of sent messages + } + return 0; +} + +int ecat_net_receive(ecat_net_t * net, unsigned int timeout_us) +{ + int wc; + wc = ecx_receive_processdata(&net->ctx, timeout_us); + + if (wc <= EC_NOFRAME) + { + // TODO: increase missing frame counter + } + else if (wc != net->expected_wc) + { + // TODO: increase invalid message counter + } + else + { + // TODO: increase received messages counter + } + return wc; +} + + + +int ecat_slave_set_state(ecat_net_t * net, unsigned int slave, ecat_state_t state) +{ + int ret = -1; + ecx_readstate (&net->ctx); + + printf ("ecat_net_set_state: %s -> %s\n", + ecat_util_state_to_str (net->ctx.slavelist[0].state), + ecat_util_state_to_str (state)); + + // TODO: clear errors? + + /* check if it's a valid transision */ + switch (net->ctx.slavelist[0].state) { + /* + case EC_STATE_INIT: + if (state == ECAT_STATE_PRE_OP) + { + net->ctx.slavelist[0].state = EC_STATE_PRE_OP; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + break; + + case EC_STATE_PRE_OP: + if (state == ECAT_STATE_SAFE_OP) + { + net->ctx.slavelist[0].state = EC_STATE_SAFE_OP; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + else if (state == ECAT_STATE_INIT) + { + net->ctx.slavelist[0].state = EC_STATE_INIT; + ecx_writestate (&net->ctx, 0); + ret = 0; + } + break; + */ + case EC_STATE_SAFE_OP: + if (state == ECAT_STATE_OP) + { + int chk = 40; + net->ctx.slavelist[0].state = EC_STATE_OPERATIONAL; + + /* send one valid process data to make outputs in slaves happy*/ + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_writestate (&net->ctx, 0); + do + { + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_statecheck (&net->ctx, 0, EC_STATE_OPERATIONAL, 50000); + } while (chk-- && (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL)); + + /* if (net->ctx.slavelist[0].state != EC_STATE_OPERATIONAL) */ + /* { */ + /* printf ("[%s] not all slaves reached safe operational state.\n", net->ifname); */ + /* ecx_readstate (&net->ctx); */ + /* for(i = 1; i <= *(net->ctx.slavecount); i++) */ + /* { */ + /* if(net->ctx.slavelist[i].state != EC_STATE_SAFE_OP) */ + /* { */ + /* printf ("[%s] slave:%d, state:%2x, statuscode:%4x : %s\n", net->ifname, */ + /* i, net->ctx.slavelist[i].state, net->ctx.slavelist[i].ALstatuscode, */ + /* ec_ALstatuscode2string(net->ctx.slavelist[i].ALstatuscode)); */ + /* } */ + /* } */ + /* ret = -1; */ + /* } */ + /* else { */ + /* ret = 0; */ + /* } */ + ret = 0; + } + break; + + case EC_STATE_OPERATIONAL: + if (state == ECAT_STATE_SAFE_OP) + { + int chk = 40; + net->ctx.slavelist[0].state = EC_STATE_SAFE_OP; + ecx_writestate (&net->ctx, 0); + do + { + ecx_send_processdata (&net->ctx); + ecx_receive_processdata (&net->ctx, EC_TIMEOUTRET); + ecx_statecheck (&net->ctx, 0, EC_STATE_SAFE_OP, 50000); + } while (chk-- && (net->ctx.slavelist[0].state != EC_STATE_SAFE_OP)); + + ret = 0; + } + break; + + default: + break; + } + return ret; +} + + +int ecat_slave_get_dc_status(ecat_net_t * net, uint32_t slave, + ecat_slave_dc_status_t * status) +{ + uint8_t sys_time[32]; + + /* Read System Time registers */ + if (ecx_FPRD(net->ctx.port, net->ctx.slavelist[slave].configadr, + ECT_REG_DCSYSTIME, sizeof(sys_time), sys_time, EC_TIMEOUTRET3)) + { + /* System Time */ + memcpy(&status->time, + &sys_time[ECT_REG_DCSYSTIME - ECT_REG_DCSYSTIME], + sizeof(status->time)); + + /* System Time Offset */ + memcpy(&status->offset, + &sys_time[ECT_REG_DCSYSOFFSET - ECT_REG_DCSYSTIME], + sizeof(status->offset)); + + /* System Time Delay */ + memcpy(&status->delay, + &sys_time[ECT_REG_DCSYSDELAY - ECT_REG_DCSYSTIME], + sizeof(status->delay)); + + /* System Time Difference */ + memcpy(&status->difference, + &sys_time[ECT_REG_DCSYSDIFF - ECT_REG_DCSYSTIME], + sizeof(status->difference)); + + if (status->difference & 0x80000000) { + status->difference = + 0 - (status->difference & 0x7FFFFFFF); + } + return 0; + } + + return -1; +} + +int ecat_slave_get_status(ecat_net_t * net, uint32_t slave, + ecat_slave_status_t * status) +{ + int ret = 0x0; + uint16_t dlstat; + uint16_t wdcntr; + uint8_t err_cntrs[20]; + uint8_t p; + + /* Read ESC DL status register */ + if (ecx_FPRD(net->ctx.port, net->ctx.slavelist[slave].configadr, + ECT_REG_DLSTAT, sizeof(dlstat), &dlstat, EC_TIMEOUTRET3)) + { + + /* Link detected */ + for (p=0; p <= 3; p++) + { + status->port[p].link_detected = + dlstat & (0x0010 << p) + ? ECAT_SLAVE_LINK_DETECTED:ECAT_SLAVE_NO_LINK; + } + + /* Loop port */ + for (p=0; p <= 3; p++) + { + status->port[p].loop_port = + dlstat & (0x0100 << (p * 2)) + ? ECAT_SLAVE_PORT_CLOSED:ECAT_SLAVE_PORT_OPEN; + } + + /* Stable communication */ + for (p=0; p <= 3; p++) + { + status->port[p].stable_com = + dlstat & (0x0200 << (p * 2)) + ? ECAT_SLAVE_COM_ESTABLISHED:ECAT_SLAVE_NO_STABLE_COM; + } + } + else + { + ret |= 0x1; + } + + /* Read Error Counters registers */ + if (ecx_FPRD(net->ctx.port, net->ctx.slavelist[slave].configadr, + ECT_REG_RXERR, sizeof(err_cntrs), err_cntrs, EC_TIMEOUTRET3)) + { + + /* Lost Link Counter */ + for (p=0; p <= 3; p++) + { + status->port[p].lost_link_counter = + err_cntrs[ECT_REG_LLCNT - ECT_REG_RXERR + p]; + } + + /* RX Error Counter */ + for (p=0; p <= 3; p++) + { + status->port[p].invalid_frame_counter = + err_cntrs[ECT_REG_RXERR + (p * 2)]; + status->port[p].rx_error_counter = + err_cntrs[ECT_REG_RXERR + (p * 2) + 1]; + } + + /* Forwarded RX Error Counter */ + for (p=0; p <= 3; p++) + { + status->port[p].forwarded_rx_error_counter = + err_cntrs[ECT_REG_FRXERR - ECT_REG_RXERR + p]; + } + + /* ECAT Processing Unit Error Counter */ + status->ecat_processing_unit_error_counter = + err_cntrs[ECT_REG_EPUECNT - ECT_REG_RXERR]; + + /* PDI Error Counter */ + status->pdi_error_counter = + err_cntrs[ECT_REG_PECNT - ECT_REG_RXERR]; + + /* PDI Error Code */ + status->pdi_error_code = + err_cntrs[ECT_REG_PECODE - ECT_REG_RXERR]; + + } + else + { + ret |= 0x2; + } + + /* Read Watchdog register */ + if (ecx_FPRD(net->ctx.port, net->ctx.slavelist[slave].configadr, + ECT_REG_WDCNT, sizeof(wdcntr), &wdcntr, EC_TIMEOUTRET3)) + { + + /* Watchdog counter process data and pdi */ + status->wd_cnt.watchdog_counter_process_data = wdcntr & 0x00FF; + status->wd_cnt.watchdog_counter_pdi = wdcntr & 0xFF00; + } + else + { + ret |= 0x4; + } + + return ret > 0 ? -ret:ret; +} + diff --git a/soem/ecat.h b/soem/ecat.h new file mode 100644 index 0000000..71e7a57 --- /dev/null +++ b/soem/ecat.h @@ -0,0 +1,478 @@ +/** + * \addtogroup EtherCAT middleware layer (DRAFT) + * \{ + */ + +#ifndef ECAT_H +#define ECAT_H + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatconfig.h" +#include "ethercatcoe.h" +#include "ethercatdc.h" +#include "ethercatprint.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + ecx_contextt ctx; + char * ifname; + uint8_t * io_map; + unsigned int expected_wc; +} ecat_net_t; + + +typedef struct { + uint32_t a; + /* TBD */ +} ecat_slave_t; + +typedef struct { + uint32_t a; + /* TBD */ +} ecat_statistics_t; + +typedef enum { + ECAT_STATE_INIT = 0x01, + ECAT_STATE_PRE_OP = 0x02, + ECAT_STATE_BOOT = 0x03, + ECAT_STATE_SAFE_OP = 0x04, + ECAT_STATE_OP = 0x08, + + ECAT_STATE_ACK = 0x10, + ECAT_STATE_ERROR = 0x10, +} ecat_state_t; + +typedef enum { + ECAT_SLAVE_NO_LINK, + ECAT_SLAVE_LINK_DETECTED +} ecat_slave_link_detected_t; + +typedef enum { + ECAT_SLAVE_PORT_OPEN, + ECAT_SLAVE_PORT_CLOSED +} ecat_slave_loop_port_t; + +typedef enum { + ECAT_SLAVE_NO_STABLE_COM, + ECAT_SLAVE_COM_ESTABLISHED +} ecat_slave_stable_com_t; + +typedef struct { + ecat_slave_link_detected_t link_detected; + ecat_slave_loop_port_t loop_port; + ecat_slave_stable_com_t stable_com; + uint8_t lost_link_counter; + uint8_t invalid_frame_counter; + uint8_t rx_error_counter; + uint8_t forwarded_rx_error_counter; +} ecat_slave_port_status_t; + +typedef struct { + uint8_t watchdog_counter_process_data; + uint8_t watchdog_counter_pdi; +} ecat_slave_wd_cnt_t; + +typedef struct { + ecat_slave_port_status_t port[4]; + ecat_slave_wd_cnt_t wd_cnt; + uint8_t ecat_processing_unit_error_counter; + uint8_t pdi_error_counter; + uint8_t pdi_error_code; +} ecat_slave_status_t; + +typedef struct { + uint64_t time; + uint64_t offset; + uint32_t delay; + int32_t difference; +} ecat_slave_dc_status_t; + +/*********************************************************************** + Example: + + ecat_net_t * net; + ... + + // This part is done during "boot" + net = ecat_net_init ("ie1g1", settings); + num_slaves = ecat_net_scan (net); + + if (ecat_net_verify (net, ...) < 0) + { + // handle net mismatch + } + + if (ecat_net_get_state (net) != ECAT_STATE_SAFE_OP) + { + // handle that not all slaves are in SAFE-OP + } + + expected_wc = ecat_net_get_expected_wc (net); + ecat_net_print_slave_states (net); + + + + // This is done when starting the EtherCAT communication + if (ecat_net_set_state (net, ECAT_STATE_OP) < 0) + { + // handle that not all slaves are in OPERATIONAL + } + + + + // When the EtherCAT network is up and running + // In the start of the cycle process incomming message + wc = ecat_net_receive (net, 0); + if (wc != expected_wc) + { + // handle invalid working counter + } + + // In the end of the cycle, send out the message + ecat_net_send (net); + + + + // This is done when shutting down the system. + ecat_net_set_state (net, ECAT_STATE_SAFE_OP); + // go to other states if needed + ... + ecat_net_deinit (net); + + ***********************************************************************/ + + + + +/*********************************************************************** + *** EtherCAT network *** + ***********************************************************************/ + +/** + * Initiate a master instance, allocates memory. + * + * \return The network handle to be used in all subsequent operations + * on the EtherCAT network and slaves + */ +ecat_net_t * ecat_net_init(char * ifname); //, ecat_net_settings_t * settings); + +/** + * Sets up network interface, scan the EtherCAT network, set up the IOMAP, + * configure slaves and bring the slaves up to SAFE OPERATIONAL. + * + * \param net Network handle + * \return number of slaves found on success, negative number on failure + */ +int ecat_net_scan(ecat_net_t * net); + +/** + * Verifies the scanned network against an expected newtork. + * + * \param net Network handle + * \param TBD Expected network + * \return 0 on success, negative number on failure + */ +int ecat_net_verify(ecat_net_t * net); //, /* TBD */); + +/** + * Tries to change the state on all slaves on the network, for example + * SAFE OPERATIONAL to OPERATIONAL. + * + * \param net Network handle + * \param state State to change to + * \return 0 on success, negative number on failure + */ +int ecat_net_set_state(ecat_net_t * net, ecat_state_t state); + +/** + * Get the lowest common state for all slaves on the network. If all + * slaves are in ECAT_STATE_OP and one in ECAT_STATE_SAFE_OP this + * function will return ECAT_STATE_SAFE_OP. + * + * \param net Network handle + * \param state State to change to + * \return current network state + */ +ecat_state_t ecat_net_get_state(ecat_net_t * net); + +/** + * Sends process data from the IOMAP on the network. + * + * \param net Network handle + * \return 0 on success, negative number on failure + */ +int ecat_net_send(ecat_net_t * net); + +/** + * Process incomming process data and store it in the IOMAP. + * + * \param net Network handle + * \param timeout_us Timeout (us) + * \return wc on success, negative number on failure + */ +int ecat_net_receive(ecat_net_t * net, unsigned int timeout_us); + +/** + * Closes the network and cleans up the allocated memory. + * + * \param net Network handle + */ +void ecat_net_deinit(ecat_net_t * net); + +/** + * Gets the expected working counter of the network. + * + * \param net Network handle + * \return the expected network handle of the network + */ +int ecat_net_get_expected_wc(ecat_net_t * net); + +/** + * Query the slaves for slave status and error codes and prints the + * result to the console. + * + * \param net Network handle + */ +void ecat_net_print_slave_states (ecat_net_t * net); + +/** + * Returns statistics from this master such as number of sent and + * received frames. + * + * \param net Network handle + * \param stats Statistics stuct + */ +void ecat_net_statistics(ecat_net_t * net, ecat_statistics_t * stats); + + +/*********************************************************************** + *** EtherCAT slave *** + ***********************************************************************/ + +/** + * Set state on a specific slave. + * + * \param net Network handle + * \param slave Slave index + * \param state State to go to + * \return 0 on success, negative number on failure + */ +int ecat_slave_set_state(ecat_net_t * net, uint32_t slave, + ecat_state_t state); + +/** + * Get state on a specific slave. + * + * \param net Network handle + * \param slave Slave index + * \return 0 on success, negative number on failure + */ +ecat_state_t ecat_slave_get_state(ecat_net_t * net); + +/** + * Read SDO data from a slave. The `data` area to be large enough to + * hold the SDO data. + * + * \param net Network handle + * \param slave Slave index + * \param index CoE index + * \param subindex CoE subindex + * \param data Pointer to where the data should be stored + * \return 0 on success, negative number on failure + */ +int ecat_slave_sdo_read(ecat_net_t * net, uint32_t slave, uint16_t index, + uint16_t subindex, void * data); +/** + * Write SDO data to a slave. + * + * \param net Network handle + * \param slave Slave index + * \param index CoE index + * \param subindex CoE subindex + * \param data Pointer to the SDO data + * \return 0 on success, negative number on failure + */ +int ecat_slave_sdo_write(ecat_net_t * net, uint32_t slave, uint16_t index, + uint16_t subindex, const void * data); + +/** + * Read PDO data from the IOMAP. The `data` area to be large enough to + * hold the PDO data. + * + * \param net Network handle + * \param slave Slave index + * \param index CoE index + * \param subindex CoE subindex + * \param data Pointer to where the data should be stored + * \return 0 on success, negative number on failure + */ +int ecat_slave_pdo_read(ecat_net_t * net, uint32_t slave, uint16_t index, + uint16_t subindex, void * data); + +/** + * Write PDO data to the IOMAP. + * + * \param net Network handle + * \param slave Slave index + * \param index CoE index + * \param subindex CoE subindex + * \param data Pointer to the SDO data + * \return 0 on success, negative number on failure + */ +int ecat_slave_pdo_write(ecat_net_t * net, uint32_t slave, uint16_t index, + uint16_t subindex, const void * data); + +/** + * Read EEPROM data from the slave. + * + * \param net Network handle + * \param slave Slave index + * \param address EEPROM start address + * \param size EEPROM data size + * \param data Pointer to where the data should be stored + * \return 0 on success, negative number on failure + */ +int ecat_slave_eeprom_read(ecat_net_t * net, uint32_t slave, uint32_t address, + size_t size, void * data); + +/** + * Write EEPROM data to the slave. + * + * \param net Network handle + * \param slave Slave index + * \param address EEPROM start address + * \param size EEPROM data size + * \param data Pointer to EEPROM data + * \return 0 on success, negative number on failure + */ +int ecat_slave_eeprom_write(ecat_net_t * net, uint32_t slave, uint32_t address, + size_t size, const void * data); + +/** + * Read register data from the slave. + * + * \param net Network handle + * \param slave Slave index + * \param address Register start address + * \param length Register data length + * \param data Pointer to where the data should be stored + * \return 0 on success, negative number on failure + */ +int ecat_slave_reg_read(ecat_net_t * net, uint32_t slave, uint32_t address, + uint32_t length, void * data); + +/** + * Write register data to the slave. + * + * \param net Network handle + * \param slave Slave index + * \param address Register start address + * \param size Register data size + * \param data Pointer to register data + * \return 0 on success, negative number on failure + */ +int ecat_slave_reg_write(ecat_net_t * net, uint32_t slave, uint32_t address, + size_t size, void * data); + +/** + * Read file data from the slave. + * + * \param net Network handle + * \param slave Slave index + * \param filename File to read + * \param size Maximum file size + * \param data Pointer to where the data should be stored + * \return 0 on success, negative number on failure + */ +int ecat_slave_file_read(ecat_net_t * net, uint32_t slave, char * filename, + size_t size, void * data); + +/** + * Write file data to the slave. + * + * \param net Network handle + * \param slave Slave index + * \param filename File to write + * \param size File size + * \param data Pointer to file data + * \return 0 on success, negative number on failure + */ +int ecat_slave_file_write(ecat_net_t * net, uint32_t slave, char * filename, + size_t size, const void * data); + +/** + * Gets the AL status from a slave. + * + * \param net Network handle + * \param slave Slave index + * \return AL status + */ +uint16_t ecat_slave_get_al_status(ecat_net_t * net, uint32_t slave); + +/** + * Gets the distributed clock status from a slave. + * + * \param net Network handle + * \param slave Slave index + * \param status Pointer to slave dc status structure + * \return 0 on success, negative number on failure + */ +int ecat_slave_get_dc_status(ecat_net_t * net, uint32_t slave, + ecat_slave_dc_status_t * status); + +/** + * Gets the status from a slave. + * + * \param net Network handle + * \param slave Slave index + * \param status Pointer to slave status structure + * \return 0 on success, negative number on failure + * -1 DL status read failed + * -2 Error counters read failed + * -3 DL status and Error counters read failed + * -4 Watchdog read failed + * -5 DL status and Watchdog read failed + * -6 Error counters and Watchdog read failed + * -7 DL status and Error counters and Watchdog read failed + */ +int ecat_slave_get_status(ecat_net_t * net, uint32_t slave, + ecat_slave_status_t * status); + + +/*********************************************************************** + *** EtherCAT utils *** + ***********************************************************************/ + +/** + * Returns the corresponding string for a EtherCAT state. + * + * \param state The state + * \returns a string + */ +char * ecat_util_state_to_str(ecat_state_t state); + +/** + * Returns the corresponding string for an AL status code. + * + * \param alstatus AL status + * \returns a string + */ +char * ecat_util_al_status_to_str(ecat_net_t * net, uint16_t alstatus); + + + +#ifdef __cplusplus +} +#endif +#endif /* ECAT_H */ + +/** + * \} + */ diff --git a/soem/ethercatbase.c b/soem/ethercatbase.c new file mode 100644 index 0000000..c39737f --- /dev/null +++ b/soem/ethercatbase.c @@ -0,0 +1,672 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatbase.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Base EtherCAT functions. + * + * Setting up a datagram in an ethernet frame. + * EtherCAT datagram primitives, broadcast, auto increment, configured and + * logical addressed data transfers. All base transfers are blocking, so + * wait for the frame to be returned to the master or timeout. If this is + * not acceptable build your own datagrams and use the functions from nicdrv.c. + */ + +#include +#include +#include "oshw.h" +#include "osal.h" +#include "ethercattype.h" +#include "ethercatbase.h" + +/** Write data to EtherCAT datagram. + * + * @param[out] datagramdata = data part of datagram + * @param[in] com = command + * @param[in] length = length of databuffer + * @param[in] data = databuffer to be copied into datagram + */ +static void ecx_writedatagramdata(void *datagramdata, ec_cmdtype com, uint16 length, const void * data) +{ + if (length > 0) + { + switch (com) + { + case EC_CMD_NOP: + /* Fall-through */ + case EC_CMD_APRD: + /* Fall-through */ + case EC_CMD_FPRD: + /* Fall-through */ + case EC_CMD_BRD: + /* Fall-through */ + case EC_CMD_LRD: + /* no data to write. initialise data so frame is in a known state */ + memset(datagramdata, 0, length); + break; + default: + memcpy(datagramdata, data, length); + break; + } + } +} + +/** Generate and set EtherCAT datagram in a standard ethernet frame. + * + * @param[in] port = port context struct + * @param[out] frame = framebuffer + * @param[in] com = command + * @param[in] idx = index used for TX and RX buffers + * @param[in] ADP = Address Position + * @param[in] ADO = Address Offset + * @param[in] length = length of datagram excluding EtherCAT header + * @param[in] data = databuffer to be copied in datagram + * @return always 0 + */ +int ecx_setupdatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data) +{ + ec_comt *datagramP; + uint8 *frameP; + + frameP = frame; + /* Ethernet header is preset and fixed in frame buffers + EtherCAT header needs to be added after that */ + datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE]; + datagramP->elength = htoes(EC_ECATTYPE + EC_HEADERSIZE + length); + datagramP->command = com; + datagramP->index = idx; + datagramP->ADP = htoes(ADP); + datagramP->ADO = htoes(ADO); + datagramP->dlength = htoes(length); + ecx_writedatagramdata(&frameP[ETH_HEADERSIZE + EC_HEADERSIZE], com, length, data); + /* set WKC to zero */ + frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length] = 0x00; + frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length + 1] = 0x00; + /* set size of frame in buffer array */ + port->txbuflength[idx] = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + length; + + return 0; +} + +/** Add EtherCAT datagram to a standard ethernet frame with existing datagram(s). + * + * @param[in] port = port context struct + * @param[out] frame = framebuffer + * @param[in] com = command + * @param[in] idx = index used for TX and RX buffers + * @param[in] more = TRUE if still more datagrams to follow + * @param[in] ADP = Address Position + * @param[in] ADO = Address Offset + * @param[in] length = length of datagram excluding EtherCAT header + * @param[in] data = databuffer to be copied in datagram + * @return Offset to data in rx frame, usefull to retrieve data after RX. + */ +int ecx_adddatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data) +{ + ec_comt *datagramP; + uint8 *frameP; + uint16 prevlength; + + frameP = frame; + /* copy previous frame size */ + prevlength = port->txbuflength[idx]; + datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE]; + /* add new datagram to ethernet frame size */ + datagramP->elength = htoes( etohs(datagramP->elength) + EC_HEADERSIZE + length ); + /* add "datagram follows" flag to previous subframe dlength */ + datagramP->dlength = htoes( etohs(datagramP->dlength) | EC_DATAGRAMFOLLOWS ); + /* set new EtherCAT header position */ + datagramP = (ec_comt*)&frameP[prevlength - EC_ELENGTHSIZE]; + datagramP->command = com; + datagramP->index = idx; + datagramP->ADP = htoes(ADP); + datagramP->ADO = htoes(ADO); + if (more) + { + /* this is not the last datagram to add */ + datagramP->dlength = htoes(length | EC_DATAGRAMFOLLOWS); + } + else + { + /* this is the last datagram in the frame */ + datagramP->dlength = htoes(length); + } + ecx_writedatagramdata(&frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE], com, length, data); + /* set WKC to zero */ + frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length] = 0x00; + frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length + 1] = 0x00; + /* set size of frame in buffer array */ + port->txbuflength[idx] = prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + EC_WKCSIZE + length; + + /* return offset to data in rx frame + 14 bytes smaller than tx frame due to stripping of ethernet header */ + return prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE - ETH_HEADERSIZE; +} + +/** BRW "broadcast write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, normally 0 + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[in] data = databuffer to be written to slaves + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_BWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + /* get fresh index */ + idx = ecx_getindex (port); + /* setup datagram */ + ecx_setupdatagram (port, &(port->txbuf[idx]), EC_CMD_BWR, idx, ADP, ADO, length, data); + /* send data and wait for answer */ + wkc = ecx_srconfirm (port, idx, timeout); + /* clear buffer status */ + ecx_setbufstat (port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** BRD "broadcast read" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, normally 0 + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[out] data = databuffer to put slave data in + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_BRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + /* get fresh index */ + idx = ecx_getindex(port); + /* setup datagram */ + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_BRD, idx, ADP, ADO, length, data); + /* send data and wait for answer */ + wkc = ecx_srconfirm (port, idx, timeout); + if (wkc > 0) + { + /* copy datagram to data buffer */ + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + /* clear buffer status */ + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** APRD "auto increment address read" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, each slave ++, slave that has 0 excecutes + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[out] data = databuffer to put slave data in + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_APRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + int wkc; + uint8 idx; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APRD, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if (wkc > 0) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** APRMW "auto increment address read, multiple write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, each slave ++, slave that has 0 reads, + * following slaves write. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[out] data = databuffer to put slave data in + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_ARMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + int wkc; + uint8 idx; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_ARMW, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if (wkc > 0) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** FPRMW "configured address read, multiple write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, slave that has address reads, + * following slaves write. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[out] data = databuffer to put slave data in + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_FRMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + int wkc; + uint8 idx; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if (wkc > 0) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** APRDw "auto increment address read" word return primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, each slave ++, slave that has 0 reads. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return word data from slave + */ +uint16 ecx_APRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout) +{ + uint16 w; + + w = 0; + ecx_APRD(port, ADP, ADO, sizeof(w), &w, timeout); + + return w; +} + +/** FPRD "configured address read" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, slave that has address reads. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[out] data = databuffer to put slave data in + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + int wkc; + uint8 idx; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if (wkc > 0) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** FPRDw "configured address read" word return primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, slave that has address reads. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return word data from slave + */ +uint16 ecx_FPRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout) +{ + uint16 w; + + w = 0; + ecx_FPRD(port, ADP, ADO, sizeof(w), &w, timeout); + return w; +} + +/** APWR "auto increment address write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, each slave ++, slave that has 0 writes. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[in] data = databuffer to write to slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_APWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APWR, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** APWRw "auto increment address write" word primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, each slave ++, slave that has 0 writes. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] data = word data to write to slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_APWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout) +{ + return ecx_APWR(port, ADP, ADO, sizeof(data), &data, timeout); +} + +/** FPWR "configured address write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, slave that has address writes. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] length = length of databuffer + * @param[in] data = databuffer to write to slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + int wkc; + uint8 idx; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPWR, idx, ADP, ADO, length, data); + wkc = ecx_srconfirm(port, idx, timeout); + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** FPWR "configured address write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] ADP = Address Position, slave that has address writes. + * @param[in] ADO = Address Offset, slave memory address + * @param[in] data = word to write to slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_FPWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout) +{ + return ecx_FPWR(port, ADP, ADO, sizeof(data), &data, timeout); +} + +/** LRW "logical memory read / write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] LogAdr = Logical memory address + * @param[in] length = length of databuffer + * @param[in,out] data = databuffer to write to and read from slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_LRW(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW)) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** LRD "logical memory read" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] LogAdr = Logical memory address + * @param[in] length = length of bytes to read from slave. + * @param[out] data = databuffer to read from slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_LRD(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRD, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data); + wkc = ecx_srconfirm(port, idx, timeout); + if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRD)) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** LWR "logical memory write" primitive. Blocking. + * + * @param[in] port = port context struct + * @param[in] LogAdr = Logical memory address + * @param[in] length = length of databuffer + * @param[in] data = databuffer to write to slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_LWR(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout) +{ + uint8 idx; + int wkc; + + idx = ecx_getindex(port); + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LWR, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data); + wkc = ecx_srconfirm(port, idx, timeout); + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +/** LRW "logical memory read / write" primitive plus Clock Distribution. Blocking. + * Frame consists of two datagrams, one LRW and one FPRMW. + * + * @param[in] port = port context struct + * @param[in] LogAdr = Logical memory address + * @param[in] length = length of databuffer + * @param[in,out] data = databuffer to write to and read from slave. + * @param[in] DCrs = Distributed Clock reference slave address. + * @param[out] DCtime = DC time read from reference slave. + * @param[in] timeout = timeout in us, standard is EC_TIMEOUTRET + * @return Workcounter or EC_NOFRAME + */ +int ecx_LRWDC(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout) +{ + uint16 DCtO; + uint8 idx; + int wkc; + uint64 DCtE; + + idx = ecx_getindex(port); + /* LRW in first datagram */ + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data); + /* FPRMW in second datagram */ + DCtE = htoell(*DCtime); + DCtO = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, DCrs, ECT_REG_DCSYSTIME, sizeof(DCtime), &DCtE); + wkc = ecx_srconfirm(port, idx, timeout); + if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW)) + { + memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length); + memcpy(&wkc, &(port->rxbuf[idx][EC_HEADERSIZE + length]), EC_WKCSIZE); + memcpy(&DCtE, &(port->rxbuf[idx][DCtO]), sizeof(*DCtime)); + *DCtime = etohll(DCtE); + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + + return wkc; +} + +#ifdef EC_VER1 +int ec_setupdatagram(void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data) +{ + return ecx_setupdatagram (&ecx_port, frame, com, idx, ADP, ADO, length, data); +} + +int ec_adddatagram (void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data) +{ + return ecx_adddatagram (&ecx_port, frame, com, idx, more, ADP, ADO, length, data); +} + +int ec_BWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_BWR (&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_BRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_BRD(&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_APRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_APRD(&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_ARMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_ARMW(&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_FRMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_FRMW(&ecx_port, ADP, ADO, length, data, timeout); +} + +uint16 ec_APRDw(uint16 ADP, uint16 ADO, int timeout) +{ + uint16 w; + + w = 0; + ec_APRD(ADP, ADO, sizeof(w), &w, timeout); + + return w; +} + +int ec_FPRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_FPRD(&ecx_port, ADP, ADO, length, data, timeout); +} + +uint16 ec_FPRDw(uint16 ADP, uint16 ADO, int timeout) +{ + uint16 w; + + w = 0; + ec_FPRD(ADP, ADO, sizeof(w), &w, timeout); + return w; +} + +int ec_APWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_APWR(&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_APWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout) +{ + return ec_APWR(ADP, ADO, sizeof(data), &data, timeout); +} + +int ec_FPWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout) +{ + return ecx_FPWR(&ecx_port, ADP, ADO, length, data, timeout); +} + +int ec_FPWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout) +{ + return ec_FPWR(ADP, ADO, sizeof(data), &data, timeout); +} + +int ec_LRW(uint32 LogAdr, uint16 length, void *data, int timeout) +{ + return ecx_LRW(&ecx_port, LogAdr, length, data, timeout); +} + +int ec_LRD(uint32 LogAdr, uint16 length, void *data, int timeout) +{ + return ecx_LRD(&ecx_port, LogAdr, length, data, timeout); +} + +int ec_LWR(uint32 LogAdr, uint16 length, void *data, int timeout) +{ + return ecx_LWR(&ecx_port, LogAdr, length, data, timeout); +} + +int ec_LRWDC(uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout) +{ + return ecx_LRWDC(&ecx_port, LogAdr, length, data, DCrs, DCtime, timeout); +} +#endif \ No newline at end of file diff --git a/soem/ethercatbase.h b/soem/ethercatbase.h new file mode 100644 index 0000000..1931e44 --- /dev/null +++ b/soem/ethercatbase.h @@ -0,0 +1,98 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatbase.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatbase.c + */ + +#ifndef _ethercatbase_ +#define _ethercatbase_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +int ecx_setupdatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data); +int ecx_adddatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data); +int ecx_BWR(ecx_portt *port, uint16 ADP,uint16 ADO,uint16 length,void *data,int timeout); +int ecx_BRD(ecx_portt *port, uint16 ADP,uint16 ADO,uint16 length,void *data,int timeout); +int ecx_APRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ecx_ARMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ecx_FRMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +uint16 ecx_APRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout); +int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +uint16 ecx_FPRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout); +int ecx_APWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout); +int ecx_APWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ecx_FPWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout); +int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ecx_LRW(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout); +int ecx_LRD(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout); +int ecx_LWR(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout); +int ecx_LRWDC(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout); + +#ifdef EC_VER1 +int ec_setupdatagram(void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data); +int ec_adddatagram(void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data); +int ec_BWR(uint16 ADP,uint16 ADO,uint16 length,void *data,int timeout); +int ec_BRD(uint16 ADP,uint16 ADO,uint16 length,void *data,int timeout); +int ec_APRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ec_ARMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ec_FRMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +uint16 ec_APRDw(uint16 ADP, uint16 ADO, int timeout); +int ec_FPRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +uint16 ec_FPRDw(uint16 ADP, uint16 ADO, int timeout); +int ec_APWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout); +int ec_APWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ec_FPWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout); +int ec_FPWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout); +int ec_LRW(uint32 LogAdr, uint16 length, void *data, int timeout); +int ec_LRD(uint32 LogAdr, uint16 length, void *data, int timeout); +int ec_LWR(uint32 LogAdr, uint16 length, void *data, int timeout); +int ec_LRWDC(uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatcoe.c b/soem/ethercatcoe.c new file mode 100644 index 0000000..acb6050 --- /dev/null +++ b/soem/ethercatcoe.c @@ -0,0 +1,1412 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatcoe.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * CAN over EtherCAT (CoE) module. + * + * SDO read / write and SDO service functions + */ + +#include +#include +#include "osal.h" +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" + +/** SDO structure, not to be confused with EcSDOserviceT */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint16 CANOpen; + uint8 Command; + uint16 Index; + uint8 SubIndex; + union + { + uint8 bdata[0x200]; /* variants for easy data access */ + uint16 wdata[0x100]; + uint32 ldata[0x80]; + }; +} ec_SDOt; +PACKED_END + +/** SDO service structure */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint16 CANOpen; + uint8 Opcode; + uint8 Reserved; + uint16 Fragments; + union + { + uint8 bdata[0x200]; /* variants for easy data access */ + uint16 wdata[0x100]; + uint32 ldata[0x80]; + }; +} ec_SDOservicet; +PACKED_END + +/** Report SDO error. + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] Index = Index that generated error + * @param[in] SubIdx = Subindex that generated error + * @param[in] AbortCode = Abortcode, see EtherCAT documentation for list + */ +void ecx_SDOerror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Time = osal_current_time(); + Ec.Slave = Slave; + Ec.Index = Index; + Ec.SubIdx = SubIdx; + *(context->ecaterror) = TRUE; + Ec.Etype = EC_ERR_TYPE_SDO_ERROR; + Ec.AbortCode = AbortCode; + ecx_pusherror(context, &Ec); +} + +/** Report SDO info error + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] Index = Index that generated error + * @param[in] SubIdx = Subindex that generated error + * @param[in] AbortCode = Abortcode, see EtherCAT documentation for list + */ +static void ecx_SDOinfoerror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Slave = Slave; + Ec.Index = Index; + Ec.SubIdx = SubIdx; + *(context->ecaterror) = TRUE; + Ec.Etype = EC_ERR_TYPE_SDOINFO_ERROR; + Ec.AbortCode = AbortCode; + ecx_pusherror(context, &Ec); +} + +/** CoE SDO read, blocking. Single subindex or Complete Access. + * + * Only a "normal" upload request is issued. If the requested parameter is <= 4bytes + * then a "expedited" response is returned, otherwise a "normal" response. If a "normal" + * response is larger than the mailbox size then the response is segmented. The function + * will combine all segments and copy them to the parameter buffer. + * + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] index = Index to read + * @param[in] subindex = Subindex to read, must be 0 or 1 if CA is used. + * @param[in] CA = FALSE = single subindex. TRUE = Complete Access, all subindexes read. + * @param[in,out] psize = Size in bytes of parameter buffer, returns bytes read from SDO. + * @param[out] p = Pointer to parameter buffer + * @param[in] timeout = Timeout in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, + boolean CA, int *psize, void *p, int timeout) +{ + ec_SDOt *SDOp, *aSDOp; + uint16 bytesize, Framedatasize; + int wkc; + int32 SDOlen; + uint8 *bp; + uint8 *hp; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt, toggle; + boolean NotLast; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOt *)&MbxIn; + SDOp = (ec_SDOt *)&MbxOut; + SDOp->MbxHeader.length = htoes(0x000a); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox count value, used as session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits (SDO request) */ + if (CA) + { + SDOp->Command = ECT_SDO_UP_REQ_CA; /* upload request complete access */ + } + else + { + SDOp->Command = ECT_SDO_UP_REQ; /* upload request normal */ + } + SDOp->Index = htoes(index); + if (CA && (subindex > 1)) + { + subindex = 1; + } + SDOp->SubIndex = subindex; + SDOp->ldata[0] = 0; + /* send CoE request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) /* succeeded to place mailbox in slave ? */ + { + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + /* slave response should be CoE, SDO response and the correct index */ + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) && + (aSDOp->Index == SDOp->Index)) + { + if ((aSDOp->Command & 0x02) > 0) + { + /* expedited frame response */ + bytesize = 4 - ((aSDOp->Command >> 2) & 0x03); + if (*psize >= bytesize) /* parameter buffer big enough ? */ + { + /* copy parameter in parameter buffer */ + memcpy(p, &aSDOp->ldata[0], bytesize); + /* return the real parameter size */ + *psize = bytesize; + } + else + { + wkc = 0; + ecx_packeterror(context, slave, index, subindex, 3); /* data container too small for type */ + } + } + else + { /* normal frame response */ + SDOlen = etohl(aSDOp->ldata[0]); + /* Does parameter fit in parameter buffer ? */ + if (SDOlen <= *psize) + { + bp = p; + hp = p; + /* calculate mailbox transfer size */ + Framedatasize = (etohs(aSDOp->MbxHeader.length) - 10); + if (Framedatasize < SDOlen) /* transfer in segments? */ + { + /* copy parameter data in parameter buffer */ + memcpy(hp, &aSDOp->ldata[1], Framedatasize); + /* increment buffer pointer */ + hp += Framedatasize; + *psize = Framedatasize; + NotLast = TRUE; + toggle= 0x00; + while (NotLast) /* segmented transfer */ + { + SDOp = (ec_SDOt *)&MbxOut; + SDOp->MbxHeader.length = htoes(0x000a); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits (SDO request) */ + SDOp->Command = ECT_SDO_SEG_UP_REQ + toggle; /* segment upload request */ + SDOp->Index = htoes(index); + SDOp->SubIndex = subindex; + SDOp->ldata[0] = 0; + /* send segmented upload request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + /* is mailbox transfered to slave ? */ + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + /* has slave responded ? */ + if (wkc > 0) + { + /* slave response should be CoE, SDO response */ + if ((((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) && + ((aSDOp->Command & 0xe0) == 0x00))) + { + /* calculate mailbox transfer size */ + Framedatasize = etohs(aSDOp->MbxHeader.length) - 3; + if ((aSDOp->Command & 0x01) > 0) + { /* last segment */ + NotLast = FALSE; + if (Framedatasize == 7) + /* substract unused bytes from frame */ + Framedatasize = Framedatasize - ((aSDOp->Command & 0x0e) >> 1); + /* copy to parameter buffer */ + memcpy(hp, &(aSDOp->Index), Framedatasize); + } + else /* segments follow */ + { + /* copy to parameter buffer */ + memcpy(hp, &(aSDOp->Index), Framedatasize); + /* increment buffer pointer */ + hp += Framedatasize; + } + /* update parametersize */ + *psize += Framedatasize; + } + /* unexpected frame returned from slave */ + else + { + NotLast = FALSE; + if ((aSDOp->Command) == ECT_SDO_ABORT) /* SDO abort frame received */ + ecx_SDOerror(context, slave, index, subindex, etohl(aSDOp->ldata[0])); + else + ecx_packeterror(context, slave, index, subindex, 1); /* Unexpected frame returned */ + wkc = 0; + } + } + } + toggle = toggle ^ 0x10; /* toggle bit for segment request */ + } + } + /* non segmented transfer */ + else + { + /* copy to parameter buffer */ + memcpy(bp, &aSDOp->ldata[1], SDOlen); + *psize = SDOlen; + } + } + /* parameter buffer too small */ + else + { + wkc = 0; + ecx_packeterror(context, slave, index, subindex, 3); /* data container too small for type */ + } + } + } + /* other slave response */ + else + { + if ((aSDOp->Command) == ECT_SDO_ABORT) /* SDO abort frame received */ + { + ecx_SDOerror(context, slave, index, subindex, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, slave, index, subindex, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + return wkc; +} + +/** CoE SDO write, blocking. Single subindex or Complete Access. + * + * A "normal" download request is issued, unless we have + * small data, then a "expedited" transfer is used. If the parameter is larger than + * the mailbox size then the download is segmented. The function will split the + * parameter data in segments and send them to the slave one by one. + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] Index = Index to write + * @param[in] SubIndex = Subindex to write, must be 0 or 1 if CA is used. + * @param[in] CA = FALSE = single subindex. TRUE = Complete Access, all subindexes written. + * @param[in] psize = Size in bytes of parameter buffer. + * @param[out] p = Pointer to parameter buffer + * @param[in] Timeout = Timeout in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex, + boolean CA, int psize, void *p, int Timeout) +{ + ec_SDOt *SDOp, *aSDOp; + int wkc, maxdata; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt, toggle; + uint16 framedatasize; + boolean NotLast; + uint8 *hp; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOt *)&MbxIn; + SDOp = (ec_SDOt *)&MbxOut; + maxdata = context->slavelist[Slave].mbx_l - 0x10; /* data section=mailbox size - 6 mbx - 2 CoE - 8 sdo req */ + /* if small data use expedited transfer */ + if ((psize <= 4) && !CA) + { + SDOp->MbxHeader.length = htoes(0x000a); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox counter, used for session handle */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits */ + SDOp->Command = ECT_SDO_DOWN_EXP | (((4 - psize) << 2) & 0x0c); /* expedited SDO download transfer */ + SDOp->Index = htoes(Index); + SDOp->SubIndex = SubIndex; + hp = p; + /* copy parameter data to mailbox */ + memcpy(&SDOp->ldata[0], hp, psize); + /* send mailbox SDO download request to slave */ + wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout); + if (wkc > 0) + { + /* response should be CoE, SDO response, correct index and subindex */ + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) && + (aSDOp->Index == SDOp->Index) && + (aSDOp->SubIndex == SDOp->SubIndex)) + { + /* all OK */ + } + /* unexpected response from slave */ + else + { + if (aSDOp->Command == ECT_SDO_ABORT) /* SDO abort frame received */ + { + ecx_SDOerror(context, Slave, Index, SubIndex, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, Slave, Index, SubIndex, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + } + else + { + framedatasize = psize; + NotLast = FALSE; + if (framedatasize > maxdata) + { + framedatasize = maxdata; /* segmented transfer needed */ + NotLast = TRUE; + } + SDOp->MbxHeader.length = htoes(0x0a + framedatasize); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox counter, used for session handle */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits */ + if (CA) + { + SDOp->Command = ECT_SDO_DOWN_INIT_CA; /* Complete Access, normal SDO init download transfer */ + } + else + { + SDOp->Command = ECT_SDO_DOWN_INIT; /* normal SDO init download transfer */ + } + SDOp->Index = htoes(Index); + SDOp->SubIndex = SubIndex; + if (CA && (SubIndex > 1)) + { + SDOp->SubIndex = 1; + } + SDOp->ldata[0] = htoel(psize); + hp = p; + /* copy parameter data to mailbox */ + memcpy(&SDOp->ldata[1], hp, framedatasize); + hp += framedatasize; + psize -= framedatasize; + /* send mailbox SDO download request to slave */ + wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout); + if (wkc > 0) + { + /* response should be CoE, SDO response, correct index and subindex */ + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) && + (aSDOp->Index == SDOp->Index) && + (aSDOp->SubIndex == SDOp->SubIndex)) + { + /* all ok */ + maxdata += 7; + toggle = 0; + /* repeat while segments left */ + while (NotLast) + { + SDOp = (ec_SDOt *)&MbxOut; + framedatasize = psize; + NotLast = FALSE; + SDOp->Command = 0x01; /* last segment */ + if (framedatasize > maxdata) + { + framedatasize = maxdata; /* more segments needed */ + NotLast = TRUE; + SDOp->Command = 0x00; /* segments follow */ + } + if (!NotLast && (framedatasize < 7)) + { + SDOp->MbxHeader.length = htoes(0x0a); /* minimum size */ + SDOp->Command = 0x01 + ((7 - framedatasize) << 1); /* last segment reduced octets */ + } + else + { + SDOp->MbxHeader.length = htoes(framedatasize + 3); /* data + 2 CoE + 1 SDO */ + } + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox counter value */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOREQ << 12)); /* number 9bits service upper 4 bits (SDO request) */ + SDOp->Command = SDOp->Command + toggle; /* add toggle bit to command byte */ + /* copy parameter data to mailbox */ + memcpy(&SDOp->Index, hp, framedatasize); + /* update parameter buffer pointer */ + hp += framedatasize; + psize -= framedatasize; + /* send SDO download request */ + wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, Timeout); + if (wkc > 0) + { + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_SDORES) && + ((aSDOp->Command & 0xe0) == 0x20)) + { + /* all OK, nothing to do */ + } + else + { + if (aSDOp->Command == ECT_SDO_ABORT) /* SDO abort frame received */ + { + ecx_SDOerror(context, Slave, Index, SubIndex, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, Slave, Index, SubIndex, 1); /* Unexpected frame returned */ + } + wkc = 0; + NotLast = FALSE; + } + } + } + toggle = toggle ^ 0x10; /* toggle bit for segment request */ + } + } + /* unexpected response from slave */ + else + { + if (aSDOp->Command == ECT_SDO_ABORT) /* SDO abort frame received */ + { + ecx_SDOerror(context, Slave, Index, SubIndex, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, Slave, Index, SubIndex, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + } + + return wkc; +} + +/** CoE RxPDO write, blocking. + * + * A RxPDO download request is issued. + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] RxPDOnumber = Related RxPDO number + * @param[in] psize = Size in bytes of PDO buffer. + * @param[out] p = Pointer to PDO buffer + * @return Workcounter from last slave response + */ +int ecx_RxPDO(ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize, void *p) +{ + ec_SDOt *SDOp; + int wkc, maxdata; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + uint16 framedatasize; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, Slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + SDOp = (ec_SDOt *)&MbxOut; + maxdata = context->slavelist[Slave].mbx_l - 0x08; /* data section=mailbox size - 6 mbx - 2 CoE */ + framedatasize = psize; + if (framedatasize > maxdata) + { + framedatasize = maxdata; /* limit transfer */ + } + SDOp->MbxHeader.length = htoes(0x02 + framedatasize); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox counter, used for session handle */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes((RxPDOnumber & 0x01ff) + (ECT_COES_RXPDO << 12)); /* number 9bits service upper 4 bits */ + /* copy PDO data to mailbox */ + memcpy(&SDOp->Command, p, framedatasize); + /* send mailbox RxPDO request to slave */ + wkc = ecx_mbxsend(context, Slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + + return wkc; +} + +/** CoE TxPDO read remote request, blocking. + * + * A RxPDO download request is issued. + * + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] TxPDOnumber = Related TxPDO number + * @param[in,out] psize = Size in bytes of PDO buffer, returns bytes read from PDO. + * @param[out] p = Pointer to PDO buffer + * @param[in] timeout = Timeout in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber , int *psize, void *p, int timeout) +{ + ec_SDOt *SDOp, *aSDOp; + int wkc; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + uint16 framedatasize; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOt *)&MbxIn; + SDOp = (ec_SDOt *)&MbxOut; + SDOp->MbxHeader.length = htoes(0x02); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* get new mailbox counter, used for session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes((TxPDOnumber & 0x01ff) + (ECT_COES_TXPDO_RR << 12)); /* number 9bits service upper 4 bits */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) + { + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + /* slave response should be CoE, TxPDO */ + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((etohs(aSDOp->CANOpen) >> 12) == ECT_COES_TXPDO)) + { + /* TxPDO response */ + framedatasize = (aSDOp->MbxHeader.length - 2); + if (*psize >= framedatasize) /* parameter buffer big enough ? */ + { + /* copy parameter in parameter buffer */ + memcpy(p, &aSDOp->Command, framedatasize); + /* return the real parameter size */ + *psize = framedatasize; + } + /* parameter buffer too small */ + else + { + wkc = 0; + ecx_packeterror(context, slave, 0, 0, 3); /* data container too small for type */ + } + } + /* other slave response */ + else + { + if ((aSDOp->Command) == ECT_SDO_ABORT) /* SDO abort frame received */ + { + ecx_SDOerror(context, slave, 0, 0, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, slave, 0, 0, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + + return wkc; +} + +/** Read PDO assign structure + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] PDOassign = PDO assign object + * @return total bitlength of PDO assign + */ +int ecx_readPDOassign(ecx_contextt *context, uint16 Slave, uint16 PDOassign) +{ + uint16 idxloop, nidx, subidxloop, rdat, idx, subidx; + uint8 subcnt; + int wkc, bsize = 0, rdl; + int32 rdat2; + + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign subindex 0 ( = number of PDO's) */ + wkc = ecx_SDOread(context, Slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + rdat = etohs(rdat); + /* positive result from slave ? */ + if ((wkc > 0) && (rdat > 0)) + { + /* number of available sub indexes */ + nidx = rdat; + bsize = 0; + /* read all PDO's */ + for (idxloop = 1; idxloop <= nidx; idxloop++) + { + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign */ + wkc = ecx_SDOread(context, Slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + /* result is index of PDO */ + idx = etohl(rdat); + if (idx > 0) + { + rdl = sizeof(subcnt); subcnt = 0; + /* read number of subindexes of PDO */ + wkc = ecx_SDOread(context, Slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM); + subidx = subcnt; + /* for each subindex */ + for (subidxloop = 1; subidxloop <= subidx; subidxloop++) + { + rdl = sizeof(rdat2); rdat2 = 0; + /* read SDO that is mapped in PDO */ + wkc = ecx_SDOread(context, Slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM); + rdat2 = etohl(rdat2); + /* extract bitlength of SDO */ + if (LO_BYTE(rdat2) < 0xff) + { + bsize += LO_BYTE(rdat2); + } + else + { + rdl = sizeof(rdat); rdat = htoes(0xff); + /* read Object Entry in Object database */ +// wkc = ec_readOEsingle(idx, (uint8)SubCount, pODlist, pOElist); + bsize += etohs(rdat); + } + } + } + } + } + /* return total found bitlength (PDO) */ + return bsize; +} + +/** Read PDO assign structure in Complete Access mode + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] PDOassign = PDO assign object + * @return total bitlength of PDO assign + */ +int ecx_readPDOassignCA(ecx_contextt *context, uint16 Slave, uint16 PDOassign) +{ + uint16 idxloop, nidx, subidxloop, idx, subidx; + int wkc, bsize = 0, rdl; + + /* find maximum size of PDOassign buffer */ + rdl = sizeof(ec_PDOassignt); + context->PDOassign->n=0; + /* read rxPDOassign in CA mode, all subindexes are read in one struct */ + wkc = ecx_SDOread(context, Slave, PDOassign, 0x00, TRUE, &rdl, context->PDOassign, EC_TIMEOUTRXM); + /* positive result from slave ? */ + if ((wkc > 0) && (context->PDOassign->n > 0)) + { + nidx = context->PDOassign->n; + bsize = 0; + /* for each PDO do */ + for (idxloop = 1; idxloop <= nidx; idxloop++) + { + /* get index from PDOassign struct */ + idx = etohs(context->PDOassign->index[idxloop - 1]); + if (idx > 0) + { + rdl = sizeof(ec_PDOdesct); context->PDOdesc->n = 0; + /* read SDO's that are mapped in PDO, CA mode */ + wkc = ecx_SDOread(context, Slave,idx, 0x00, TRUE, &rdl, context->PDOdesc, EC_TIMEOUTRXM); + subidx = context->PDOdesc->n; + /* extract all bitlengths of SDO's */ + for (subidxloop = 1; subidxloop <= subidx; subidxloop++) + { + bsize += LO_BYTE(etohl(context->PDOdesc->PDO[subidxloop -1])); + } + } + } + } + + /* return total found bitlength (PDO) */ + return bsize; +} + +/** CoE read PDO mapping. + * + * CANopen has standard indexes defined for PDO mapping. This function + * tries to read them and collect a full input and output mapping size + * of designated slave. + * + * Principal structure in slave:\n + * 1C00:00 is number of SM defined\n + * 1C00:01 SM0 type -> 1C10\n + * 1C00:02 SM1 type -> 1C11\n + * 1C00:03 SM2 type -> 1C12\n + * 1C00:04 SM3 type -> 1C13\n + * Type 0 = unused, 1 = mailbox in, 2 = mailbox out, + * 3 = outputs (RxPDO), 4 = inputs (TxPDO). + * + * 1C12:00 is number of PDO's defined for SM2\n + * 1C12:01 PDO assign SDO #1 -> f.e. 1A00\n + * 1C12:02 PDO assign SDO #2 -> f.e. 1A04\ + * + * 1A00:00 is number of object defined for this PDO\n + * 1A00:01 object mapping #1, f.e. 60100710 (SDO 6010 SI 07 bitlength 0x10) + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[out] Osize = Size in bits of output mapping (rxPDO) found + * @param[out] Isize = Size in bits of input mapping (txPDO) found + * @return >0 if mapping succesful. + */ +int ecx_readPDOmap(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize) +{ + int wkc, rdl; + int retVal = 0; + uint8 nSM, iSM, tSM; + int Tsize; + uint8 SMt_bug_add; + + *Isize = 0; + *Osize = 0; + SMt_bug_add = 0; + rdl = sizeof(nSM); nSM = 0; + /* read SyncManager Communication Type object count */ + wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM); + /* positive result from slave ? */ + if ((wkc > 0) && (nSM > 2)) + { + /* make nSM equal to number of defined SM */ + nSM--; + /* limit to maximum number of SM defined, if true the slave can't be configured */ + if (nSM > EC_MAXSM) + nSM = EC_MAXSM; + /* iterate for every SM type defined */ + for (iSM = 2 ; iSM <= nSM ; iSM++) + { + rdl = sizeof(tSM); tSM = 0; + /* read SyncManager Communication Type */ + wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM); + if (wkc > 0) + { +// start slave bug prevention code, remove if possible + if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave! + { + SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4 + } + if(tSM) + { + tSM += SMt_bug_add; // only add if SMt > 0 + } + if((iSM == 2) && (tSM == 0)) // SM2 has type 0, this is a bug in the slave! + { + tSM = 3; + } + if((iSM == 3) && (tSM == 0)) // SM3 has type 0, this is a bug in the slave! + { + tSM = 4; + } +// end slave bug prevention code + + context->slavelist[Slave].SMtype[iSM] = tSM; + /* check if SM is unused -> clear enable flag */ + if (tSM == 0) + { + context->slavelist[Slave].SM[iSM].SMflags = + htoel( etohl(context->slavelist[Slave].SM[iSM].SMflags) & EC_SMENABLEMASK); + } + if ((tSM == 3) || (tSM == 4)) + { + /* read the assign PDO */ + Tsize = ecx_readPDOassign(context, Slave, ECT_SDO_PDOASSIGN + iSM ); + /* if a mapping is found */ + if (Tsize) + { + context->slavelist[Slave].SM[iSM].SMlength = htoes((Tsize + 7) / 8); + if (tSM == 3) + { + /* we are doing outputs */ + *Osize += Tsize; + } + else + { + /* we are doing inputs */ + *Isize += Tsize; + } + } + } + } + } + } + + /* found some I/O bits ? */ + if ((*Isize > 0) || (*Osize > 0)) + { + retVal = 1; + } + + return retVal; +} + +/** CoE read PDO mapping in Complete Access mode (CA). + * + * CANopen has standard indexes defined for PDO mapping. This function + * tries to read them and collect a full input and output mapping size + * of designated slave. Slave has to support CA, otherwise use ec_readPDOmap(). + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[out] Osize = Size in bits of output mapping (rxPDO) found + * @param[out] Isize = Size in bits of input mapping (txPDO) found + * @return >0 if mapping succesful. + */ +int ecx_readPDOmapCA(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize) +{ + int wkc, rdl; + int retVal = 0; + uint8 nSM, iSM, tSM; + int Tsize; + uint8 SMt_bug_add; + + *Isize = 0; + *Osize = 0; + SMt_bug_add = 0; + rdl = sizeof(ec_SMcommtypet); + context->SMcommtype->n = 0; + /* read SyncManager Communication Type object count Complete Access*/ + wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, 0x00, TRUE, &rdl, context->SMcommtype, EC_TIMEOUTRXM); + /* positive result from slave ? */ + if ((wkc > 0) && (context->SMcommtype->n > 2)) + { + /* make nSM equal to number of defined SM */ + nSM = context->SMcommtype->n - 1; + /* limit to maximum number of SM defined, if true the slave can't be configured */ + if (nSM > EC_MAXSM) + { + nSM = EC_MAXSM; + ecx_packeterror(context, Slave, 0, 0, 10); /* #SM larger than EC_MAXSM */ + } + /* iterate for every SM type defined */ + for (iSM = 2 ; iSM <= nSM ; iSM++) + { + tSM = context->SMcommtype->SMtype[iSM]; + +// start slave bug prevention code, remove if possible + if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave! + { + SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4 + } + if(tSM) + { + tSM += SMt_bug_add; // only add if SMt > 0 + } +// end slave bug prevention code + + context->slavelist[Slave].SMtype[iSM] = tSM; + /* check if SM is unused -> clear enable flag */ + if (tSM == 0) + { + context->slavelist[Slave].SM[iSM].SMflags = + htoel( etohl(context->slavelist[Slave].SM[iSM].SMflags) & EC_SMENABLEMASK); + } + if ((tSM == 3) || (tSM == 4)) + { + /* read the assign PDO */ + Tsize = ecx_readPDOassignCA(context, Slave, ECT_SDO_PDOASSIGN + iSM ); + /* if a mapping is found */ + if (Tsize) + { + context->slavelist[Slave].SM[iSM].SMlength = htoes((Tsize + 7) / 8); + if (tSM == 3) + { + /* we are doing outputs */ + *Osize += Tsize; + } + else + { + /* we are doing inputs */ + *Isize += Tsize; + } + } + } + } + } + + /* found some I/O bits ? */ + if ((*Isize > 0) || (*Osize > 0)) + { + retVal = 1; + } + return retVal; +} + +/** CoE read Object Description List. + * + * @param[in] context = context struct + * @param[in] Slave = Slave number. + * @param[out] pODlist = resulting Object Description list. + * @return Workcounter of slave response. + */ +int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist) +{ + ec_SDOservicet *SDOp, *aSDOp; + ec_mbxbuft MbxIn, MbxOut; + int wkc; + uint16 x, n, i, sp, offset; + boolean stop; + uint8 cnt; + boolean First; + + pODlist->Slave = Slave; + pODlist->Entries = 0; + ec_clearmbx(&MbxIn); + /* clear pending out mailbox in slave if available. Timeout is set to 0 */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOservicet*)&MbxIn; + SDOp = (ec_SDOservicet*)&MbxOut; + SDOp->MbxHeader.length = htoes(0x0008); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* Get new mailbox counter value */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOINFO << 12)); /* number 9bits service upper 4 bits */ + SDOp->Opcode = ECT_GET_ODLIST_REQ; /* get object description list request */ + SDOp->Reserved = 0; + SDOp->Fragments = 0; /* fragments left */ + SDOp->wdata[0] = htoes(0x01); /* all objects */ + /* send get object description list request to slave */ + wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM); + /* mailbox placed in slave ? */ + if (wkc > 0) + { + x = 0; + sp = 0; + First = TRUE; + offset = 1; /* offset to skip info header in first frame, otherwise set to 0 */ + do + { + stop = TRUE; /* assume this is last iteration */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM); + /* got response ? */ + if (wkc > 0) + { + /* response should be CoE and "get object description list response" */ + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((aSDOp->Opcode & 0x7f) == ECT_GET_ODLIST_RES)) + { + if (First) + { + /* extract number of indexes from mailbox data size */ + n = (etohs(aSDOp->MbxHeader.length) - (6 + 2)) / 2; + } + else + { + /* extract number of indexes from mailbox data size */ + n = (etohs(aSDOp->MbxHeader.length) - 6) / 2; + } + /* check if indexes fit in buffer structure */ + if ((sp + n) > EC_MAXODLIST) + { + n = EC_MAXODLIST + 1 - sp; + ecx_SDOinfoerror(context, Slave, 0, 0, 0xf000000); /* Too many entries for master buffer */ + stop = TRUE; + } + /* trim to maximum number of ODlist entries defined */ + if ((pODlist->Entries + n) > EC_MAXODLIST) + { + n = EC_MAXODLIST - pODlist->Entries; + } + pODlist->Entries += n; + /* extract indexes one by one */ + for (i = 0; i < n; i++) + { + pODlist->Index[sp + i] = etohs(aSDOp->wdata[i + offset]); + } + sp += n; + /* check if more fragments will follow */ + if (aSDOp->Fragments > 0) + { + stop = FALSE; + } + First = FALSE; + offset = 0; + } + /* got unexpected response from slave */ + else + { + if ((aSDOp->Opcode & 0x7f) == ECT_SDOINFO_ERROR) /* SDO info error received */ + { + ecx_SDOinfoerror(context, Slave, 0, 0, etohl(aSDOp->ldata[0])); + stop = TRUE; + } + else + { + ecx_packeterror(context, Slave, 0, 0, 1); /* Unexpected frame returned */ + } + wkc = 0; + x += 20; + } + } + x++; + } + while ((x <= 128) && !stop); + } + return wkc; +} + +/** CoE read Object Description. Adds textual description to object indexes. + * + * @param[in] context = context struct + * @param[in] Item = Item number in ODlist. + * @param[in,out] pODlist = referencing Object Description list. + * @return Workcounter of slave response. + */ +int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist) +{ + ec_SDOservicet *SDOp, *aSDOp; + int wkc; + uint16 n, Slave; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + + Slave = pODlist->Slave; + pODlist->DataType[Item] = 0; + pODlist->ObjectCode[Item] = 0; + pODlist->MaxSub[Item] = 0; + pODlist->Name[Item][0] = 0; + ec_clearmbx(&MbxIn); + /* clear pending out mailbox in slave if available. Timeout is set to 0 */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOservicet*)&MbxIn; + SDOp = (ec_SDOservicet*)&MbxOut; + SDOp->MbxHeader.length = htoes(0x0008); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* Get new mailbox counter value */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOINFO << 12)); /* number 9bits service upper 4 bits */ + SDOp->Opcode = ECT_GET_OD_REQ; /* get object description request */ + SDOp->Reserved = 0; + SDOp->Fragments = 0; /* fragments left */ + SDOp->wdata[0] = htoes(pODlist->Index[Item]); /* Data of Index */ + /* send get object description request to slave */ + wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM); + /* mailbox placed in slave ? */ + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM); + /* got response ? */ + if (wkc > 0) + { + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((aSDOp->Opcode & 0x7f) == ECT_GET_OD_RES)) + { + n = (etohs(aSDOp->MbxHeader.length) - 12); /* length of string(name of object) */ + if (n > EC_MAXNAME) + { + n = EC_MAXNAME; /* max chars */ + } + pODlist->DataType[Item] = etohs(aSDOp->wdata[1]); + pODlist->ObjectCode[Item] = aSDOp->bdata[5]; + pODlist->MaxSub[Item] = aSDOp->bdata[4]; + + strncpy(pODlist->Name[Item] , (char *)&aSDOp->bdata[6], n); + pODlist->Name[Item][n] = 0x00; /* String terminator */ + } + /* got unexpected response from slave */ + else + { + if (((aSDOp->Opcode & 0x7f) == ECT_SDOINFO_ERROR)) /* SDO info error received */ + { + ecx_SDOinfoerror(context, Slave,pODlist->Index[Item], 0, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, Slave,pODlist->Index[Item], 0, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + + return wkc; +} + +/** CoE read SDO service object entry, single subindex. + * Used in ec_readOE(). + * + * @param[in] context = context struct + * @param[in] Item = Item in ODlist. + * @param[in] SubI = Subindex of item in ODlist. + * @param[in] pODlist = Object description list for reference. + * @param[out] pOElist = resulting object entry structure. + * @return Workcounter of slave response. + */ +int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist) +{ + ec_SDOservicet *SDOp, *aSDOp; + uint16 wkc, Index, Slave; + int16 n; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + + wkc = 0; + Slave = pODlist->Slave; + Index = pODlist->Index[Item]; + ec_clearmbx(&MbxIn); + /* clear pending out mailbox in slave if available. Timeout is set to 0 */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, 0); + ec_clearmbx(&MbxOut); + aSDOp = (ec_SDOservicet*)&MbxIn; + SDOp = (ec_SDOservicet*)&MbxOut; + SDOp->MbxHeader.length = htoes(0x000a); + SDOp->MbxHeader.address = htoes(0x0000); + SDOp->MbxHeader.priority = 0x00; + /* Get new mailbox counter value */ + cnt = ec_nextmbxcnt(context->slavelist[Slave].mbx_cnt); + context->slavelist[Slave].mbx_cnt = cnt; + SDOp->MbxHeader.mbxtype = ECT_MBXT_COE + (cnt << 4); /* CoE */ + SDOp->CANOpen = htoes(0x000 + (ECT_COES_SDOINFO << 12)); /* number 9bits service upper 4 bits */ + SDOp->Opcode = ECT_GET_OE_REQ; /* get object entry description request */ + SDOp->Reserved = 0; + SDOp->Fragments = 0; /* fragments left */ + SDOp->wdata[0] = htoes(Index); /* Index */ + SDOp->bdata[2] = SubI; /* SubIndex */ + SDOp->bdata[3] = 1 + 2 + 4; /* get access rights, object category, PDO */ + /* send get object entry description request to slave */ + wkc = ecx_mbxsend(context, Slave, &MbxOut, EC_TIMEOUTTXM); + /* mailbox placed in slave ? */ + if (wkc > 0) + { + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, Slave, &MbxIn, EC_TIMEOUTRXM); + /* got response ? */ + if (wkc > 0) + { + if (((aSDOp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_COE) && + ((aSDOp->Opcode & 0x7f) == ECT_GET_OE_RES)) + { + pOElist->Entries++; + n = (etohs(aSDOp->MbxHeader.length) - 16); /* length of string(name of object) */ + if (n > EC_MAXNAME) + { + n = EC_MAXNAME; /* max string length */ + } + if (n < 0 ) + { + n = 0; + } + pOElist->ValueInfo[SubI] = aSDOp->bdata[3]; + pOElist->DataType[SubI] = etohs(aSDOp->wdata[2]); + pOElist->BitLength[SubI] = etohs(aSDOp->wdata[3]); + pOElist->ObjAccess[SubI] = etohs(aSDOp->wdata[4]); + + strncpy(pOElist->Name[SubI] , (char *)&aSDOp->wdata[5], n); + pOElist->Name[SubI][n] = 0x00; /* string terminator */ + } + /* got unexpected response from slave */ + else + { + if (((aSDOp->Opcode & 0x7f) == ECT_SDOINFO_ERROR)) /* SDO info error received */ + { + ecx_SDOinfoerror(context, Slave, Index, SubI, etohl(aSDOp->ldata[0])); + } + else + { + ecx_packeterror(context, Slave, Index, SubI, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + } + + return wkc; +} + +/** CoE read SDO service object entry. + * + * @param[in] context = context struct + * @param[in] Item = Item in ODlist. + * @param[in] pODlist = Object description list for reference. + * @param[out] pOElist = resulting object entry structure. + * @return Workcounter of slave response. + */ +int ecx_readOE(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist) +{ + uint16 SubCount; + int wkc; + uint8 SubI; + + wkc = 0; + pOElist->Entries = 0; + SubI = pODlist->MaxSub[Item]; + /* for each entry found in ODlist */ + for (SubCount = 0; SubCount <= SubI; SubCount++) + { + /* read subindex of entry */ + wkc = ecx_readOEsingle(context, Item, (uint8)SubCount, pODlist, pOElist); + } + + return wkc; +} + +#ifdef EC_VER1 +void ec_SDOerror(uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode) +{ + ecx_SDOerror(&ecx_context, Slave, Index, SubIdx, AbortCode); +} + +int ec_SDOread(uint16 slave, uint16 index, uint8 subindex, + boolean CA, int *psize, void *p, int timeout) +{ + return ecx_SDOread(&ecx_context, slave, index, subindex, CA, psize, p, timeout); +} + +int ec_SDOwrite(uint16 Slave, uint16 Index, uint8 SubIndex, + boolean CA, int psize, void *p, int Timeout) +{ + return ecx_SDOwrite(&ecx_context, Slave, Index, SubIndex, CA, psize, p, Timeout); +} + +int ec_RxPDO(uint16 Slave, uint16 RxPDOnumber, int psize, void *p) +{ + return ecx_RxPDO(&ecx_context, Slave, RxPDOnumber, psize, p); +} + +int ec_TxPDO(uint16 slave, uint16 TxPDOnumber , int *psize, void *p, int timeout) +{ + return ecx_TxPDO(&ecx_context, slave, TxPDOnumber, psize, p, timeout); +} + +/** Read PDO assign structure */ +int ec_readPDOassign(uint16 Slave, uint16 PDOassign) +{ + return ecx_readPDOassign(&ecx_context, Slave, PDOassign); +} + +/** Read PDO assign structure in Complete Access mode */ +int ec_readPDOassignCA(uint16 Slave, uint16 PDOassign) +{ + return ecx_readPDOassignCA(&ecx_context, Slave, PDOassign); +} + +int ec_readPDOmap(uint16 Slave, int *Osize, int *Isize) +{ + return ecx_readPDOmap(&ecx_context, Slave, Osize, Isize); +} + +int ec_readPDOmapCA(uint16 Slave, int *Osize, int *Isize) +{ + return ecx_readPDOmapCA(&ecx_context, Slave, Osize, Isize); +} + +int ec_readODlist(uint16 Slave, ec_ODlistt *pODlist) +{ + return ecx_readODlist(&ecx_context, Slave, pODlist); +} + +int ec_readODdescription(uint16 Item, ec_ODlistt *pODlist) +{ + return ecx_readODdescription(&ecx_context, Item, pODlist); +} + +int ec_readOEsingle(uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist) +{ + return ecx_readOEsingle(&ecx_context, Item, SubI, pODlist, pOElist); +} + +int ec_readOE(uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist) +{ + return ecx_readOE(&ecx_context, Item, pODlist, pOElist); +} +#endif diff --git a/soem/ethercatcoe.h b/soem/ethercatcoe.h new file mode 100644 index 0000000..cada6e1 --- /dev/null +++ b/soem/ethercatcoe.h @@ -0,0 +1,130 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatcoe.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatcoe.c + */ + +#ifndef _ethercatcoe_ +#define _ethercatcoe_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** max entries in Object Description list */ +#define EC_MAXODLIST 1024 + +/** max entries in Object Entry list */ +#define EC_MAXOELIST 256 + +/* Storage for object description list */ +typedef struct +{ + /** slave number */ + uint16 Slave; + /** number of entries in list */ + uint16 Entries; + /** array of indexes */ + uint16 Index[EC_MAXODLIST]; + /** array of datatypes, see EtherCAT specification */ + uint16 DataType[EC_MAXODLIST]; + /** array of object codes, see EtherCAT specification */ + uint8 ObjectCode[EC_MAXODLIST]; + /** number of subindexes for each index */ + uint8 MaxSub[EC_MAXODLIST]; + /** textual description of each index */ + char Name[EC_MAXODLIST][EC_MAXNAME+1]; +} ec_ODlistt; + +/* storage for object list entry information */ +typedef struct +{ + /** number of entries in list */ + uint16 Entries; + /** array of value infos, see EtherCAT specification */ + uint8 ValueInfo[EC_MAXOELIST]; + /** array of value infos, see EtherCAT specification */ + uint16 DataType[EC_MAXOELIST]; + /** array of bit lengths, see EtherCAT specification */ + uint16 BitLength[EC_MAXOELIST]; + /** array of object access bits, see EtherCAT specification */ + uint16 ObjAccess[EC_MAXOELIST]; + /** textual description of each index */ + char Name[EC_MAXOELIST][EC_MAXNAME+1]; +} ec_OElistt; + +#ifdef EC_VER1 +void ec_SDOerror(uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode); +int ec_SDOread(uint16 slave, uint16 index, uint8 subindex, + boolean CA, int *psize, void *p, int timeout); +int ec_SDOwrite(uint16 Slave, uint16 Index, uint8 SubIndex, + boolean CA, int psize, void *p, int Timeout); +int ec_RxPDO(uint16 Slave, uint16 RxPDOnumber , int psize, void *p); +int ec_TxPDO(uint16 slave, uint16 TxPDOnumber , int *psize, void *p, int timeout); +int ec_readPDOmap(uint16 Slave, int *Osize, int *Isize); +int ec_readPDOmapCA(uint16 Slave, int *Osize, int *Isize); +int ec_readODlist(uint16 Slave, ec_ODlistt *pODlist); +int ec_readODdescription(uint16 Item, ec_ODlistt *pODlist); +int ec_readOEsingle(uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist); +int ec_readOE(uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist); +#endif + +void ecx_SDOerror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode); +int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex, + boolean CA, int *psize, void *p, int timeout); +int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex, + boolean CA, int psize, void *p, int Timeout); +int ecx_RxPDO(ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber , int psize, void *p); +int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber , int *psize, void *p, int timeout); +int ecx_readPDOmap(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize); +int ecx_readPDOmapCA(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize); +int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist); +int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist); +int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist); +int ecx_readOE(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatconfig.c b/soem/ethercatconfig.c new file mode 100644 index 0000000..f0fd590 --- /dev/null +++ b/soem/ethercatconfig.c @@ -0,0 +1,1429 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatconfig.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Configuration module for EtherCAT master. + * + * After successful initialisation with ec_init() or ec_init_redundant() + * the slaves can be auto configured with this module. + */ + +#include +#include +#include "osal.h" +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatsoe.h" +#include "ethercatconfig.h" + +// define if debug printf is needed +//#define EC_DEBUG + +#ifdef EC_DEBUG +#define EC_PRINT printf +#else +#define EC_PRINT(...) do {} while (0) +#endif + +/* define maximum number of concurrent threads in mapping */ +#define MAX_MAPT 8 + +typedef struct +{ + int running; + ecx_contextt *context; + uint16 slave; +} ecx_mapt_t; + +ecx_mapt_t ecx_mapt[MAX_MAPT]; +OSAL_THREAD_HANDLE ecx_threadh[MAX_MAPT]; + +#ifdef EC_VER1 +/** Slave configuration structure */ +typedef const struct +{ + /** Manufacturer code of slave */ + uint32 man; + /** ID of slave */ + uint32 id; + /** Readable name */ + char name[EC_MAXNAME + 1]; + /** Data type */ + uint8 Dtype; + /** Input bits */ + uint16 Ibits; + /** Output bits */ + uint16 Obits; + /** SyncManager 2 address */ + uint16 SM2a; + /** SyncManager 2 flags */ + uint32 SM2f; + /** SyncManager 3 address */ + uint16 SM3a; + /** SyncManager 3 flags */ + uint32 SM3f; + /** FMMU 0 activation */ + uint8 FM0ac; + /** FMMU 1 activation */ + uint8 FM1ac; +} ec_configlist_t; + +#include "ethercatconfiglist.h" +#endif + +/** standard SM0 flags configuration for mailbox slaves */ +#define EC_DEFAULTMBXSM0 0x00010026 +/** standard SM1 flags configuration for mailbox slaves */ +#define EC_DEFAULTMBXSM1 0x00010022 +/** standard SM0 flags configuration for digital output slaves */ +#define EC_DEFAULTDOSM0 0x00010044 + +#ifdef EC_VER1 +/** Find slave in standard configuration list ec_configlist[] + * + * @param[in] man = manufacturer + * @param[in] id = ID + * @return index in ec_configlist[] when found, otherwise 0 + */ +int ec_findconfig( uint32 man, uint32 id) +{ + int i = 0; + + do + { + i++; + } while ( (ec_configlist[i].man != EC_CONFIGEND) && + ((ec_configlist[i].man != man) || (ec_configlist[i].id != id)) ); + if (ec_configlist[i].man == EC_CONFIGEND) + { + i = 0; + } + return i; +} +#endif + +void ecx_init_context(ecx_contextt *context) +{ + int lp; + *(context->slavecount) = 0; + /* clean ec_slave array */ + memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave); + memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup); + /* clear slave eeprom cache, does not actually read any eeprom */ + ecx_siigetbyte(context, 0, EC_MAXEEPBUF); + for(lp = 0; lp < context->maxgroup; lp++) + { + context->grouplist[lp].logstartaddr = lp << 16; /* default start address per group entry */ + } +} + +int ecx_detect_slaves(ecx_contextt *context) +{ + uint8 b; + uint16 w; + int wkc; + + /* make special pre-init register writes to enable MAC[1] local administered bit * + * setting for old netX100 slaves */ + b = 0x00; + ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS, sizeof(b), &b, EC_TIMEOUTRET3); /* Ignore Alias register */ + b = EC_STATE_INIT | EC_STATE_ACK; + ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3); /* Reset all slaves to Init */ + /* netX100 should now be happy */ + ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3); /* Reset all slaves to Init */ + wkc = ecx_BRD(context->port, 0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE); /* detect number of slaves */ + if (wkc > 0) + { + *(context->slavecount) = wkc; + } + return wkc; +} + +static void ecx_set_slaves_to_default(ecx_contextt *context) +{ + uint8 b; + uint16 w; + uint8 zbuf[64]; + memset(&zbuf, 0x00, sizeof(zbuf)); + b = 0x00; + ecx_BWR(context->port, 0x0000, ECT_REG_DLPORT , sizeof(b) , &b, EC_TIMEOUTRET3); /* deact loop manual */ + w = htoes(0x0004); + ecx_BWR(context->port, 0x0000, ECT_REG_IRQMASK , sizeof(w) , &w, EC_TIMEOUTRET3); /* set IRQ mask */ + ecx_BWR(context->port, 0x0000, ECT_REG_RXERR , 8 , &zbuf, EC_TIMEOUTRET3); /* reset CRC counters */ + ecx_BWR(context->port, 0x0000, ECT_REG_FMMU0 , 16 * 3 , &zbuf, EC_TIMEOUTRET3); /* reset FMMU's */ + ecx_BWR(context->port, 0x0000, ECT_REG_SM0 , 8 * 4 , &zbuf, EC_TIMEOUTRET3); /* reset SyncM */ + ecx_BWR(context->port, 0x0000, ECT_REG_DCSYSTIME , 4 , &zbuf, EC_TIMEOUTRET3); /* reset system time+ofs */ + w = htoes(0x1000); + ecx_BWR(context->port, 0x0000, ECT_REG_DCSPEEDCNT , sizeof(w) , &w, EC_TIMEOUTRET3); /* DC speedstart */ + w = htoes(0x0c00); + ecx_BWR(context->port, 0x0000, ECT_REG_DCTIMEFILT , sizeof(w) , &w, EC_TIMEOUTRET3); /* DC filt expr */ + b = 0x00; + ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS , sizeof(b) , &b, EC_TIMEOUTRET3); /* Ignore Alias register */ + b = EC_STATE_INIT | EC_STATE_ACK; + ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL , sizeof(b) , &b, EC_TIMEOUTRET3); /* Reset all slaves to Init */ + b = 2; + ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG , sizeof(b) , &b, EC_TIMEOUTRET3); /* force Eeprom from PDI */ + b = 0; + ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG , sizeof(b) , &b, EC_TIMEOUTRET3); /* set Eeprom to master */ +} + +#ifdef EC_VER1 +static int ecx_config_from_table(ecx_contextt *context, uint16 slave) +{ + int cindex; + ec_slavet *csl; + + csl = &(context->slavelist[slave]); + cindex = ec_findconfig( csl->eep_man, csl->eep_id ); + csl->configindex= cindex; + /* slave found in configuration table ? */ + if (cindex) + { + csl->Dtype = ec_configlist[cindex].Dtype; + strcpy(csl->name ,ec_configlist[cindex].name); + csl->Ibits = ec_configlist[cindex].Ibits; + csl->Obits = ec_configlist[cindex].Obits; + if (csl->Obits) + { + csl->FMMU0func = 1; + } + if (csl->Ibits) + { + csl->FMMU1func = 2; + } + csl->FMMU[0].FMMUactive = ec_configlist[cindex].FM0ac; + csl->FMMU[1].FMMUactive = ec_configlist[cindex].FM1ac; + csl->SM[2].StartAddr = htoes(ec_configlist[cindex].SM2a); + csl->SM[2].SMflags = htoel(ec_configlist[cindex].SM2f); + /* simple (no mailbox) output slave found ? */ + if (csl->Obits && !csl->SM[2].StartAddr) + { + csl->SM[0].StartAddr = htoes(0x0f00); + csl->SM[0].SMlength = htoes((csl->Obits + 7) / 8); + csl->SM[0].SMflags = htoel(EC_DEFAULTDOSM0); + csl->FMMU[0].FMMUactive = 1; + csl->FMMU[0].FMMUtype = 2; + csl->SMtype[0] = 3; + } + /* complex output slave */ + else + { + csl->SM[2].SMlength = htoes((csl->Obits + 7) / 8); + csl->SMtype[2] = 3; + } + csl->SM[3].StartAddr = htoes(ec_configlist[cindex].SM3a); + csl->SM[3].SMflags = htoel(ec_configlist[cindex].SM3f); + /* simple (no mailbox) input slave found ? */ + if (csl->Ibits && !csl->SM[3].StartAddr) + { + csl->SM[1].StartAddr = htoes(0x1000); + csl->SM[1].SMlength = htoes((csl->Ibits + 7) / 8); + csl->SM[1].SMflags = htoel(0x00000000); + csl->FMMU[1].FMMUactive = 1; + csl->FMMU[1].FMMUtype = 1; + csl->SMtype[1] = 4; + } + /* complex input slave */ + else + { + csl->SM[3].SMlength = htoes((csl->Ibits + 7) / 8); + csl->SMtype[3] = 4; + } + } + return cindex; +} +#else +static int ecx_config_from_table(ecx_contextt *context, uint16 slave) +{ + return 0; +} +#endif + +/* If slave has SII and same slave ID done before, use previous data. + * This is safe because SII is constant for same slave ID. + */ +static int ecx_lookup_prev_sii(ecx_contextt *context, uint16 slave) +{ + int i, nSM; + if ((slave > 1) && (*(context->slavecount) > 0)) + { + i = 1; + while(((context->slavelist[i].eep_man != context->slavelist[slave].eep_man) || + (context->slavelist[i].eep_id != context->slavelist[slave].eep_id ) || + (context->slavelist[i].eep_rev != context->slavelist[slave].eep_rev)) && + (i < slave)) + { + i++; + } + if(i < slave) + { + context->slavelist[slave].CoEdetails = context->slavelist[i].CoEdetails; + context->slavelist[slave].FoEdetails = context->slavelist[i].FoEdetails; + context->slavelist[slave].EoEdetails = context->slavelist[i].EoEdetails; + context->slavelist[slave].SoEdetails = context->slavelist[i].SoEdetails; + if(context->slavelist[i].blockLRW > 0) + { + context->slavelist[slave].blockLRW = 1; + context->slavelist[0].blockLRW++; + } + context->slavelist[slave].Ebuscurrent = context->slavelist[i].Ebuscurrent; + context->slavelist[0].Ebuscurrent += context->slavelist[slave].Ebuscurrent; + memcpy(context->slavelist[slave].name, context->slavelist[i].name, EC_MAXNAME + 1); + for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ) + { + context->slavelist[slave].SM[nSM].StartAddr = context->slavelist[i].SM[nSM].StartAddr; + context->slavelist[slave].SM[nSM].SMlength = context->slavelist[i].SM[nSM].SMlength; + context->slavelist[slave].SM[nSM].SMflags = context->slavelist[i].SM[nSM].SMflags; + } + context->slavelist[slave].FMMU0func = context->slavelist[i].FMMU0func; + context->slavelist[slave].FMMU1func = context->slavelist[i].FMMU1func; + context->slavelist[slave].FMMU2func = context->slavelist[i].FMMU2func; + context->slavelist[slave].FMMU3func = context->slavelist[i].FMMU3func; + EC_PRINT("Copy SII slave %d from %d.\n", slave, i); + return 1; + } + } + return 0; +} + +/** Enumerate and init all slaves. + * + * @param[in] context = context struct + * @param[in] usetable = TRUE when using configtable to init slaves, FALSE otherwise + * @return Workcounter of slave discover datagram = number of slaves found + */ +int ecx_config_init(ecx_contextt *context, uint8 usetable) +{ + uint16 slave, ADPh, configadr, ssigen; + uint16 topology, estat; + int16 topoc, slavec, aliasadr; + uint8 b,h; + uint8 SMc; + uint32 eedat; + int wkc, cindex, nSM; + + EC_PRINT("ec_config_init %d\n",usetable); + ecx_init_context(context); + wkc = ecx_detect_slaves(context); + if (wkc > 0) + { + ecx_set_slaves_to_default(context); + for (slave = 1; slave <= *(context->slavecount); slave++) + { + ADPh = (uint16)(1 - slave); + context->slavelist[slave].Itype = + etohs(ecx_APRDw(context->port, ADPh, ECT_REG_PDICTL, EC_TIMEOUTRET3)); /* read interface type of slave */ + /* a node offset is used to improve readibility of network frames */ + /* this has no impact on the number of addressable slaves (auto wrap around) */ + ecx_APWRw(context->port, ADPh, ECT_REG_STADR, htoes(slave + EC_NODEOFFSET) , EC_TIMEOUTRET3); /* set node address of slave */ + if (slave == 1) + { + b = 1; /* kill non ecat frames for first slave */ + } + else + { + b = 0; /* pass all frames for following slaves */ + } + ecx_APWRw(context->port, ADPh, ECT_REG_DLCTL, htoes(b), EC_TIMEOUTRET3); /* set non ecat frame behaviour */ + configadr = etohs(ecx_APRDw(context->port, ADPh, ECT_REG_STADR, EC_TIMEOUTRET3)); + context->slavelist[slave].configadr = configadr; + ecx_FPRD(context->port, configadr, ECT_REG_ALIAS, sizeof(aliasadr), &aliasadr, EC_TIMEOUTRET3); + context->slavelist[slave].aliasadr = etohs(aliasadr); + ecx_FPRD(context->port, configadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET3); + estat = etohs(estat); + if (estat & EC_ESTAT_R64) /* check if slave can read 8 byte chunks */ + { + context->slavelist[slave].eep_8byte = 1; + } + ecx_readeeprom1(context, slave, ECT_SII_MANUF); /* Manuf */ + } + for (slave = 1; slave <= *(context->slavecount); slave++) + { + context->slavelist[slave].eep_man = + etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* Manuf */ + ecx_readeeprom1(context, slave, ECT_SII_ID); /* ID */ + } + for (slave = 1; slave <= *(context->slavecount); slave++) + { + context->slavelist[slave].eep_id = + etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* ID */ + ecx_readeeprom1(context, slave, ECT_SII_REV); /* revision */ + } + for (slave = 1; slave <= *(context->slavecount); slave++) + { + context->slavelist[slave].eep_rev = + etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* revision */ + ecx_readeeprom1(context, slave, ECT_SII_RXMBXADR); /* write mailbox address + mailboxsize */ + } + for (slave = 1; slave <= *(context->slavecount); slave++) + { + eedat = etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* write mailbox address and mailboxsize */ + context->slavelist[slave].mbx_wo = (uint16)LO_WORD(eedat); + context->slavelist[slave].mbx_l = (uint16)HI_WORD(eedat); + if (context->slavelist[slave].mbx_l > 0) + { + ecx_readeeprom1(context, slave, ECT_SII_TXMBXADR); /* read mailbox offset */ + } + } + for (slave = 1; slave <= *(context->slavecount); slave++) + { + if (context->slavelist[slave].mbx_l > 0) + { + eedat = etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* read mailbox offset */ + context->slavelist[slave].mbx_ro = (uint16)LO_WORD(eedat); /* read mailbox offset */ + context->slavelist[slave].mbx_rl = (uint16)HI_WORD(eedat); /*read mailbox length */ + if (context->slavelist[slave].mbx_rl == 0) + { + context->slavelist[slave].mbx_rl = context->slavelist[slave].mbx_l; + } + ecx_readeeprom1(context, slave, ECT_SII_MBXPROTO); + } + configadr = context->slavelist[slave].configadr; + if ((etohs(ecx_FPRDw(context->port, configadr, ECT_REG_ESCSUP, EC_TIMEOUTRET3)) & 0x04) > 0) /* Support DC? */ + { + context->slavelist[slave].hasdc = TRUE; + } + else + { + context->slavelist[slave].hasdc = FALSE; + } + topology = etohs(ecx_FPRDw(context->port, configadr, ECT_REG_DLSTAT, EC_TIMEOUTRET3)); /* extract topology from DL status */ + h = 0; + b = 0; + if ((topology & 0x0300) == 0x0200) /* port0 open and communication established */ + { + h++; + b |= 0x01; + } + if ((topology & 0x0c00) == 0x0800) /* port1 open and communication established */ + { + h++; + b |= 0x02; + } + if ((topology & 0x3000) == 0x2000) /* port2 open and communication established */ + { + h++; + b |= 0x04; + } + if ((topology & 0xc000) == 0x8000) /* port3 open and communication established */ + { + h++; + b |= 0x08; + } + /* ptype = Physical type*/ + context->slavelist[slave].ptype = + LO_BYTE(etohs(ecx_FPRDw(context->port, configadr, ECT_REG_PORTDES, EC_TIMEOUTRET3))); + context->slavelist[slave].topology = h; + context->slavelist[slave].activeports = b; + /* 0=no links, not possible */ + /* 1=1 link , end of line */ + /* 2=2 links , one before and one after */ + /* 3=3 links , split point */ + /* 4=4 links , cross point */ + /* search for parent */ + context->slavelist[slave].parent = 0; /* parent is master */ + if (slave > 1) + { + topoc = 0; + slavec = slave - 1; + do + { + topology = context->slavelist[slavec].topology; + if (topology == 1) + { + topoc--; /* endpoint found */ + } + if (topology == 3) + { + topoc++; /* split found */ + } + if (topology == 4) + { + topoc += 2; /* cross found */ + } + if (((topoc >= 0) && (topology > 1)) || + (slavec == 1)) /* parent found */ + { + context->slavelist[slave].parent = slavec; + slavec = 1; + } + slavec--; + } + while (slavec > 0); + } + (void)ecx_statecheck(context, slave, EC_STATE_INIT, EC_TIMEOUTSTATE); //* check state change Init */ + + /* set default mailbox configuration if slave has mailbox */ + if (context->slavelist[slave].mbx_l>0) + { + context->slavelist[slave].SMtype[0] = 1; + context->slavelist[slave].SMtype[1] = 2; + context->slavelist[slave].SMtype[2] = 3; + context->slavelist[slave].SMtype[3] = 4; + context->slavelist[slave].SM[0].StartAddr = htoes(context->slavelist[slave].mbx_wo); + context->slavelist[slave].SM[0].SMlength = htoes(context->slavelist[slave].mbx_l); + context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0); + context->slavelist[slave].SM[1].StartAddr = htoes(context->slavelist[slave].mbx_ro); + context->slavelist[slave].SM[1].SMlength = htoes(context->slavelist[slave].mbx_rl); + context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1); + context->slavelist[slave].mbx_proto = + ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); + } + cindex = 0; + /* use configuration table ? */ + if (usetable == 1) + { + cindex = ecx_config_from_table(context, slave); + } + /* slave not in configuration table, find out via SII */ + if (!cindex && !ecx_lookup_prev_sii(context, slave)) + { + ssigen = ecx_siifind(context, slave, ECT_SII_GENERAL); + /* SII general section */ + if (ssigen) + { + context->slavelist[slave].CoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x07); + context->slavelist[slave].FoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x08); + context->slavelist[slave].EoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x09); + context->slavelist[slave].SoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x0a); + if((ecx_siigetbyte(context, slave, ssigen + 0x0d) & 0x02) > 0) + { + context->slavelist[slave].blockLRW = 1; + context->slavelist[0].blockLRW++; + } + context->slavelist[slave].Ebuscurrent = ecx_siigetbyte(context, slave, ssigen + 0x0e); + context->slavelist[slave].Ebuscurrent += ecx_siigetbyte(context, slave, ssigen + 0x0f) << 8; + context->slavelist[0].Ebuscurrent += context->slavelist[slave].Ebuscurrent; + } + /* SII strings section */ + if (ecx_siifind(context, slave, ECT_SII_STRING) > 0) + { + ecx_siistring(context, context->slavelist[slave].name, slave, 1); + } + /* no name for slave found, use constructed name */ + else + { + sprintf(context->slavelist[slave].name, "? M:%8.8x I:%8.8x", + (unsigned int)context->slavelist[slave].eep_man, + (unsigned int)context->slavelist[slave].eep_id); + } + /* SII SM section */ + nSM = ecx_siiSM(context, slave, context->eepSM); + if (nSM>0) + { + context->slavelist[slave].SM[0].StartAddr = htoes(context->eepSM->PhStart); + context->slavelist[slave].SM[0].SMlength = htoes(context->eepSM->Plength); + context->slavelist[slave].SM[0].SMflags = + htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16)); + SMc = 1; + while ((SMc < EC_MAXSM) && ecx_siiSMnext(context, slave, context->eepSM, SMc)) + { + context->slavelist[slave].SM[SMc].StartAddr = htoes(context->eepSM->PhStart); + context->slavelist[slave].SM[SMc].SMlength = htoes(context->eepSM->Plength); + context->slavelist[slave].SM[SMc].SMflags = + htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16)); + SMc++; + } + } + /* SII FMMU section */ + if (ecx_siiFMMU(context, slave, context->eepFMMU)) + { + if (context->eepFMMU->FMMU0 !=0xff) + { + context->slavelist[slave].FMMU0func = context->eepFMMU->FMMU0; + } + if (context->eepFMMU->FMMU1 !=0xff) + { + context->slavelist[slave].FMMU1func = context->eepFMMU->FMMU1; + } + if (context->eepFMMU->FMMU2 !=0xff) + { + context->slavelist[slave].FMMU2func = context->eepFMMU->FMMU2; + } + if (context->eepFMMU->FMMU3 !=0xff) + { + context->slavelist[slave].FMMU3func = context->eepFMMU->FMMU3; + } + } + } + + if (context->slavelist[slave].mbx_l > 0) + { + if (context->slavelist[slave].SM[0].StartAddr == 0x0000) /* should never happen */ + { + EC_PRINT("Slave %d has no proper mailbox in configuration, try default.\n", slave); + context->slavelist[slave].SM[0].StartAddr = htoes(0x1000); + context->slavelist[slave].SM[0].SMlength = htoes(0x0080); + context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0); + context->slavelist[slave].SMtype[0] = 1; + } + if (context->slavelist[slave].SM[1].StartAddr == 0x0000) /* should never happen */ + { + EC_PRINT("Slave %d has no proper mailbox out configuration, try default.\n", slave); + context->slavelist[slave].SM[1].StartAddr = htoes(0x1080); + context->slavelist[slave].SM[1].SMlength = htoes(0x0080); + context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1); + context->slavelist[slave].SMtype[1] = 2; + } + /* program SM0 mailbox in and SM1 mailbox out for slave */ + /* writing both SM in one datagram will solve timing issue in old NETX */ + ecx_FPWR(context->port, configadr, ECT_REG_SM0, sizeof(ec_smt) * 2, + &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3); + } + /* some slaves need eeprom available to PDI in init->preop transition */ + ecx_eeprom2pdi(context, slave); + /* request pre_op for slave */ + ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP | EC_STATE_ACK) , EC_TIMEOUTRET3); /* set preop status */ + } + } + return wkc; +} + +/* If slave has SII mapping and same slave ID done before, use previous mapping. + * This is safe because SII mapping is constant for same slave ID. + */ +static int ecx_lookup_mapping(ecx_contextt *context, uint16 slave, int *Osize, int *Isize) +{ + int i, nSM; + if ((slave > 1) && (*(context->slavecount) > 0)) + { + i = 1; + while(((context->slavelist[i].eep_man != context->slavelist[slave].eep_man) || + (context->slavelist[i].eep_id != context->slavelist[slave].eep_id ) || + (context->slavelist[i].eep_rev != context->slavelist[slave].eep_rev)) && + (i < slave)) + { + i++; + } + if(i < slave) + { + for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ) + { + context->slavelist[slave].SM[nSM].SMlength = context->slavelist[i].SM[nSM].SMlength; + context->slavelist[slave].SMtype[nSM] = context->slavelist[i].SMtype[nSM]; + } + *Osize = context->slavelist[i].Obits; + *Isize = context->slavelist[i].Ibits; + context->slavelist[slave].Obits = *Osize; + context->slavelist[slave].Ibits = *Isize; + EC_PRINT("Copy mapping slave %d from %d.\n", slave, i); + return 1; + } + } + return 0; +} + +static int ecx_map_coe_soe(ecx_contextt *context, uint16 slave) +{ + int Isize, Osize; + int rval; + + ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */ + + EC_PRINT(" >Slave %d, configadr %x, state %2.2x\n", + slave, context->slavelist[slave].configadr, context->slavelist[slave].state); + + /* execute special slave configuration hook Pre-Op to Safe-OP */ + if(context->slavelist[slave].PO2SOconfig) /* only if registered */ + { + context->slavelist[slave].PO2SOconfig(slave); + } + /* if slave not found in configlist find IO mapping in slave self */ + if (!context->slavelist[slave].configindex) + { + Isize = 0; + Osize = 0; + if (context->slavelist[slave].mbx_proto & ECT_MBXPROT_COE) /* has CoE */ + { + rval = 0; + if (context->slavelist[slave].CoEdetails & ECT_COEDET_SDOCA) /* has Complete Access */ + { + /* read PDO mapping via CoE and use Complete Access */ + rval = ecx_readPDOmapCA(context, slave, &Osize, &Isize); + } + if (!rval) /* CA not available or not succeeded */ + { + /* read PDO mapping via CoE */ + rval = ecx_readPDOmap(context, slave, &Osize, &Isize); + } + EC_PRINT(" CoE Osize:%d Isize:%d\n", Osize, Isize); + } + if ((!Isize && !Osize) && (context->slavelist[slave].mbx_proto & ECT_MBXPROT_SOE)) /* has SoE */ + { + /* read AT / MDT mapping via SoE */ + rval = ecx_readIDNmap(context, slave, &Osize, &Isize); + context->slavelist[slave].SM[2].SMlength = htoes((Osize + 7) / 8); + context->slavelist[slave].SM[3].SMlength = htoes((Isize + 7) / 8); + EC_PRINT(" SoE Osize:%d Isize:%d\n", Osize, Isize); + } + context->slavelist[slave].Obits = Osize; + context->slavelist[slave].Ibits = Isize; + } + + return 1; +} + +static int ecx_map_sii(ecx_contextt *context, uint16 slave) +{ + int Isize, Osize; + int nSM; + ec_eepromPDOt eepPDO; + + Osize = context->slavelist[slave].Obits; + Isize = context->slavelist[slave].Ibits; + + if (!Isize && !Osize) /* find PDO in previous slave with same ID */ + { + (void)ecx_lookup_mapping(context, slave, &Osize, &Isize); + } + if (!Isize && !Osize) /* find PDO mapping by SII */ + { + memset(&eepPDO, 0, sizeof(eepPDO)); + Isize = (int)ecx_siiPDO(context, slave, &eepPDO, 0); + EC_PRINT(" SII Isize:%d\n", Isize); + for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ) + { + if (eepPDO.SMbitsize[nSM] > 0) + { + context->slavelist[slave].SM[nSM].SMlength = htoes((eepPDO.SMbitsize[nSM] + 7) / 8); + context->slavelist[slave].SMtype[nSM] = 4; + EC_PRINT(" SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]); + } + } + Osize = (int)ecx_siiPDO(context, slave, &eepPDO, 1); + EC_PRINT(" SII Osize:%d\n", Osize); + for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ) + { + if (eepPDO.SMbitsize[nSM] > 0) + { + context->slavelist[slave].SM[nSM].SMlength = htoes((eepPDO.SMbitsize[nSM] + 7) / 8); + context->slavelist[slave].SMtype[nSM] = 3; + EC_PRINT(" SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]); + } + } + } + context->slavelist[slave].Obits = Osize; + context->slavelist[slave].Ibits = Isize; + EC_PRINT(" ISIZE:%d %d OSIZE:%d\n", + context->slavelist[slave].Ibits, Isize,context->slavelist[slave].Obits); + + return 1; +} + +static int ecx_map_sm(ecx_contextt *context, uint16 slave) +{ + uint16 configadr; + int nSM; + + configadr = context->slavelist[slave].configadr; + + EC_PRINT(" SM programming\n"); + if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[0].StartAddr) + { + ecx_FPWR(context->port, configadr, ECT_REG_SM0, + sizeof(ec_smt), &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3); + EC_PRINT(" SM0 Type:%d StartAddr:%4.4x Flags:%8.8x\n", + context->slavelist[slave].SMtype[0], + context->slavelist[slave].SM[0].StartAddr, + context->slavelist[slave].SM[0].SMflags); + } + if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[1].StartAddr) + { + ecx_FPWR(context->port, configadr, ECT_REG_SM1, + sizeof(ec_smt), &context->slavelist[slave].SM[1], EC_TIMEOUTRET3); + EC_PRINT(" SM1 Type:%d StartAddr:%4.4x Flags:%8.8x\n", + context->slavelist[slave].SMtype[1], + context->slavelist[slave].SM[1].StartAddr, + context->slavelist[slave].SM[1].SMflags); + } + /* program SM2 to SMx */ + for( nSM = 2 ; nSM < EC_MAXSM ; nSM++ ) + { + if (context->slavelist[slave].SM[nSM].StartAddr) + { + /* check if SM length is zero -> clear enable flag */ + if( context->slavelist[slave].SM[nSM].SMlength == 0) + { + context->slavelist[slave].SM[nSM].SMflags = + htoel( etohl(context->slavelist[slave].SM[nSM].SMflags) & EC_SMENABLEMASK); + } + ecx_FPWR(context->port, configadr, ECT_REG_SM0 + (nSM * sizeof(ec_smt)), + sizeof(ec_smt), &context->slavelist[slave].SM[nSM], EC_TIMEOUTRET3); + EC_PRINT(" SM%d Type:%d StartAddr:%4.4x Flags:%8.8x\n", nSM, + context->slavelist[slave].SMtype[nSM], + context->slavelist[slave].SM[nSM].StartAddr, + context->slavelist[slave].SM[nSM].SMflags); + } + } + if (context->slavelist[slave].Ibits > 7) + { + context->slavelist[slave].Ibytes = (context->slavelist[slave].Ibits + 7) / 8; + } + if (context->slavelist[slave].Obits > 7) + { + context->slavelist[slave].Obytes = (context->slavelist[slave].Obits + 7) / 8; + } + + return 1; +} + +OSAL_THREAD_FUNC ecx_mapper_thread(void *param) +{ + ecx_mapt_t *maptp; + maptp = param; + ecx_map_coe_soe(maptp->context, maptp->slave); + maptp->running = 0; +} + +static int ecx_find_mapt(void) +{ + int p; + p = 0; + while((p < MAX_MAPT) && ecx_mapt[p].running) + { + p++; + } + if(p < MAX_MAPT) + { + return p; + } + else + { + return -1; + } +} + +static int ecx_get_threadcount(void) +{ + int thrc, thrn; + thrc = 0; + for(thrn = 0 ; thrn < MAX_MAPT ; thrn++) + { + thrc += ecx_mapt[thrn].running; + } + return thrc; +} + +/** Map all PDOs in one group of slaves to IOmap. + * + * @param[in] context = context struct + * @param[out] pIOmap = pointer to IOmap + * @param[in] group = group to map, 0 = all groups + * @return IOmap size + */ +int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group) +{ + uint16 slave, configadr; + int BitCount, ByteCount, FMMUsize, FMMUdone; + uint16 SMlength, EndAddr; + uint8 BitPos; + uint8 SMc, FMMUc; + uint32 LogAddr = 0; + uint32 oLogAddr = 0; + uint32 diff; + uint16 currentsegment = 0; + uint32 segmentsize = 0; + int thrn, thrc; + + if ((*(context->slavecount) > 0) && (group < context->maxgroup)) + { + EC_PRINT("ec_config_map_group IOmap:%p group:%d\n", pIOmap, group); + LogAddr = context->grouplist[group].logstartaddr; + oLogAddr = LogAddr; + BitPos = 0; + context->grouplist[group].nsegments = 0; + context->grouplist[group].outputsWKC = 0; + context->grouplist[group].inputsWKC = 0; + + for(thrn = 0 ; thrn < MAX_MAPT ; thrn++) + { + ecx_mapt[thrn].running = 0; + } + /* find CoE and SoE mapping of slaves in multiple threads */ + for (slave = 1; slave <= *(context->slavecount); slave++) + { + if (!group || (group == context->slavelist[slave].group)) + { + if(MAX_MAPT <= 1) + { + /* serialised version */ + ecx_map_coe_soe(context, slave); + } + else + { + /* multi-threaded version */ + while((thrn = ecx_find_mapt()) < 0) + { + osal_usleep(1000); + } + ecx_mapt[thrn].context = context; + ecx_mapt[thrn].slave = slave; + ecx_mapt[thrn].running = 1; + osal_thread_create(&(ecx_threadh[thrn]), 128000, + &ecx_mapper_thread, &(ecx_mapt[thrn])); + } + } + } + /* wait for all threads to finish */ + do + { + thrc = ecx_get_threadcount(); + if(thrc) + { + osal_usleep(1000); + } + } while(thrc); + /* find SII mapping of slave and program SM */ + for (slave = 1; slave <= *(context->slavecount); slave++) + { + if (!group || (group == context->slavelist[slave].group)) + { + ecx_map_sii(context, slave); + ecx_map_sm(context, slave); + } + } + + /* do input mapping of slave and program FMMUs */ + for (slave = 1; slave <= *(context->slavecount); slave++) + { + configadr = context->slavelist[slave].configadr; + + if (!group || (group == context->slavelist[slave].group)) + { + FMMUc = context->slavelist[slave].FMMUunused; + SMc = 0; + BitCount = 0; + ByteCount = 0; + EndAddr = 0; + FMMUsize = 0; + FMMUdone = 0; + /* create output mapping */ + if (context->slavelist[slave].Obits) + { + EC_PRINT(" OUTPUT MAPPING\n"); + /* search for SM that contribute to the output mapping */ + while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Obits + 7) / 8))) + { + EC_PRINT(" FMMU %d\n", FMMUc); + while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++; + EC_PRINT(" SM%d\n", SMc); + context->slavelist[slave].FMMU[FMMUc].PhysStart = + context->slavelist[slave].SM[SMc].StartAddr; + SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength); + ByteCount += SMlength; + BitCount += SMlength * 8; + EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength; + while ( (BitCount < context->slavelist[slave].Obits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for output */ + { + SMc++; + while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++; + /* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */ + if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ) + { + break; + } + EC_PRINT(" SM%d\n", SMc); + SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength); + ByteCount += SMlength; + BitCount += SMlength * 8; + EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength; + } + + /* bit oriented slave */ + if (!context->slavelist[slave].Obytes) + { + context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr); + context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos; + BitPos += context->slavelist[slave].Obits - 1; + if (BitPos > 7) + { + LogAddr++; + BitPos -= 8; + } + FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1; + context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize); + context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos; + BitPos ++; + if (BitPos > 7) + { + LogAddr++; + BitPos -= 8; + } + } + /* byte oriented slave */ + else + { + if (BitPos) + { + LogAddr++; + BitPos = 0; + } + context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr); + context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos; + BitPos = 7; + FMMUsize = ByteCount; + if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Obytes) + { + FMMUsize = context->slavelist[slave].Obytes - FMMUdone; + } + LogAddr += FMMUsize; + context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize); + context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos; + BitPos = 0; + } + FMMUdone += FMMUsize; + context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0; + context->slavelist[slave].FMMU[FMMUc].FMMUtype = 2; + context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1; + /* program FMMU for output */ + ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), + sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3); + context->grouplist[group].outputsWKC++; + if (!context->slavelist[slave].outputs) + { + context->slavelist[slave].outputs = + (uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart); + context->slavelist[slave].Ostartbit = + context->slavelist[slave].FMMU[FMMUc].LogStartbit; + EC_PRINT(" slave %d Outputs %p startbit %d\n", + slave, + context->slavelist[slave].outputs, + context->slavelist[slave].Ostartbit); + } + FMMUc++; + } + context->slavelist[slave].FMMUunused = FMMUc; + diff = LogAddr - oLogAddr; + oLogAddr = LogAddr; + if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)) + { + context->grouplist[group].IOsegment[currentsegment] = segmentsize; + if (currentsegment < (EC_MAXIOSEGMENTS - 1)) + { + currentsegment++; + segmentsize = diff; + } + } + else + { + segmentsize += diff; + } + } + } + } + if (BitPos) + { + LogAddr++; + oLogAddr = LogAddr; + BitPos = 0; + if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)) + { + context->grouplist[group].IOsegment[currentsegment] = segmentsize; + if (currentsegment < (EC_MAXIOSEGMENTS - 1)) + { + currentsegment++; + segmentsize = 1; + } + } + else + { + segmentsize += 1; + } + } + context->grouplist[group].outputs = pIOmap; + context->grouplist[group].Obytes = LogAddr; + context->grouplist[group].nsegments = currentsegment + 1; + context->grouplist[group].Isegment = currentsegment; + context->grouplist[group].Ioffset = segmentsize; + if (!group) + { + context->slavelist[0].outputs = pIOmap; + context->slavelist[0].Obytes = LogAddr; /* store output bytes in master record */ + } + + /* do input mapping of slave and program FMMUs */ + for (slave = 1; slave <= *(context->slavecount); slave++) + { + configadr = context->slavelist[slave].configadr; + if (!group || (group == context->slavelist[slave].group)) + { + FMMUc = context->slavelist[slave].FMMUunused; + if (context->slavelist[slave].Obits) /* find free FMMU */ + { + while ( context->slavelist[slave].FMMU[FMMUc].LogStart ) FMMUc++; + } + SMc = 0; + BitCount = 0; + ByteCount = 0; + EndAddr = 0; + FMMUsize = 0; + FMMUdone = 0; + /* create input mapping */ + if (context->slavelist[slave].Ibits) + { + EC_PRINT(" =Slave %d, INPUT MAPPING\n", slave); + /* search for SM that contribute to the input mapping */ + while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Ibits + 7) / 8))) + { + EC_PRINT(" FMMU %d\n", FMMUc); + while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++; + EC_PRINT(" SM%d\n", SMc); + context->slavelist[slave].FMMU[FMMUc].PhysStart = + context->slavelist[slave].SM[SMc].StartAddr; + SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength); + ByteCount += SMlength; + BitCount += SMlength * 8; + EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength; + while ( (BitCount < context->slavelist[slave].Ibits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for input */ + { + SMc++; + while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++; + /* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */ + if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ) + { + break; + } + EC_PRINT(" SM%d\n", SMc); + SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength); + ByteCount += SMlength; + BitCount += SMlength * 8; + EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength; + } + + /* bit oriented slave */ + if (!context->slavelist[slave].Ibytes) + { + context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr); + context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos; + BitPos += context->slavelist[slave].Ibits - 1; + if (BitPos > 7) + { + LogAddr++; + BitPos -= 8; + } + FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1; + context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize); + context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos; + BitPos ++; + if (BitPos > 7) + { + LogAddr++; + BitPos -= 8; + } + } + /* byte oriented slave */ + else + { + if (BitPos) + { + LogAddr++; + BitPos = 0; + } + context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr); + context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos; + BitPos = 7; + FMMUsize = ByteCount; + if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Ibytes) + { + FMMUsize = context->slavelist[slave].Ibytes - FMMUdone; + } + LogAddr += FMMUsize; + context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize); + context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos; + BitPos = 0; + } + FMMUdone += FMMUsize; + if (context->slavelist[slave].FMMU[FMMUc].LogLength) + { + context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0; + context->slavelist[slave].FMMU[FMMUc].FMMUtype = 1; + context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1; + /* program FMMU for input */ + ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), + sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3); + /* add one for an input FMMU */ + context->grouplist[group].inputsWKC++; + } + if (!context->slavelist[slave].inputs) + { + context->slavelist[slave].inputs = + (uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart); + context->slavelist[slave].Istartbit = + context->slavelist[slave].FMMU[FMMUc].LogStartbit; + EC_PRINT(" Inputs %p startbit %d\n", + context->slavelist[slave].inputs, + context->slavelist[slave].Istartbit); + } + FMMUc++; + } + context->slavelist[slave].FMMUunused = FMMUc; + diff = LogAddr - oLogAddr; + oLogAddr = LogAddr; + if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)) + { + context->grouplist[group].IOsegment[currentsegment] = segmentsize; + if (currentsegment < (EC_MAXIOSEGMENTS - 1)) + { + currentsegment++; + segmentsize = diff; + } + } + else + { + segmentsize += diff; + } + } + + ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */ + ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET3); /* set safeop status */ + + if (context->slavelist[slave].blockLRW) + { + context->grouplist[group].blockLRW++; + } + context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent; + } + } + if (BitPos) + { + LogAddr++; + oLogAddr = LogAddr; + BitPos = 0; + if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)) + { + context->grouplist[group].IOsegment[currentsegment] = segmentsize; + if (currentsegment < (EC_MAXIOSEGMENTS - 1)) + { + currentsegment++; + segmentsize = 1; + } + } + else + { + segmentsize += 1; + } + } + context->grouplist[group].IOsegment[currentsegment] = segmentsize; + context->grouplist[group].nsegments = currentsegment + 1; + context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes; + context->grouplist[group].Ibytes = LogAddr - context->grouplist[group].Obytes; + if (!group) + { + context->slavelist[0].inputs = (uint8 *)(pIOmap) + context->slavelist[0].Obytes; + context->slavelist[0].Ibytes = LogAddr - context->slavelist[0].Obytes; /* store input bytes in master record */ + } + + EC_PRINT("IOmapSize %d\n", LogAddr - context->grouplist[group].logstartaddr); + + return (LogAddr - context->grouplist[group].logstartaddr); + } + + return 0; +} + +/** Recover slave. + * + * @param[in] context = context struct + * @param[in] slave = slave to recover + * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3 + * @return >0 if successful + */ +int ecx_recover_slave(ecx_contextt *context, uint16 slave, int timeout) +{ + int rval; + uint16 ADPh, configadr, readadr, wkc; + + rval = 0; + configadr = context->slavelist[slave].configadr; + ADPh = (uint16)(1 - slave); + /* check if we found another slave than the requested */ + readadr = 0xfffe; + wkc = ecx_APRD(context->port, ADPh, ECT_REG_STADR, sizeof(readadr), &readadr, timeout); + /* correct slave found, finished */ + if(readadr == configadr) + { + return 1; + } + /* only try if no config address*/ + if( (wkc > 0) && (readadr == 0)) + { + /* clear possible slaves at EC_TEMPNODE */ + ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , 0); + /* set temporary node address of slave */ + if(ecx_APWRw(context->port, ADPh, ECT_REG_STADR, htoes(EC_TEMPNODE) , timeout) <= 0) + { + ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , 0); + return 0; /* slave fails to respond */ + } + + context->slavelist[slave].configadr = EC_TEMPNODE; /* temporary config address */ + ecx_eeprom2master(context, slave); /* set Eeprom control to master */ + + /* check if slave is the same as configured before */ + if ((ecx_FPRDw(context->port, EC_TEMPNODE, ECT_REG_ALIAS, timeout) == + context->slavelist[slave].aliasadr) && + (ecx_readeeprom(context, slave, ECT_SII_ID, EC_TIMEOUTEEP) == + context->slavelist[slave].eep_id) && + (ecx_readeeprom(context, slave, ECT_SII_MANUF, EC_TIMEOUTEEP) == + context->slavelist[slave].eep_man) && + (ecx_readeeprom(context, slave, ECT_SII_REV, EC_TIMEOUTEEP) == + context->slavelist[slave].eep_rev)) + { + rval = ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(configadr) , timeout); + context->slavelist[slave].configadr = configadr; + } + else + { + /* slave is not the expected one, remove config address*/ + ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , timeout); + context->slavelist[slave].configadr = configadr; + } + } + + return rval; +} + +/** Reconfigure slave. + * + * @param[in] context = context struct + * @param[in] slave = slave to reconfigure + * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3 + * @return Slave state + */ +int ecx_reconfig_slave(ecx_contextt *context, uint16 slave, int timeout) +{ + int state, nSM, FMMUc; + uint16 configadr; + + configadr = context->slavelist[slave].configadr; + if (ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_INIT) , timeout) <= 0) + { + return 0; + } + state = 0; + ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */ + /* check state change init */ + state = ecx_statecheck(context, slave, EC_STATE_INIT, EC_TIMEOUTSTATE); + if(state == EC_STATE_INIT) + { + /* program all enabled SM */ + for( nSM = 0 ; nSM < EC_MAXSM ; nSM++ ) + { + if (context->slavelist[slave].SM[nSM].StartAddr) + { + ecx_FPWR(context->port, configadr, ECT_REG_SM0 + (nSM * sizeof(ec_smt)), + sizeof(ec_smt), &context->slavelist[slave].SM[nSM], timeout); + } + } + ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP) , timeout); + state = ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */ + if( state == EC_STATE_PRE_OP) + { + /* execute special slave configuration hook Pre-Op to Safe-OP */ + if(context->slavelist[slave].PO2SOconfig) /* only if registered */ + { + context->slavelist[slave].PO2SOconfig(slave); + } + ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , timeout); /* set safeop status */ + state = ecx_statecheck(context, slave, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); /* check state change safe-op */ + /* program configured FMMU */ + for( FMMUc = 0 ; FMMUc < context->slavelist[slave].FMMUunused ; FMMUc++ ) + { + ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), + sizeof(ec_fmmut), &context->slavelist[slave].FMMU[FMMUc], timeout); + } + } + } + + return state; +} + +#ifdef EC_VER1 +int ec_config_init(uint8 usetable) +{ + return ecx_config_init(&ecx_context, usetable); +} + +int ec_config_map_group(void *pIOmap, uint8 group) +{ + return ecx_config_map_group(&ecx_context, pIOmap, group); +} + +/** Map all PDOs from slaves to IOmap. + * + * @param[out] pIOmap = pointer to IOmap + * @return IOmap size + */ +int ec_config_map(void *pIOmap) +{ + return ec_config_map_group(pIOmap, 0); +} + +/** Enumerate / map and init all slaves. + * + * @param[in] usetable = TRUE when using configtable to init slaves, FALSE otherwise + * @param[out] pIOmap = pointer to IOmap + * @return Workcounter of slave discover datagram = number of slaves found + */ +int ec_config(uint8 usetable, void *pIOmap) +{ + int wkc; + wkc = ec_config_init(usetable); + if (wkc) + { + ec_config_map(pIOmap); + } + return wkc; +} + +int ec_recover_slave(uint16 slave, int timeout) +{ + return ecx_recover_slave(&ecx_context, slave, timeout); +} + +int ec_reconfig_slave(uint16 slave, int timeout) +{ + return ecx_reconfig_slave(&ecx_context, slave, timeout); +} +#endif diff --git a/soem/ethercatconfig.h b/soem/ethercatconfig.h new file mode 100644 index 0000000..7258967 --- /dev/null +++ b/soem/ethercatconfig.h @@ -0,0 +1,75 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatconfig.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatconfig.c + */ + +#ifndef _ethercatconfig_ +#define _ethercatconfig_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define EC_NODEOFFSET 0x1000 +#define EC_TEMPNODE 0xffff + +#ifdef EC_VER1 +int ec_config_init(uint8 usetable); +int ec_config_map(void *pIOmap); +int ec_config_map_group(void *pIOmap, uint8 group); +int ec_config(uint8 usetable, void *pIOmap); +int ec_recover_slave(uint16 slave, int timeout); +int ec_reconfig_slave(uint16 slave, int timeout); +#endif + +int ecx_config_init(ecx_contextt *context, uint8 usetable); +int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group); +int ecx_recover_slave(ecx_contextt *context, uint16 slave, int timeout); +int ecx_reconfig_slave(ecx_contextt *context, uint16 slave, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatconfiglist.h b/soem/ethercatconfiglist.h new file mode 100644 index 0000000..e535395 --- /dev/null +++ b/soem/ethercatconfiglist.h @@ -0,0 +1,92 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatconfiglist.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * DEPRICATED Configuration list of known EtherCAT slave devices. + * + * If a slave is found in this list it is configured according to the parameters + * in the list. Otherwise the configuration info is read directly from the slave + * EEPROM (SII or Slave Information Interface). + */ + +#ifndef _ethercatconfiglist_ +#define _ethercatconfiglist_ + +/* + explanation of dev: + 1: static device with no IO mapping ie EK1100 + 2: input device no mailbox ie simple IO device + 3: output device no mailbox + 4: input device with mailbox configuration + 5: output device with mailbox configuration + 6: input/output device no mailbox + 7: input.output device with mailbox configuration +*/ +#define EC_CONFIGEND 0xffffffff + +ec_configlist_t ec_configlist[] = { + {/*Man=*/0x00000000,/*ID=*/0x00000000,/*Name=*/"" ,/*dtype=*/0,/*Ibits=*/ 0,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x044c2c52,/*Name=*/"EK1100" ,/*dtype=*/1,/*Ibits=*/ 0,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x03ea3052,/*Name=*/"EL1002" ,/*dtype=*/2,/*Ibits=*/ 2,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x03ec3052,/*Name=*/"EL1004" ,/*dtype=*/2,/*Ibits=*/ 4,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x03f43052,/*Name=*/"EL1012" ,/*dtype=*/2,/*Ibits=*/ 2,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x03f63052,/*Name=*/"EL1014" ,/*dtype=*/2,/*Ibits=*/ 4,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x03fa3052,/*Name=*/"EL1018" ,/*dtype=*/2,/*Ibits=*/ 8,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x07d23052,/*Name=*/"EL2002" ,/*dtype=*/3,/*Ibits=*/ 0,/*Obits=*/ 2,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x07d43052,/*Name=*/"EL2004" ,/*dtype=*/3,/*Ibits=*/ 0,/*Obits=*/ 4,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x07d83052,/*Name=*/"EL2008" ,/*dtype=*/3,/*Ibits=*/ 0,/*Obits=*/ 8,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x07f03052,/*Name=*/"EL2032" ,/*dtype=*/6,/*Ibits=*/ 2,/*Obits=*/ 2,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x0c1e3052,/*Name=*/"EL3102" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0c283052,/*Name=*/"EL3112" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0c323052,/*Name=*/"EL3122" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0c463052,/*Name=*/"EL3142" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0c503052,/*Name=*/"EL3152" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0c5a3052,/*Name=*/"EL3162" ,/*dtype=*/4,/*Ibits=*/48,/*Obits=*/ 0,/*SM2a*/0x1000,/*SM2f*/0x00000024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/0,/*FM1ac*/1}, + {/*Man=*/0x00000002,/*ID=*/0x0fc03052,/*Name=*/"EL4032" ,/*dtype=*/5,/*Ibits=*/ 0,/*Obits=*/32,/*SM2a*/0x1100,/*SM2f*/0x00010024,/*SM3a*/0x1180,/*SM3f*/0x00000022,/*FM0ac*/1,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x10063052,/*Name=*/"EL4102" ,/*dtype=*/5,/*Ibits=*/ 0,/*Obits=*/32,/*SM2a*/0x1000,/*SM2f*/0x00010024,/*SM3a*/0x1100,/*SM3f*/0x00000022,/*FM0ac*/1,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x10103052,/*Name=*/"EL4112" ,/*dtype=*/5,/*Ibits=*/ 0,/*Obits=*/32,/*SM2a*/0x1000,/*SM2f*/0x00010024,/*SM3a*/0x1100,/*SM3f*/0x00000022,/*FM0ac*/1,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x101a3052,/*Name=*/"EL4122" ,/*dtype=*/5,/*Ibits=*/ 0,/*Obits=*/32,/*SM2a*/0x1000,/*SM2f*/0x00010024,/*SM3a*/0x1100,/*SM3f*/0x00000022,/*FM0ac*/1,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x10243052,/*Name=*/"EL4132" ,/*dtype=*/5,/*Ibits=*/ 0,/*Obits=*/32,/*SM2a*/0x1000,/*SM2f*/0x00010024,/*SM3a*/0x1100,/*SM3f*/0x00000022,/*FM0ac*/1,/*FM1ac*/0}, + {/*Man=*/0x00000002,/*ID=*/0x13ed3052,/*Name=*/"EL5101" ,/*dtype=*/7,/*Ibits=*/40,/*Obits=*/24,/*SM2a*/0x1000,/*SM2f*/0x00010024,/*SM3a*/0x1100,/*SM3f*/0x00010020,/*FM0ac*/1,/*FM1ac*/1}, + {/*Man=*/EC_CONFIGEND,/*ID=*/0x00000000,/*Name=*/"" ,/*dtype=*/0,/*Ibits=*/ 0,/*Obits=*/ 0,/*SM2a*/ 0,/*SM2f*/ 0,/*SM3a*/ 0,/*SM3f*/ 0,/*FM0ac*/0,/*FM1ac*/0} +}; + +#endif diff --git a/soem/ethercatdc.c b/soem/ethercatdc.c new file mode 100644 index 0000000..2fb0e10 --- /dev/null +++ b/soem/ethercatdc.c @@ -0,0 +1,471 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatdc.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Distributed Clock EtherCAT functions. + * + */ +#include "oshw.h" +#include "osal.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatdc.h" + +#define PORTM0 0x01 +#define PORTM1 0x02 +#define PORTM2 0x04 +#define PORTM3 0x08 + +/** 1st sync pulse delay in ns here 100ms */ +#define SyncDelay ((int32)100000000) + +/** + * Set DC of slave to fire sync0 at CyclTime interval with CyclShift offset. + * + * @param[in] context = context struct + * @param [in] slave Slave number. + * @param [in] act TRUE = active, FALSE = deactivated + * @param [in] CyclTime Cycltime in ns. + * @param [in] CyclShift CyclShift in ns. + */ +void ecx_dcsync0(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift) +{ + uint8 h, RA; + uint16 slaveh; + int64 t, t1; + int32 tc; + + slaveh = context->slavelist[slave].configadr; + RA = 0; + + /* stop cyclic operation, ready for next trigger */ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); + if (act) + { + RA = 1 + 2; /* act cyclic operation and sync0, sync1 deactivated */ + } + h = 0; + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCUC, sizeof(h), &h, EC_TIMEOUTRET); /* write access to ethercat */ + t1 = 0; + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSYSTIME, sizeof(t1), &t1, EC_TIMEOUTRET); /* read local time of slave */ + t1 = etohll(t1); + + /* Calculate first trigger time, always a whole multiple of CyclTime rounded up + plus the shifttime (can be negative) + This insures best sychronisation between slaves, slaves with the same CyclTime + will sync at the same moment (you can use CyclShift to shift the sync) */ + if (CyclTime > 0) + { + t = ((t1 + SyncDelay) / CyclTime) * CyclTime + CyclTime + CyclShift; + } + else + { + t = t1 + SyncDelay + CyclShift; + /* first trigger at T1 + CyclTime + SyncDelay + CyclShift in ns */ + } + t = htoell(t); + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSTART0, sizeof(t), &t, EC_TIMEOUTRET); /* SYNC0 start time */ + tc = htoel(CyclTime); + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE0, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC0 cycle time */ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); /* activate cyclic operation */ +} + +/** + * Set DC of slave to fire sync0 and sync1 at CyclTime interval with CyclShift offset. + * + * @param[in] context = context struct + * @param [in] slave Slave number. + * @param [in] act TRUE = active, FALSE = deactivated + * @param [in] CyclTime0 Cycltime SYNC0 in ns. + * @param [in] CyclTime1 Cycltime SYNC1 in ns. This time is a delta time in relation to + the SYNC0 fire. If CylcTime1 = 0 then SYNC1 fires a the same time + as SYNC0. + * @param [in] CyclShift CyclShift in ns. + */ +void ecx_dcsync01(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift) +{ + uint8 h, RA; + uint16 slaveh; + int64 t, t1; + int32 tc; + uint32 TrueCyclTime; + + /* Sync1 can be used as a multiple of Sync0, use true cycle time */ + TrueCyclTime = ((CyclTime1 / CyclTime0) + 1) * CyclTime0; + + slaveh = context->slavelist[slave].configadr; + RA = 0; + + /* stop cyclic operation, ready for next trigger */ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); + if (act) + { + RA = 1 + 2 + 4; /* act cyclic operation and sync0 + sync1 */ + } + h = 0; + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCUC, sizeof(h), &h, EC_TIMEOUTRET); /* write access to ethercat */ + t1 = 0; + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSYSTIME, sizeof(t1), &t1, EC_TIMEOUTRET); /* read local time of slave */ + t1 = etohll(t1); + + /* Calculate first trigger time, always a whole multiple of TrueCyclTime rounded up + plus the shifttime (can be negative) + This insures best sychronisation between slaves, slaves with the same CyclTime + will sync at the same moment (you can use CyclShift to shift the sync) */ + if (CyclTime0 > 0) + { + t = ((t1 + SyncDelay) / TrueCyclTime) * TrueCyclTime + TrueCyclTime + CyclShift; + } + else + { + t = t1 + SyncDelay + CyclShift; + /* first trigger at T1 + CyclTime + SyncDelay + CyclShift in ns */ + } + t = htoell(t); + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSTART0, sizeof(t), &t, EC_TIMEOUTRET); /* SYNC0 start time */ + tc = htoel(CyclTime0); + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE0, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC0 cycle time */ + tc = htoel(CyclTime1); + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCCYCLE1, sizeof(tc), &tc, EC_TIMEOUTRET); /* SYNC1 cycle time */ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYNCACT, sizeof(RA), &RA, EC_TIMEOUTRET); /* activate cyclic operation */ +} + +/* latched port time of slave */ +static int32 ecx_porttime(ecx_contextt *context, uint16 slave, uint8 port) +{ + int32 ts; + switch (port) + { + case 0: + ts = context->slavelist[slave].DCrtA; + break; + case 1: + ts = context->slavelist[slave].DCrtB; + break; + case 2: + ts = context->slavelist[slave].DCrtC; + break; + case 3: + ts = context->slavelist[slave].DCrtD; + break; + default: + ts = 0; + break; + } + return ts; +} + +/* calculate previous active port of a slave */ +static uint8 ecx_prevport(ecx_contextt *context, uint16 slave, uint8 port) +{ + uint8 pport = port; + uint8 aport = context->slavelist[slave].activeports; + switch(port) + { + case 0: + if(aport & PORTM2) + pport = 2; + else if (aport & PORTM1) + pport = 1; + else if (aport & PORTM3) + pport = 3; + break; + case 1: + if(aport & PORTM3) + pport = 3; + else if (aport & PORTM0) + pport = 0; + else if (aport & PORTM2) + pport = 2; + break; + case 2: + if(aport & PORTM1) + pport = 1; + else if (aport & PORTM3) + pport = 3; + else if (aport & PORTM0) + pport = 0; + break; + case 3: + if(aport & PORTM0) + pport = 0; + else if (aport & PORTM2) + pport = 2; + else if (aport & PORTM1) + pport = 1; + break; + } + return pport; +} + +/* search unconsumed ports in parent, consume and return first open port */ +static uint8 ecx_parentport(ecx_contextt *context, uint16 parent) +{ + uint8 parentport = 0; + uint8 b; + /* search order is important, here 3 - 1 - 2 - 0 */ + b = context->slavelist[parent].consumedports; + if (b & PORTM3) + { + parentport = 3; + b &= (uint8)~PORTM3; + } + else if (b & PORTM1) + { + parentport = 1; + b &= (uint8)~PORTM1; + } + else if (b & PORTM2) + { + parentport = 2; + b &= (uint8)~PORTM2; + } + else if (b & PORTM0) + { + parentport = 0; + b &= (uint8)~PORTM0; + } + context->slavelist[parent].consumedports = b; + return parentport; +} + +/** + * Locate DC slaves, measure propagation delays. + * + * @param[in] context = context struct + * @return boolean if slaves are found with DC + */ +boolean ecx_configdc(ecx_contextt *context) +{ + uint16 i, slaveh, parent, child; + uint16 parenthold = 0; + uint16 prevDCslave = 0; + int32 ht, dt1, dt2, dt3; + int64 hrt; + uint8 entryport; + int8 nlist; + int8 plist[4]; + int32 tlist[4]; + ec_timet mastertime; + uint64 mastertime64; + + context->slavelist[0].hasdc = FALSE; + context->grouplist[0].hasdc = FALSE; + ht = 0; + mastertime = osal_current_time(); + ecx_BWR(context->port, 0, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET); /* latch DCrecvTimeA of all slaves */ + mastertime64 = (((uint64)mastertime.sec * 1000000) + (uint64)mastertime.usec) * 1000; + for (i = 1; i <= *(context->slavecount); i++) + { + context->slavelist[i].consumedports = context->slavelist[i].activeports; + if (context->slavelist[i].hasdc) + { + if (!context->slavelist[0].hasdc) + { + context->slavelist[0].hasdc = TRUE; + context->slavelist[0].DCnext = i; + context->slavelist[i].DCprevious = 0; + context->grouplist[0].hasdc = TRUE; + context->grouplist[0].DCnext = i; + } + else + { + context->slavelist[prevDCslave].DCnext = i; + context->slavelist[i].DCprevious = prevDCslave; + } + /* this branch has DC slave so remove parenthold */ + parenthold = 0; + prevDCslave = i; + slaveh = context->slavelist[i].configadr; + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET); + context->slavelist[i].DCrtA = etohl(ht); + /* 64bit latched DCrecvTimeA of each specific slave */ + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSOF, sizeof(hrt), &hrt, EC_TIMEOUTRET); + /* use it as offset in order to set local time around 0 + mastertime */ + hrt = htoell(-etohll(hrt) + mastertime64); + /* save it in the offset register */ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSOFFSET, sizeof(hrt), &hrt, EC_TIMEOUTRET); + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME1, sizeof(ht), &ht, EC_TIMEOUTRET); + context->slavelist[i].DCrtB = etohl(ht); + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME2, sizeof(ht), &ht, EC_TIMEOUTRET); + context->slavelist[i].DCrtC = etohl(ht); + (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME3, sizeof(ht), &ht, EC_TIMEOUTRET); + context->slavelist[i].DCrtD = etohl(ht); + + /* make list of active ports and their time stamps */ + nlist = 0; + if (context->slavelist[i].activeports & PORTM0) + { + plist[nlist] = 0; + tlist[nlist] = context->slavelist[i].DCrtA; + nlist++; + } + if (context->slavelist[i].activeports & PORTM3) + { + plist[nlist] = 3; + tlist[nlist] = context->slavelist[i].DCrtD; + nlist++; + } + if (context->slavelist[i].activeports & PORTM1) + { + plist[nlist] = 1; + tlist[nlist] = context->slavelist[i].DCrtB; + nlist++; + } + if (context->slavelist[i].activeports & PORTM2) + { + plist[nlist] = 2; + tlist[nlist] = context->slavelist[i].DCrtC; + nlist++; + } + /* entryport is port with the lowest timestamp */ + entryport = 0; + if((nlist > 1) && (tlist[1] < tlist[entryport])) + { + entryport = 1; + } + if((nlist > 2) && (tlist[2] < tlist[entryport])) + { + entryport = 2; + } + if((nlist > 3) && (tlist[3] < tlist[entryport])) + { + entryport = 3; + } + entryport = plist[entryport]; + context->slavelist[i].entryport = entryport; + /* consume entryport from activeports */ + context->slavelist[i].consumedports &= (uint8)~(1 << entryport); + + /* finding DC parent of current */ + parent = i; + do + { + child = parent; + parent = context->slavelist[parent].parent; + } + while (!((parent == 0) || (context->slavelist[parent].hasdc))); + /* only calculate propagation delay if slave is not the first */ + if (parent > 0) + { + /* find port on parent this slave is connected to */ + context->slavelist[i].parentport = ecx_parentport(context, parent); + if (context->slavelist[parent].topology == 1) + { + context->slavelist[i].parentport = context->slavelist[parent].entryport; + } + + dt1 = 0; + dt2 = 0; + /* delta time of (parentport - 1) - parentport */ + /* note: order of ports is 0 - 3 - 1 -2 */ + /* non active ports are skipped */ + dt3 = ecx_porttime(context, parent, context->slavelist[i].parentport) - + ecx_porttime(context, parent, + ecx_prevport(context, parent, context->slavelist[i].parentport)); + /* current slave has children */ + /* those childrens delays need to be substacted */ + if (context->slavelist[i].topology > 1) + { + dt1 = ecx_porttime(context, i, + ecx_prevport(context, i, context->slavelist[i].entryport)) - + ecx_porttime(context, i, context->slavelist[i].entryport); + } + /* we are only interrested in positive diference */ + if (dt1 > dt3) dt1 = -dt1; + /* current slave is not the first child of parent */ + /* previous childs delays need to be added */ + if ((child - parent) > 1) + { + dt2 = ecx_porttime(context, parent, + ecx_prevport(context, parent, context->slavelist[i].parentport)) - + ecx_porttime(context, parent, context->slavelist[parent].entryport); + } + if (dt2 < 0) dt2 = -dt2; + + /* calculate current slave delay from delta times */ + /* assumption : forward delay equals return delay */ + context->slavelist[i].pdelay = ((dt3 - dt1) / 2) + dt2 + + context->slavelist[parent].pdelay; + ht = htoel(context->slavelist[i].pdelay); + /* write propagation delay*/ + (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSDELAY, sizeof(ht), &ht, EC_TIMEOUTRET); + } + } + else + { + context->slavelist[i].DCrtA = 0; + context->slavelist[i].DCrtB = 0; + context->slavelist[i].DCrtC = 0; + context->slavelist[i].DCrtD = 0; + parent = context->slavelist[i].parent; + /* if non DC slave found on first position on branch hold root parent */ + if ( (parent > 0) && (context->slavelist[parent].topology > 2)) + parenthold = parent; + /* if branch has no DC slaves consume port on root parent */ + if ( parenthold && (context->slavelist[i].topology == 1)) + { + ecx_parentport(context, parenthold); + parenthold = 0; + } + } + } + + return context->slavelist[0].hasdc; +} + +#ifdef EC_VER1 +void ec_dcsync0(uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift) +{ + ecx_dcsync0(&ecx_context, slave, act, CyclTime, CyclShift); +} + +void ec_dcsync01(uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift) +{ + ecx_dcsync01(&ecx_context, slave, act, CyclTime0, CyclTime1, CyclShift); +} + +boolean ec_configdc(void) +{ + return ecx_configdc(&ecx_context); +} +#endif diff --git a/soem/ethercatdc.h b/soem/ethercatdc.h new file mode 100644 index 0000000..f4131ee --- /dev/null +++ b/soem/ethercatdc.h @@ -0,0 +1,68 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatdc.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatdc.c + */ + +#ifndef _EC_ECATDC_H +#define _EC_ECATDC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef EC_VER1 +boolean ec_configdc(); +void ec_dcsync0(uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift); +void ec_dcsync01(uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift); +#endif + +boolean ecx_configdc(ecx_contextt *context); +void ecx_dcsync0(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, uint32 CyclShift); +void ecx_dcsync01(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, uint32 CyclShift); + +#ifdef __cplusplus +} +#endif + +#endif /* _EC_ECATDC_H */ diff --git a/soem/ethercatfoe.c b/soem/ethercatfoe.c new file mode 100644 index 0000000..2771f7d --- /dev/null +++ b/soem/ethercatfoe.c @@ -0,0 +1,400 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatfoe.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + * + * 14-06-2010 : fixed bug in FOEread() by Torsten Bitterlich + */ + +/** \file + * \brief + * File over EtherCAT (FoE) module. + * + * SDO read / write and SDO service functions + */ + +#include +#include +#include "osal.h" +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatfoe.h" + +#define EC_MAXFOEDATA 512 + +/** FOE structure. + * Used for Read, Write, Data, Ack and Error mailbox packets. + */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint8 OpCode; + uint8 Reserved; + union + { + uint32 Password; + uint32 PacketNumber; + uint32 ErrorCode; + }; + union + { + char FileName[EC_MAXFOEDATA]; + uint8 Data[EC_MAXFOEDATA]; + char ErrorText[EC_MAXFOEDATA]; + }; +} ec_FOEt; +PACKED_END + +/** FoE progress hook. + * + * @param[in] context = context struct + * @param[in] hook = Pointer to hook function. + * @return 1 + */ +int ecx_FOEdefinehook(ecx_contextt *context, void *hook) +{ + context->FOEhook = hook; + return 1; +} + +/** FoE read, blocking. + * + * @param[in] context = context struct + * @param[in] slave = Slave number. + * @param[in] filename = Filename of file to read. + * @param[in] password = password. + * @param[in,out] psize = Size in bytes of file buffer, returns bytes read from file. + * @param[out] p = Pointer to file buffer + * @param[in] timeout = Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout) +{ + ec_FOEt *FOEp, *aFOEp; + int wkc; + int32 dataread = 0; + int32 buffersize, packetnumber, prevpacket = 0; + uint16 fnsize, maxdata, segmentdata; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + boolean worktodo; + + buffersize = *psize; + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aFOEp = (ec_FOEt *)&MbxIn; + FOEp = (ec_FOEt *)&MbxOut; + fnsize = strlen(filename); + maxdata = context->slavelist[slave].mbx_l - 12; + if (fnsize > maxdata) + { + fnsize = maxdata; + } + FOEp->MbxHeader.length = htoes(0x0006 + fnsize); + FOEp->MbxHeader.address = htoes(0x0000); + FOEp->MbxHeader.priority = 0x00; + /* get new mailbox count value, used as session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */ + FOEp->OpCode = ECT_FOE_READ; + FOEp->Password = htoel(password); + /* copy filename in mailbox */ + memcpy(&FOEp->FileName[0], filename, fnsize); + /* send FoE request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) /* succeeded to place mailbox in slave ? */ + { + do + { + worktodo = FALSE; + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + /* slave response should be FoE */ + if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE) + { + if(aFOEp->OpCode == ECT_FOE_DATA) + { + segmentdata = etohs(aFOEp->MbxHeader.length) - 0x0006; + packetnumber = etohl(aFOEp->PacketNumber); + if ((packetnumber == ++prevpacket) && (dataread + segmentdata <= buffersize)) + { + memcpy(p, &aFOEp->Data[0], segmentdata); + dataread += segmentdata; + p = (uint8 *)p + segmentdata; + if (segmentdata == maxdata) + { + worktodo = TRUE; + } + FOEp->MbxHeader.length = htoes(0x0006); + FOEp->MbxHeader.address = htoes(0x0000); + FOEp->MbxHeader.priority = 0x00; + /* get new mailbox count value */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */ + FOEp->OpCode = ECT_FOE_ACK; + FOEp->PacketNumber = htoel(packetnumber); + /* send FoE ack to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc <= 0) + { + worktodo = FALSE; + } + if (context->FOEhook) + { + context->FOEhook(slave, packetnumber, dataread); + } + } + else + { + /* FoE error */ + wkc = -EC_ERR_TYPE_FOE_BUF2SMALL; + } + } + else + { + if(aFOEp->OpCode == ECT_FOE_ERROR) + { + /* FoE error */ + wkc = -EC_ERR_TYPE_FOE_ERROR; + } + else + { + /* unexpected mailbox received */ + wkc = -EC_ERR_TYPE_PACKET_ERROR; + } + } + } + else + { + /* unexpected mailbox received */ + wkc = -EC_ERR_TYPE_PACKET_ERROR; + } + *psize = dataread; + } + } while (worktodo); + } + + return wkc; +} + +/** FoE write, blocking. + * + * @param[in] context = context struct + * @param[in] slave = Slave number. + * @param[in] filename = Filename of file to write. + * @param[in] password = password. + * @param[in] psize = Size in bytes of file buffer. + * @param[out] p = Pointer to file buffer + * @param[in] timeout = Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout) +{ + ec_FOEt *FOEp, *aFOEp; + int wkc; + int32 packetnumber, sendpacket = 0; + uint16 fnsize, maxdata; + int segmentdata; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + boolean worktodo, dofinalzero; + int tsize; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aFOEp = (ec_FOEt *)&MbxIn; + FOEp = (ec_FOEt *)&MbxOut; + dofinalzero = FALSE; + fnsize = strlen(filename); + maxdata = context->slavelist[slave].mbx_l - 12; + if (fnsize > maxdata) + { + fnsize = maxdata; + } + FOEp->MbxHeader.length = htoes(0x0006 + fnsize); + FOEp->MbxHeader.address = htoes(0x0000); + FOEp->MbxHeader.priority = 0x00; + /* get new mailbox count value, used as session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */ + FOEp->OpCode = ECT_FOE_WRITE; + FOEp->Password = htoel(password); + /* copy filename in mailbox */ + memcpy(&FOEp->FileName[0], filename, fnsize); + /* send FoE request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) /* succeeded to place mailbox in slave ? */ + { + do + { + worktodo = FALSE; + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + /* slave response should be FoE */ + if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE) + { + switch (aFOEp->OpCode) + { + case ECT_FOE_ACK: + { + packetnumber = etohl(aFOEp->PacketNumber); + if (packetnumber == sendpacket) + { + if (context->FOEhook) + { + context->FOEhook(slave, packetnumber, psize); + } + tsize = psize; + if (tsize > maxdata) + { + tsize = maxdata; + } + if(tsize || dofinalzero) + { + worktodo = TRUE; + dofinalzero = FALSE; + segmentdata = tsize; + psize -= segmentdata; + /* if last packet was full size, add a zero size packet as final */ + /* EOF is defined as packetsize < full packetsize */ + if (!psize && (segmentdata == maxdata)) + { + dofinalzero = TRUE; + } + FOEp->MbxHeader.length = htoes(0x0006 + segmentdata); + FOEp->MbxHeader.address = htoes(0x0000); + FOEp->MbxHeader.priority = 0x00; + /* get new mailbox count value */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */ + FOEp->OpCode = ECT_FOE_DATA; + sendpacket++; + FOEp->PacketNumber = htoel(sendpacket); + memcpy(&FOEp->Data[0], p, segmentdata); + p = (uint8 *)p + segmentdata; + /* send FoE data to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc <= 0) + { + worktodo = FALSE; + } + } + } + else + { + /* FoE error */ + wkc = -EC_ERR_TYPE_FOE_PACKETNUMBER; + } + break; + } + case ECT_FOE_BUSY: + { + /* resend if data has been send before */ + /* otherwise ignore */ + if (sendpacket) + { + if (!psize) + { + dofinalzero = TRUE; + } + psize += segmentdata; + p = (uint8 *)p - segmentdata; + --sendpacket; + } + break; + } + case ECT_FOE_ERROR: + { + /* FoE error */ + wkc = -EC_ERR_TYPE_FOE_ERROR; + break; + } + default: + { + /* unexpected mailbox received */ + wkc = -EC_ERR_TYPE_PACKET_ERROR; + break; + } + } + } + else + { + /* unexpected mailbox received */ + wkc = -EC_ERR_TYPE_PACKET_ERROR; + } + } + } while (worktodo); + } + + return wkc; +} + +#ifdef EC_VER1 +int ec_FOEdefinehook(void *hook) +{ + return ecx_FOEdefinehook(&ecx_context, hook); +} + +int ec_FOEread(uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout) +{ + return ecx_FOEread(&ecx_context, slave, filename, password, psize, p, timeout); +} + +int ec_FOEwrite(uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout) +{ + return ecx_FOEwrite(&ecx_context, slave, filename, password, psize, p, timeout); +} +#endif diff --git a/soem/ethercatfoe.h b/soem/ethercatfoe.h new file mode 100644 index 0000000..7d45f7e --- /dev/null +++ b/soem/ethercatfoe.h @@ -0,0 +1,68 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatfoe.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatfoe.c + */ + +#ifndef _ethercatfoe_ +#define _ethercatfoe_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef EC_VER1 +int ec_FOEdefinehook(void *hook); +int ec_FOEread(uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout); +int ec_FOEwrite(uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout); +#endif + +int ecx_FOEdefinehook(ecx_contextt *context, void *hook); +int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout); +int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatmain.c b/soem/ethercatmain.c new file mode 100644 index 0000000..41e0e8e --- /dev/null +++ b/soem/ethercatmain.c @@ -0,0 +1,2058 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatmain.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** + * \file + * \brief + * Main EtherCAT functions. + * + * Initialisation, state set and read, mailbox primitives, EEPROM primitives, + * SII reading and processdata exchange. + * + * Defines ec_slave[]. All slave information is put in this structure. + * Needed for most user interaction with slaves. + */ + +#include +#include +#include "osal.h" +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" + + +/** delay in us for eeprom ready loop */ +#define EC_LOCALDELAY 200 + +/** record for ethercat eeprom communications */ +PACKED_BEGIN +typedef struct PACKED +{ + uint16 comm; + uint16 addr; + uint16 d2; +} ec_eepromt; +PACKED_END + +/** mailbox error structure */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint16 Type; + uint16 Detail; +} ec_mbxerrort; +PACKED_END + +/** emergency request structure */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint16 CANOpen; + uint16 ErrorCode; + uint8 ErrorReg; + uint8 bData; + uint16 w1,w2; +} ec_emcyt; +PACKED_END + +#ifdef EC_VER1 +/** Main slave data array. + * Each slave found on the network gets its own record. + * ec_slave[0] is reserved for the master. Structure gets filled + * in by the configuration function ec_config(). + */ +ec_slavet ec_slave[EC_MAXSLAVE]; +/** number of slaves found on the network */ +int ec_slavecount; +/** slave group structure */ +ec_groupt ec_group[EC_MAXGROUP]; + +/** cache for EEPROM read functions */ +static uint8 ec_esibuf[EC_MAXEEPBUF]; +/** bitmap for filled cache buffer bytes */ +static uint32 ec_esimap[EC_MAXEEPBITMAP]; +/** current slave for EEPROM cache buffer */ +static ec_eringt ec_elist; +static ec_idxstackT ec_idxstack; + +/** SyncManager Communication Type struct to store data of one slave */ +static ec_SMcommtypet ec_SMcommtype; +/** PDO assign struct to store data of one slave */ +static ec_PDOassignt ec_PDOassign; +/** PDO description struct to store data of one slave */ +static ec_PDOdesct ec_PDOdesc; + +/** buffer for EEPROM SM data */ +static ec_eepromSMt ec_SM; +/** buffer for EEPROM FMMU data */ +static ec_eepromFMMUt ec_FMMU; +/** Global variable TRUE if error available in error stack */ +boolean EcatError = FALSE; + +int64 ec_DCtime; + +ecx_portt ecx_port; +ecx_redportt ecx_redport; + +ecx_contextt ecx_context = { + &ecx_port, // .port = + &ec_slave[0], // .slavelist = + &ec_slavecount, // .slavecount = + EC_MAXSLAVE, // .maxslave = + &ec_group[0], // .grouplist = + EC_MAXGROUP, // .maxgroup = + &ec_esibuf[0], // .esibuf = + &ec_esimap[0], // .esimap = + 0, // .esislave = + &ec_elist, // .elist = + &ec_idxstack, // .idxstack = + &EcatError, // .ecaterror = + 0, // .DCtO = + 0, // .DCl = + &ec_DCtime, // .DCtime = + &ec_SMcommtype, // .SMcommtype = + &ec_PDOassign, // .PDOassign = + &ec_PDOdesc, // .PDOdesc = + &ec_SM, // .eepSM = + &ec_FMMU, // .eepFMMU = + NULL // .FOEhook() +}; +#endif + +/** Create list over available network adapters. + * + * @return First element in list over available network adapters. + */ +ec_adaptert * ec_find_adapters (void) +{ + ec_adaptert * ret_adapter; + + ret_adapter = oshw_find_adapters (); + + return ret_adapter; +} + +/** Free dynamically allocated list over available network adapters. + * + * @param[in] adapter = Struct holding adapter name, description and pointer to next. + */ +void ec_free_adapters (ec_adaptert * adapter) +{ + oshw_free_adapters (adapter); +} + +/** Pushes an error on the error list. + * + * @param[in] context = context struct + * @param[in] Ec pointer describing the error. + */ +void ecx_pusherror(ecx_contextt *context, const ec_errort *Ec) +{ + context->elist->Error[context->elist->head] = *Ec; + context->elist->Error[context->elist->head].Signal = TRUE; + context->elist->head++; + if (context->elist->head > EC_MAXELIST) + { + context->elist->head = 0; + } + if (context->elist->head == context->elist->tail) + { + context->elist->tail++; + } + if (context->elist->tail > EC_MAXELIST) + { + context->elist->tail = 0; + } + *(context->ecaterror) = TRUE; +} + +/** Pops an error from the list. + * + * @param[in] context = context struct + * @param[out] Ec = Struct describing the error. + * @return TRUE if an error was popped. + */ +boolean ecx_poperror(ecx_contextt *context, ec_errort *Ec) +{ + boolean notEmpty = (context->elist->head != context->elist->tail); + + *Ec = context->elist->Error[context->elist->tail]; + context->elist->Error[context->elist->tail].Signal = FALSE; + if (notEmpty) + { + context->elist->tail++; + if (context->elist->tail > EC_MAXELIST) + { + context->elist->tail = 0; + } + } + else + { + *(context->ecaterror) = FALSE; + } + return notEmpty; +} + +/** Check if error list has entries. + * + * @param[in] context = context struct + * @return TRUE if error list contains entries. + */ +boolean ecx_iserror(ecx_contextt *context) +{ + return (context->elist->head != context->elist->tail); +} + +/** Report packet error + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] Index = Index that generated error + * @param[in] SubIdx = Subindex that generated error + * @param[in] ErrorCode = Error code + */ +void ecx_packeterror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Time = osal_current_time(); + Ec.Slave = Slave; + Ec.Index = Index; + Ec.SubIdx = SubIdx; + *(context->ecaterror) = TRUE; + Ec.Etype = EC_ERR_TYPE_PACKET_ERROR; + Ec.ErrorCode = ErrorCode; + ecx_pusherror(context, &Ec); +} + +/** Report Mailbox Error + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] Detail = Following EtherCAT specification + */ +static void ecx_mbxerror(ecx_contextt *context, uint16 Slave,uint16 Detail) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Time = osal_current_time(); + Ec.Slave = Slave; + Ec.Index = 0; + Ec.SubIdx = 0; + Ec.Etype = EC_ERR_TYPE_MBX_ERROR; + Ec.ErrorCode = Detail; + ecx_pusherror(context, &Ec); +} + +/** Report Mailbox Emergency Error + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] ErrorCode = Following EtherCAT specification + * @param[in] ErrorReg + * @param[in] b1 + * @param[in] w1 + * @param[in] w2 + */ +static void ecx_mbxemergencyerror(ecx_contextt *context, uint16 Slave,uint16 ErrorCode,uint16 ErrorReg, + uint8 b1, uint16 w1, uint16 w2) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Time = osal_current_time(); + Ec.Slave = Slave; + Ec.Index = 0; + Ec.SubIdx = 0; + Ec.Etype = EC_ERR_TYPE_EMERGENCY; + Ec.ErrorCode = ErrorCode; + Ec.ErrorReg = (uint8)ErrorReg; + Ec.b1 = b1; + Ec.w1 = w1; + Ec.w2 = w2; + ecx_pusherror(context, &Ec); +} + +/** Initialise lib in single NIC mode + * @param[in] context = context struct + * @param[in] ifname = Dev name, f.e. "eth0" + * @return >0 if OK + */ +int ecx_init(ecx_contextt *context, char * ifname) +{ + return ecx_setupnic(context->port, ifname, FALSE); +} + +/** Initialise lib in redundant NIC mode + * @param[in] context = context struct + * @param[in] redport = pointer to redport, redundant port data + * @param[in] ifname = Primary Dev name, f.e. "eth0" + * @param[in] if2name = Secondary Dev name, f.e. "eth1" + * @return >0 if OK + */ +int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, char *ifname, char *if2name) +{ + int rval, zbuf; + ec_etherheadert *ehp; + + context->port->redport = redport; + ecx_setupnic(context->port, ifname, FALSE); + rval = ecx_setupnic(context->port, if2name, TRUE); + /* prepare "dummy" BRD tx frame for redundant operation */ + ehp = (ec_etherheadert *)&(context->port->txbuf2); + ehp->sa1 = oshw_htons(secMAC[0]); + zbuf = 0; + ecx_setupdatagram(context->port, &(context->port->txbuf2), EC_CMD_BRD, 0, 0x0000, 0x0000, 2, &zbuf); + context->port->txbuflength2 = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + 2; + + return rval; +} + +/** Close lib. + * @param[in] context = context struct + */ +void ecx_close(ecx_contextt *context) +{ + ecx_closenic(context->port); +}; + +/** Read one byte from slave EEPROM via cache. + * If the cache location is empty then a read request is made to the slave. + * Depending on the slave capabillities the request is 4 or 8 bytes. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[in] address = eeprom address in bytes (slave uses words) + * @return requested byte, if not available then 0xff + */ +uint8 ecx_siigetbyte(ecx_contextt *context, uint16 slave, uint16 address) +{ + uint16 configadr, eadr; + uint64 edat; + uint16 mapw, mapb; + int lp,cnt; + uint8 retval; + + retval = 0xff; + if (slave != context->esislave) /* not the same slave? */ + { + memset(context->esimap, 0x00, EC_MAXEEPBITMAP * sizeof(uint32)); /* clear esibuf cache map */ + context->esislave = slave; + } + if (address < EC_MAXEEPBUF) + { + mapw = address >> 5; + mapb = address - (mapw << 5); + if (context->esimap[mapw] & (uint32)(1 << mapb)) + { + /* byte is already in buffer */ + retval = context->esibuf[address]; + } + else + { + /* byte is not in buffer, put it there */ + configadr = context->slavelist[slave].configadr; + ecx_eeprom2master(context, slave); /* set eeprom control to master */ + eadr = address >> 1; + edat = ecx_readeepromFP (context, configadr, eadr, EC_TIMEOUTEEP); + /* 8 byte response */ + if (context->slavelist[slave].eep_8byte) + { + put_unaligned64(edat, &(context->esibuf[eadr << 1])); + cnt = 8; + } + /* 4 byte response */ + else + { + put_unaligned32(edat, &(context->esibuf[eadr << 1])); + cnt = 4; + } + /* find bitmap location */ + mapw = eadr >> 4; + mapb = (eadr << 1) - (mapw << 5); + for(lp = 0 ; lp < cnt ; lp++) + { + /* set bitmap for each byte that is read */ + context->esimap[mapw] |= (1 << mapb); + mapb++; + if (mapb > 31) + { + mapb = 0; + mapw++; + } + } + retval = context->esibuf[address]; + } + } + + return retval; +} + +/** Find SII section header in slave EEPROM. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[in] cat = section category + * @return byte address of section at section length entry, if not available then 0 + */ +int16 ecx_siifind(ecx_contextt *context, uint16 slave, uint16 cat) +{ + int16 a; + uint16 p; + uint8 eectl = context->slavelist[slave].eep_pdi; + + a = ECT_SII_START << 1; + /* read first SII section category */ + p = ecx_siigetbyte(context, slave, a++); + p += (ecx_siigetbyte(context, slave, a++) << 8); + /* traverse SII while category is not found and not EOF */ + while ((p != cat) && (p != 0xffff)) + { + /* read section length */ + p = ecx_siigetbyte(context, slave, a++); + p += (ecx_siigetbyte(context, slave, a++) << 8); + /* locate next section category */ + a += p << 1; + /* read section category */ + p = ecx_siigetbyte(context, slave, a++); + p += (ecx_siigetbyte(context, slave, a++) << 8); + } + if (p != cat) + { + a = 0; + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } + + return a; +} + +/** Get string from SII string section in slave EEPROM. + * @param[in] context = context struct + * @param[out] str = requested string, 0x00 if not found + * @param[in] slave = slave number + * @param[in] Sn = string number + */ +void ecx_siistring(ecx_contextt *context, char *str, uint16 slave, uint16 Sn) +{ + uint16 a,i,j,l,n,ba; + char *ptr; + uint8 eectl = context->slavelist[slave].eep_pdi; + + ptr = str; + a = ecx_siifind (context, slave, ECT_SII_STRING); /* find string section */ + if (a > 0) + { + ba = a + 2; /* skip SII section header */ + n = ecx_siigetbyte(context, slave, ba++); /* read number of strings in section */ + if (Sn <= n) /* is req string available? */ + { + for (i = 1; i <= Sn; i++) /* walk through strings */ + { + l = ecx_siigetbyte(context, slave, ba++); /* length of this string */ + if (i < Sn) + { + ba += l; + } + else + { + ptr = str; + for (j = 1; j <= l; j++) /* copy one string */ + { + if(j <= EC_MAXNAME) + { + *ptr = (char)ecx_siigetbyte(context, slave, ba++); + ptr++; + } + else + { + ba++; + } + } + } + } + *ptr = 0; /* add zero terminator */ + } + else + { + ptr = str; + *ptr = 0; /* empty string */ + } + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } +} + +/** Get FMMU data from SII FMMU section in slave EEPROM. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[out] FMMU = FMMU struct from SII, max. 4 FMMU's + * @return number of FMMU's defined in section + */ +uint16 ecx_siiFMMU(ecx_contextt *context, uint16 slave, ec_eepromFMMUt* FMMU) +{ + uint16 a; + uint8 eectl = context->slavelist[slave].eep_pdi; + + FMMU->nFMMU = 0; + FMMU->FMMU0 = 0; + FMMU->FMMU1 = 0; + FMMU->FMMU2 = 0; + FMMU->FMMU3 = 0; + FMMU->Startpos = ecx_siifind(context, slave, ECT_SII_FMMU); + + if (FMMU->Startpos > 0) + { + a = FMMU->Startpos; + FMMU->nFMMU = ecx_siigetbyte(context, slave, a++); + FMMU->nFMMU += (ecx_siigetbyte(context, slave, a++) << 8); + FMMU->nFMMU *= 2; + FMMU->FMMU0 = ecx_siigetbyte(context, slave, a++); + FMMU->FMMU1 = ecx_siigetbyte(context, slave, a++); + if (FMMU->nFMMU > 2) + { + FMMU->FMMU2 = ecx_siigetbyte(context, slave, a++); + FMMU->FMMU3 = ecx_siigetbyte(context, slave, a++); + } + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } + + return FMMU->nFMMU; +} + +/** Get SM data from SII SM section in slave EEPROM. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[out] SM = first SM struct from SII + * @return number of SM's defined in section + */ +uint16 ecx_siiSM(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM) +{ + uint16 a,w; + uint8 eectl = context->slavelist[slave].eep_pdi; + + SM->nSM = 0; + SM->Startpos = ecx_siifind(context, slave, ECT_SII_SM); + if (SM->Startpos > 0) + { + a = SM->Startpos; + w = ecx_siigetbyte(context, slave, a++); + w += (ecx_siigetbyte(context, slave, a++) << 8); + SM->nSM = (w / 4); + SM->PhStart = ecx_siigetbyte(context, slave, a++); + SM->PhStart += (ecx_siigetbyte(context, slave, a++) << 8); + SM->Plength = ecx_siigetbyte(context, slave, a++); + SM->Plength += (ecx_siigetbyte(context, slave, a++) << 8); + SM->Creg = ecx_siigetbyte(context, slave, a++); + SM->Sreg = ecx_siigetbyte(context, slave, a++); + SM->Activate = ecx_siigetbyte(context, slave, a++); + SM->PDIctrl = ecx_siigetbyte(context, slave, a++); + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } + + return SM->nSM; +} + +/** Get next SM data from SII SM section in slave EEPROM. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[out] SM = first SM struct from SII + * @param[in] n = SM number + * @return >0 if OK + */ +uint16 ecx_siiSMnext(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM, uint16 n) +{ + uint16 a; + uint16 retVal = 0; + uint8 eectl = context->slavelist[slave].eep_pdi; + + if (n < SM->nSM) + { + a = SM->Startpos + 2 + (n * 8); + SM->PhStart = ecx_siigetbyte(context, slave, a++); + SM->PhStart += (ecx_siigetbyte(context, slave, a++) << 8); + SM->Plength = ecx_siigetbyte(context, slave, a++); + SM->Plength += (ecx_siigetbyte(context, slave, a++) << 8); + SM->Creg = ecx_siigetbyte(context, slave, a++); + SM->Sreg = ecx_siigetbyte(context, slave, a++); + SM->Activate = ecx_siigetbyte(context, slave, a++); + SM->PDIctrl = ecx_siigetbyte(context, slave, a++); + retVal = 1; + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } + + return retVal; +} + +/** Get PDO data from SII PDO section in slave EEPROM. + * @param[in] context = context struct + * @param[in] slave = slave number + * @param[out] PDO = PDO struct from SII + * @param[in] t = 0=RXPDO 1=TXPDO + * @return mapping size in bits of PDO + */ +int ecx_siiPDO(ecx_contextt *context, uint16 slave, ec_eepromPDOt* PDO, uint8 t) +{ + uint16 a , w, c, e, er, Size; + uint8 eectl = context->slavelist[slave].eep_pdi; + + Size = 0; + PDO->nPDO = 0; + PDO->Length = 0; + PDO->Index[1] = 0; + for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0; + if (t > 1) + t = 1; + PDO->Startpos = ecx_siifind(context, slave, ECT_SII_PDO + t); + if (PDO->Startpos > 0) + { + a = PDO->Startpos; + w = ecx_siigetbyte(context, slave, a++); + w += (ecx_siigetbyte(context, slave, a++) << 8); + PDO->Length = w; + c = 1; + /* traverse through all PDOs */ + do + { + PDO->nPDO++; + PDO->Index[PDO->nPDO] = ecx_siigetbyte(context, slave, a++); + PDO->Index[PDO->nPDO] += (ecx_siigetbyte(context, slave, a++) << 8); + PDO->BitSize[PDO->nPDO] = 0; + c++; + e = ecx_siigetbyte(context, slave, a++); + PDO->SyncM[PDO->nPDO] = ecx_siigetbyte(context, slave, a++); + a += 4; + c += 2; + if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */ + { + /* read all entries defined in PDO */ + for (er = 1; er <= e; er++) + { + c += 4; + a += 5; + PDO->BitSize[PDO->nPDO] += ecx_siigetbyte(context, slave, a++); + a += 2; + } + PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO]; + Size += PDO->BitSize[PDO->nPDO]; + c++; + } + else /* PDO deactivated because SM is 0xff or > EC_MAXSM */ + { + c += 4 * e; + a += 8 * e; + c++; + } + if (PDO->nPDO >= (EC_MAXEEPDO - 1)) + { + c = PDO->Length; /* limit number of PDO entries in buffer */ + } + } + while (c < PDO->Length); + } + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } + + return (Size); +} + +#define MAX_FPRD_MULTI 64 + +int ecx_FPRD_multi(ecx_contextt *context, int n, uint16 *configlst, ec_alstatust *slstatlst, int timeout) +{ + int wkc; + uint8 idx; + ecx_portt *port; + int sldatapos[MAX_FPRD_MULTI]; + int slcnt; + + port = context->port; + idx = ecx_getindex(port); + slcnt = 0; + ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, + *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); + sldatapos[slcnt] = EC_HEADERSIZE; + while(++slcnt < (n - 1)) + { + sldatapos[slcnt] = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, TRUE, + *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); + } + if(slcnt < n) + { + sldatapos[slcnt] = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, FALSE, + *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); + } + wkc = ecx_srconfirm(port, idx, timeout); + if (wkc >= 0) + { + for(slcnt = 0 ; slcnt < n ; slcnt++) + { + memcpy(slstatlst + slcnt, &(port->rxbuf[idx][sldatapos[slcnt]]), sizeof(ec_alstatust)); + } + } + ecx_setbufstat(port, idx, EC_BUF_EMPTY); + return wkc; +} + +/** Read all slave states in ec_slave. + * @param[in] context = context struct + * @return lowest state found + */ +int ecx_readstate(ecx_contextt *context) +{ + uint16 slave, fslave, lslave, configadr, lowest, rval; + ec_alstatust sl[MAX_FPRD_MULTI]; + uint16 slca[MAX_FPRD_MULTI]; + + lowest = 0xff; + context->slavelist[0].ALstatuscode = 0; + fslave = 1; + do + { + lslave = *(context->slavecount); + if ((lslave - fslave) >= MAX_FPRD_MULTI) + { + lslave = fslave + MAX_FPRD_MULTI - 1; + } + for (slave = fslave; slave <= lslave; slave++) + { + const ec_alstatust zero = {0, 0, 0}; + + configadr = context->slavelist[slave].configadr; + slca[slave - fslave] = configadr; + sl[slave - fslave] = zero; + } + ecx_FPRD_multi(context, (lslave - fslave) + 1, &(slca[0]), &(sl[0]), EC_TIMEOUTRET3); + for (slave = fslave; slave <= lslave; slave++) + { + configadr = context->slavelist[slave].configadr; + rval = etohs(sl[slave - fslave].alstatus); + context->slavelist[slave].ALstatuscode = etohs(sl[slave - fslave].alstatuscode); + if (rval < lowest) + { + lowest = rval; + } + context->slavelist[slave].state = rval; + context->slavelist[0].ALstatuscode |= context->slavelist[slave].ALstatuscode; + } + fslave = lslave + 1; + } while(lslave < *(context->slavecount)); + context->slavelist[0].state = lowest; + + return lowest; +} + +/** Write slave state, if slave = 0 then write to all slaves. + * The function does not check if the actual state is changed. + * @param[in] context = context struct + * @param[in] slave = Slave number, 0 = master + * @return 0 + */ +int ecx_writestate(ecx_contextt *context, uint16 slave) +{ + uint16 configadr, slstate; + + if (slave == 0) + { + slstate = htoes(context->slavelist[slave].state); + ecx_BWR(context->port, 0, ECT_REG_ALCTL, sizeof(slstate), &slstate, EC_TIMEOUTRET3); /* write slave status */ + } + else + { + configadr = context->slavelist[slave].configadr; + + ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(context->slavelist[slave].state), EC_TIMEOUTRET3); /* write slave status */ + } + return 0; +} + +/** Check actual slave state. + * This is a blocking function. + * @param[in] context = context struct + * @param[in] slave = Slave number, 0 = all slaves + * @param[in] reqstate = Requested state + * @param[in] timeout = Timout value in us + * @return Requested state, or found state after timeout. + */ +uint16 ecx_statecheck(ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout) +{ + uint16 configadr, state, rval; + ec_alstatust slstat; + osal_timert timer; + + if ( slave > *(context->slavecount) ) + { + return 0; + } + osal_timer_start(&timer, timeout); + configadr = context->slavelist[slave].configadr; + do + { + if (slave < 1) + { + rval = 0; + ecx_BRD(context->port, 0, ECT_REG_ALSTAT, sizeof(rval), &rval , EC_TIMEOUTRET); + rval = etohs(rval); + } + else + { + slstat.alstatus = 0; + slstat.alstatuscode = 0; + ecx_FPRD(context->port, configadr, ECT_REG_ALSTAT, sizeof(slstat), &slstat, EC_TIMEOUTRET); + rval = etohs(slstat.alstatus); + context->slavelist[slave].ALstatuscode = etohs(slstat.alstatuscode); + } + state = rval & 0x000f; /* read slave status */ + if (state != reqstate) + { + osal_usleep(1000); + } + } + while ((state != reqstate) && (osal_timer_is_expired(&timer) == FALSE)); + context->slavelist[slave].state = rval; + + return state; +} + +/** Get index of next mailbox counter value. + * Used for Mailbox Link Layer. + * @param[in] cnt = Mailbox counter value [0..7] + * @return next mailbox counter value + */ +uint8 ec_nextmbxcnt(uint8 cnt) +{ + cnt++; + if (cnt > 7) + { + cnt = 1; /* wrap around to 1, not 0 */ + } + + return cnt; +} + +/** Clear mailbox buffer. + * @param[out] Mbx = Mailbox buffer to clear + */ +void ec_clearmbx(ec_mbxbuft *Mbx) +{ + memset(Mbx, 0x00, EC_MAXMBX); +} + +/** Check if IN mailbox of slave is empty. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] timeout = Timeout in us + * @return >0 is success + */ +int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout) +{ + uint16 configadr; + uint8 SMstat; + int wkc; + osal_timert timer; + + osal_timer_start(&timer, timeout); + configadr = context->slavelist[slave].configadr; + do + { + SMstat = 0; + wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM0STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); + SMstat = etohs(SMstat); + if (((SMstat & 0x08) != 0) && (timeout > EC_LOCALDELAY)) + { + osal_usleep(EC_LOCALDELAY); + } + } + while (((wkc <= 0) || ((SMstat & 0x08) != 0)) && (osal_timer_is_expired(&timer) == FALSE)); + + if ((wkc > 0) && ((SMstat & 0x08) == 0)) + { + return 1; + } + + return 0; +} + +/** Write IN mailbox to slave. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[out] mbx = Mailbox data + * @param[in] timeout = Timeout in us + * @return Work counter (>0 is success) + */ +int ecx_mbxsend(ecx_contextt *context, uint16 slave,ec_mbxbuft *mbx, int timeout) +{ + uint16 mbxwo,mbxl,configadr; + int wkc; + + wkc = 0; + configadr = context->slavelist[slave].configadr; + mbxl = context->slavelist[slave].mbx_l; + if ((mbxl > 0) && (mbxl <= EC_MAXMBX)) + { + if (ecx_mbxempty(context, slave, timeout)) + { + mbxwo = context->slavelist[slave].mbx_wo; + /* write slave in mailbox */ + wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET3); + } + else + { + wkc = 0; + } + } + + return wkc; +} + +/** Read OUT mailbox from slave. + * Supports Mailbox Link Layer with repeat requests. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[out] mbx = Mailbox data + * @param[in] timeout = Timeout in us + * @return Work counter (>0 is success) + */ +int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout) +{ + uint16 mbxro,mbxl,configadr; + int wkc=0; + int wkc2; + uint16 SMstat; + uint8 SMcontr; + ec_mbxheadert *mbxh; + ec_emcyt *EMp; + ec_mbxerrort *MBXEp; + + configadr = context->slavelist[slave].configadr; + mbxl = context->slavelist[slave].mbx_rl; + if ((mbxl > 0) && (mbxl <= EC_MAXMBX)) + { + osal_timert timer; + + osal_timer_start(&timer, timeout); + wkc = 0; + do /* wait for read mailbox available */ + { + SMstat = 0; + wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); + SMstat = etohs(SMstat); + if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY)) + { + osal_usleep(EC_LOCALDELAY); + } + } + while (((wkc <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE)); + + if ((wkc > 0) && ((SMstat & 0x08) > 0)) /* read mailbox available ? */ + { + mbxro = context->slavelist[slave].mbx_ro; + mbxh = (ec_mbxheadert *)mbx; + do + { + wkc = ecx_FPRD(context->port, configadr, mbxro, mbxl, mbx, EC_TIMEOUTRET); /* get mailbox */ + if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x00)) /* Mailbox error response? */ + { + MBXEp = (ec_mbxerrort *)mbx; + ecx_mbxerror(context, slave, etohs(MBXEp->Detail)); + wkc = 0; /* prevent emergency to cascade up, it is already handled. */ + } + else if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x03)) /* CoE response? */ + { + EMp = (ec_emcyt *)mbx; + if ((etohs(EMp->CANOpen) >> 12) == 0x01) /* Emergency request? */ + { + ecx_mbxemergencyerror(context, slave, etohs(EMp->ErrorCode), EMp->ErrorReg, + EMp->bData, etohs(EMp->w1), etohs(EMp->w2)); + wkc = 0; /* prevent emergency to cascade up, it is already handled. */ + } + } + else + { + if (wkc <= 0) /* read mailbox lost */ + { + SMstat ^= 0x0200; /* toggle repeat request */ + SMstat = htoes(SMstat); + wkc2 = ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); + SMstat = etohs(SMstat); + do /* wait for toggle ack */ + { + wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET); + } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstat) & 0x02))) && (osal_timer_is_expired(&timer) == FALSE)); + do /* wait for read mailbox available */ + { + wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); + SMstat = etohs(SMstat); + if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY)) + { + osal_usleep(EC_LOCALDELAY); + } + } while (((wkc2 <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE)); + } + } + } while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE)); /* if WKC<=0 repeat */ + } + else /* no read mailbox available */ + { + wkc = 0; + } + } + + return wkc; +} + +/** Dump complete EEPROM data from slave in buffer. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[out] esibuf = EEPROM data buffer, make sure it is big enough. + */ +void ecx_esidump(ecx_contextt *context, uint16 slave, uint8 *esibuf) +{ + int address, incr; + uint16 configadr; + uint64 *p64; + uint16 *p16; + uint64 edat; + uint8 eectl = context->slavelist[slave].eep_pdi; + + ecx_eeprom2master(context, slave); /* set eeprom control to master */ + configadr = context->slavelist[slave].configadr; + address = ECT_SII_START; + p16=(uint16*)esibuf; + if (context->slavelist[slave].eep_8byte) + { + incr = 4; + } + else + { + incr = 2; + } + do + { + edat = ecx_readeepromFP(context, configadr, address, EC_TIMEOUTEEP); + p64 = (uint64*)p16; + *p64 = edat; + p16 += incr; + address += incr; + } while ((address <= (EC_MAXEEPBUF >> 1)) && ((uint32)edat != 0xffffffff)); + + if (eectl) + { + ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ + } +} + +/** Read EEPROM from slave bypassing cache. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] timeout = Timeout in us. + * @return EEPROM data 32bit + */ +uint32 ecx_readeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout) +{ + uint16 configadr; + + ecx_eeprom2master(context, slave); /* set eeprom control to master */ + configadr = context->slavelist[slave].configadr; + + return ((uint32)ecx_readeepromFP(context, configadr, eeproma, timeout)); +} + +/** Write EEPROM to slave bypassing cache. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] data = 16bit data + * @param[in] timeout = Timeout in us. + * @return >0 if OK + */ +int ecx_writeeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout) +{ + uint16 configadr; + + ecx_eeprom2master(context, slave); /* set eeprom control to master */ + configadr = context->slavelist[slave].configadr; + return (ecx_writeeepromFP(context, configadr, eeproma, data, timeout)); +} + +/** Set eeprom control to master. Only if set to PDI. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @return >0 if OK + */ +int ecx_eeprom2master(ecx_contextt *context, uint16 slave) +{ + int wkc = 1, cnt = 0; + uint16 configadr; + uint8 eepctl; + + if ( context->slavelist[slave].eep_pdi ) + { + configadr = context->slavelist[slave].configadr; + eepctl = 2; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + eepctl = 0; + cnt = 0; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + context->slavelist[slave].eep_pdi = 0; + } + + return wkc; +} + +/** Set eeprom control to PDI. Only if set to master. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @return >0 if OK + */ +int ecx_eeprom2pdi(ecx_contextt *context, uint16 slave) +{ + int wkc = 1, cnt = 0; + uint16 configadr; + uint8 eepctl; + + if ( !context->slavelist[slave].eep_pdi ) + { + configadr = context->slavelist[slave].configadr; + eepctl = 1; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to PDI */ + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + context->slavelist[slave].eep_pdi = 1; + } + + return wkc; +} + +uint16 ecx_eeprom_waitnotbusyAP(ecx_contextt *context, uint16 aiadr,uint16 *estat, int timeout) +{ + int wkc, cnt = 0, retval = 0; + osal_timert timer; + + osal_timer_start(&timer, timeout); + do + { + if (cnt++) + { + osal_usleep(EC_LOCALDELAY); + } + *estat = 0; + wkc=ecx_APRD(context->port, aiadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET); + *estat = etohs(*estat); + } + while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (osal_timer_is_expired(&timer) == FALSE)); /* wait for eeprom ready */ + if ((*estat & EC_ESTAT_BUSY) == 0) + { + retval = 1; + } + + return retval; +} + +/** Read EEPROM from slave bypassing cache. APRD method. + * @param[in] context = context struct + * @param[in] aiadr = auto increment address of slave + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] timeout = Timeout in us. + * @return EEPROM data 64bit or 32bit + */ +uint64 ecx_readeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout) +{ + uint16 estat; + uint32 edat32; + uint64 edat64; + ec_eepromt ed; + int wkc, cnt, nackcnt = 0; + + edat64 = 0; + edat32 = 0; + if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) + { + if (estat & EC_ESTAT_EMASK) /* error bits are set */ + { + estat = htoes(EC_ECMD_NOP); /* clear error bits */ + wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); + } + + do + { + ed.comm = htoes(EC_ECMD_READ); + ed.addr = htoes(eeproma); + ed.d2 = 0x0000; + cnt = 0; + do + { + wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + if (wkc) + { + osal_usleep(EC_LOCALDELAY); + estat = 0x0000; + if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) + { + if (estat & EC_ESTAT_NACK) + { + nackcnt++; + osal_usleep(EC_LOCALDELAY * 5); + } + else + { + nackcnt = 0; + if (estat & EC_ESTAT_R64) + { + cnt = 0; + do + { + wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + } + else + { + cnt = 0; + do + { + wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + edat64=(uint64)edat32; + } + } + } + } + } + while ((nackcnt > 0) && (nackcnt < 3)); + } + + return edat64; +} + +/** Write EEPROM to slave bypassing cache. APWR method. + * @param[in] context = context struct + * @param[in] aiadr = configured address of slave + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] data = 16bit data + * @param[in] timeout = Timeout in us. + * @return >0 if OK + */ +int ecx_writeeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout) +{ + uint16 estat; + ec_eepromt ed; + int wkc, rval = 0, cnt = 0, nackcnt = 0; + + if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) + { + if (estat & EC_ESTAT_EMASK) /* error bits are set */ + { + estat = htoes(EC_ECMD_NOP); /* clear error bits */ + wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); + } + do + { + cnt = 0; + do + { + wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + + ed.comm = EC_ECMD_WRITE; + ed.addr = eeproma; + ed.d2 = 0x0000; + cnt = 0; + do + { + wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + if (wkc) + { + osal_usleep(EC_LOCALDELAY * 2); + estat = 0x0000; + if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) + { + if (estat & EC_ESTAT_NACK) + { + nackcnt++; + osal_usleep(EC_LOCALDELAY * 5); + } + else + { + nackcnt = 0; + rval = 1; + } + } + } + + } + while ((nackcnt > 0) && (nackcnt < 3)); + } + + return rval; +} + +uint16 ecx_eeprom_waitnotbusyFP(ecx_contextt *context, uint16 configadr,uint16 *estat, int timeout) +{ + int wkc, cnt = 0, retval = 0; + osal_timert timer; + + osal_timer_start(&timer, timeout); + do + { + if (cnt++) + { + osal_usleep(EC_LOCALDELAY); + } + *estat = 0; + wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET); + *estat = etohs(*estat); + } + while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (osal_timer_is_expired(&timer) == FALSE)); /* wait for eeprom ready */ + if ((*estat & EC_ESTAT_BUSY) == 0) + { + retval = 1; + } + + return retval; +} + +/** Read EEPROM from slave bypassing cache. FPRD method. + * @param[in] context = context struct + * @param[in] configadr = configured address of slave + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] timeout = Timeout in us. + * @return EEPROM data 64bit or 32bit + */ +uint64 ecx_readeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout) +{ + uint16 estat; + uint32 edat32; + uint64 edat64; + ec_eepromt ed; + int wkc, cnt, nackcnt = 0; + + edat64 = 0; + edat32 = 0; + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) + { + if (estat & EC_ESTAT_EMASK) /* error bits are set */ + { + estat = htoes(EC_ECMD_NOP); /* clear error bits */ + wkc=ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); + } + + do + { + ed.comm = htoes(EC_ECMD_READ); + ed.addr = htoes(eeproma); + ed.d2 = 0x0000; + cnt = 0; + do + { + wkc=ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + if (wkc) + { + osal_usleep(EC_LOCALDELAY); + estat = 0x0000; + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) + { + if (estat & EC_ESTAT_NACK) + { + nackcnt++; + osal_usleep(EC_LOCALDELAY * 5); + } + else + { + nackcnt = 0; + if (estat & EC_ESTAT_R64) + { + cnt = 0; + do + { + wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + } + else + { + cnt = 0; + do + { + wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + edat64=(uint64)edat32; + } + } + } + } + } + while ((nackcnt > 0) && (nackcnt < 3)); + } + + return edat64; +} + +/** Write EEPROM to slave bypassing cache. FPWR method. + * @param[in] context = context struct + * @param[in] configadr = configured address of slave + * @param[in] eeproma = (WORD) Address in the EEPROM + * @param[in] data = 16bit data + * @param[in] timeout = Timeout in us. + * @return >0 if OK + */ +int ecx_writeeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout) +{ + uint16 estat; + ec_eepromt ed; + int wkc, rval = 0, cnt = 0, nackcnt = 0; + + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) + { + if (estat & EC_ESTAT_EMASK) /* error bits are set */ + { + estat = htoes(EC_ECMD_NOP); /* clear error bits */ + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); + } + do + { + cnt = 0; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + ed.comm = EC_ECMD_WRITE; + ed.addr = eeproma; + ed.d2 = 0x0000; + cnt = 0; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + if (wkc) + { + osal_usleep(EC_LOCALDELAY * 2); + estat = 0x0000; + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) + { + if (estat & EC_ESTAT_NACK) + { + nackcnt++; + osal_usleep(EC_LOCALDELAY * 5); + } + else + { + nackcnt = 0; + rval = 1; + } + } + } + } + while ((nackcnt > 0) && (nackcnt < 3)); + } + + return rval; +} + +/** Read EEPROM from slave bypassing cache. + * Parallel read step 1, make request to slave. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] eeproma = (WORD) Address in the EEPROM + */ +void ecx_readeeprom1(ecx_contextt *context, uint16 slave, uint16 eeproma) +{ + uint16 configadr, estat; + ec_eepromt ed; + int wkc, cnt = 0; + + ecx_eeprom2master(context, slave); /* set eeprom control to master */ + configadr = context->slavelist[slave].configadr; + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, EC_TIMEOUTEEP)) + { + if (estat & EC_ESTAT_EMASK) /* error bits are set */ + { + estat = htoes(EC_ECMD_NOP); /* clear error bits */ + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); + } + ed.comm = htoes(EC_ECMD_READ); + ed.addr = htoes(eeproma); + ed.d2 = 0x0000; + do + { + wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + } +} + +/** Read EEPROM from slave bypassing cache. + * Parallel read step 2, actual read from slave. + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] timeout = Timeout in us. + * @return EEPROM data 32bit + */ +uint32 ecx_readeeprom2(ecx_contextt *context, uint16 slave, int timeout) +{ + uint16 estat, configadr; + uint32 edat; + int wkc, cnt = 0; + + configadr = context->slavelist[slave].configadr; + edat = 0; + estat = 0x0000; + if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) + { + do + { + wkc = ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat), &edat, EC_TIMEOUTRET); + } + while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); + } + + return edat; +} + +/** Push index of segmented LRD/LWR/LRW combination. + * @param[in] context = context struct + * @param[in] idx = Used datagram index. + * @param[in] data = Pointer to process data segment. + * @param[in] length = Length of data segment in bytes. + */ +static void ecx_pushindex(ecx_contextt *context, uint8 idx, void *data, uint16 length) +{ + if(context->idxstack->pushed < EC_MAXBUF) + { + context->idxstack->idx[context->idxstack->pushed] = idx; + context->idxstack->data[context->idxstack->pushed] = data; + context->idxstack->length[context->idxstack->pushed] = length; + context->idxstack->pushed++; + } +} + +/** Pull index of segmented LRD/LWR/LRW combination. + * @param[in] context = context struct + * @return Stack location, -1 if stack is empty. + */ +static int ecx_pullindex(ecx_contextt *context) +{ + int rval = -1; + if(context->idxstack->pulled < context->idxstack->pushed) + { + rval = context->idxstack->pulled; + context->idxstack->pulled++; + } + + return rval; +} + +/** Transmit processdata to slaves. + * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). + * Both the input and output processdata are transmitted. + * The outputs with the actual data, the inputs have a placeholder. + * The inputs are gathered with the receive processdata function. + * In contrast to the base LRW function this function is non-blocking. + * If the processdata does not fit in one datagram, multiple are used. + * In order to recombine the slave response, a stack is used. + * @param[in] context = context struct + * @param[in] group = group number + * @return >0 if processdata is transmitted. + */ +int ecx_send_processdata_group(ecx_contextt *context, uint8 group) +{ + uint32 LogAdr; + uint16 w1, w2; + int length, sublength; + uint8 idx; + int wkc; + uint8* data; + boolean first=FALSE; + uint16 currentsegment = 0; + + wkc = 0; + if(context->grouplist[group].hasdc) + { + first = TRUE; + } + length = context->grouplist[group].Obytes + context->grouplist[group].Ibytes; + LogAdr = context->grouplist[group].logstartaddr; + if (length) + { + if(!group) + { + context->idxstack->pushed = 0; + context->idxstack->pulled = 0; + } + wkc = 1; + /* LRW blocked by one or more slaves ? */ + if (context->grouplist[group].blockLRW) + { + /* if inputs available generate LRD */ + if(context->grouplist[group].Ibytes) + { + currentsegment = context->grouplist[group].Isegment; + data = context->grouplist[group].inputs; + length = context->grouplist[group].Ibytes; + LogAdr += context->grouplist[group].Obytes; + /* segment transfer if needed */ + do + { + if(currentsegment == context->grouplist[group].Isegment) + { + sublength = context->grouplist[group].IOsegment[currentsegment++] - context->grouplist[group].Ioffset; + } + else + { + sublength = context->grouplist[group].IOsegment[currentsegment++]; + } + /* get new index */ + idx = ecx_getindex(context->port); + w1 = LO_WORD(LogAdr); + w2 = HI_WORD(LogAdr); + ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LRD, idx, w1, w2, sublength, data); + if(first) + { + context->DCl = sublength; + /* FPRMW in second datagram */ + context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, + context->slavelist[context->grouplist[group].DCnext].configadr, + ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); + first = FALSE; + } + /* send frame */ + ecx_outframe_red(context->port, idx); + /* push index and data pointer on stack */ + ecx_pushindex(context, idx, data, sublength); + length -= sublength; + LogAdr += sublength; + data += sublength; + } while (length && (currentsegment < context->grouplist[group].nsegments)); + } + /* if outputs available generate LWR */ + if(context->grouplist[group].Obytes) + { + data = context->grouplist[group].outputs; + length = context->grouplist[group].Obytes; + LogAdr = context->grouplist[group].logstartaddr; + currentsegment = 0; + /* segment transfer if needed */ + do + { + sublength = context->grouplist[group].IOsegment[currentsegment++]; + if((length - sublength) < 0) + { + sublength = length; + } + /* get new index */ + idx = ecx_getindex(context->port); + w1 = LO_WORD(LogAdr); + w2 = HI_WORD(LogAdr); + ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LWR, idx, w1, w2, sublength, data); + if(first) + { + context->DCl = sublength; + /* FPRMW in second datagram */ + context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, + context->slavelist[context->grouplist[group].DCnext].configadr, + ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); + first = FALSE; + } + /* send frame */ + ecx_outframe_red(context->port, idx); + /* push index and data pointer on stack */ + ecx_pushindex(context, idx, data, sublength); + length -= sublength; + LogAdr += sublength; + data += sublength; + } while (length && (currentsegment < context->grouplist[group].nsegments)); + } + } + /* LRW can be used */ + else + { + if (context->grouplist[group].Obytes) + { + data = context->grouplist[group].outputs; + } + else + { + data = context->grouplist[group].inputs; + } + /* segment transfer if needed */ + do + { + sublength = context->grouplist[group].IOsegment[currentsegment++]; + /* get new index */ + idx = ecx_getindex(context->port); + w1 = LO_WORD(LogAdr); + w2 = HI_WORD(LogAdr); + ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LRW, idx, w1, w2, sublength, data); + if(first) + { + context->DCl = sublength; + /* FPRMW in second datagram */ + context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, + context->slavelist[context->grouplist[group].DCnext].configadr, + ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); + first = FALSE; + } + /* send frame */ + ecx_outframe_red(context->port, idx); + /* push index and data pointer on stack */ + ecx_pushindex(context, idx, data, sublength); + length -= sublength; + LogAdr += sublength; + data += sublength; + } while (length && (currentsegment < context->grouplist[group].nsegments)); + } + } + + return wkc; +} + +/** Receive processdata from slaves. + * Second part from ec_send_processdata(). + * Received datagrams are recombined with the processdata with help from the stack. + * If a datagram contains input processdata it copies it to the processdata structure. + * @param[in] context = context struct + * @param[in] group = group number + * @param[in] timeout = Timeout in us. + * @return Work counter. + */ +int ecx_receive_processdata_group(ecx_contextt *context, uint8 group, int timeout) +{ + int pos, idx; + int wkc = 0, wkc2; + uint16 le_wkc = 0; + int64 le_DCtime; + boolean first = FALSE; + + if(context->grouplist[group].hasdc) + { + first = TRUE; + } + /* get first index */ + pos = ecx_pullindex(context); + /* read the same number of frames as send */ + while (pos >= 0) + { + idx = context->idxstack->idx[pos]; + wkc2 = ecx_waitinframe(context->port, context->idxstack->idx[pos], timeout); + /* check if there is input data in frame */ + if (wkc2 > EC_NOFRAME) + { + if((context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRD) || (context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRW)) + { + if(first) + { + memcpy(context->idxstack->data[pos], &(context->port->rxbuf[idx][EC_HEADERSIZE]), context->DCl); + memcpy(&le_wkc, &(context->port->rxbuf[idx][EC_HEADERSIZE + context->DCl]), EC_WKCSIZE); + wkc = etohs(le_wkc); + memcpy(&le_DCtime, &(context->port->rxbuf[idx][context->DCtO]), sizeof(le_DCtime)); + *(context->DCtime) = etohll(le_DCtime); + first = FALSE; + } + else + { + /* copy input data back to process data buffer */ + memcpy(context->idxstack->data[pos], &(context->port->rxbuf[idx][EC_HEADERSIZE]), context->idxstack->length[pos]); + wkc += wkc2; + } + } + else if(context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LWR) + { + if(first) + { + memcpy(&le_wkc, &(context->port->rxbuf[idx][EC_HEADERSIZE + context->DCl]), EC_WKCSIZE); + /* output WKC counts 2 times when using LRW, emulate the same for LWR */ + wkc = etohs(le_wkc) * 2; + memcpy(&le_DCtime, &(context->port->rxbuf[idx][context->DCtO]), sizeof(le_DCtime)); + *(context->DCtime) = etohll(le_DCtime); + first = FALSE; + } + else + { + /* output WKC counts 2 times when using LRW, emulate the same for LWR */ + wkc += wkc2 * 2; + } + } + } + /* release buffer */ + ecx_setbufstat(context->port, idx, EC_BUF_EMPTY); + /* get next index */ + pos = ecx_pullindex(context); + } + + return wkc; +} + + +int ecx_send_processdata(ecx_contextt *context) +{ + return ecx_send_processdata_group(context, 0); +} + +int ecx_receive_processdata(ecx_contextt *context, int timeout) +{ + return ecx_receive_processdata_group(context, 0, timeout); +} + +#ifdef EC_VER1 +void ec_pusherror(const ec_errort *Ec) +{ + ecx_pusherror(&ecx_context, Ec); +} + +boolean ec_poperror(ec_errort *Ec) +{ + return ecx_poperror(&ecx_context, Ec); +} + +boolean ec_iserror(void) +{ + return ecx_iserror(&ecx_context); +} + +void ec_packeterror(uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode) +{ + ecx_packeterror(&ecx_context, Slave, Index, SubIdx, ErrorCode); +} + +int ec_init(char * ifname) +{ + return ecx_init(&ecx_context, ifname); +} + +int ec_init_redundant(char *ifname, char *if2name) +{ + return ecx_init_redundant (&ecx_context, &ecx_redport, ifname, if2name); +} + +void ec_close(void) +{ + ecx_close(&ecx_context); +}; + +uint8 ec_siigetbyte(uint16 slave, uint16 address) +{ + return ecx_siigetbyte (&ecx_context, slave, address); +} + +int16 ec_siifind(uint16 slave, uint16 cat) +{ + return ecx_siifind (&ecx_context, slave, cat); +} + +void ec_siistring(char *str, uint16 slave, uint16 Sn) +{ + ecx_siistring(&ecx_context, str, slave, Sn); +} + +uint16 ec_siiFMMU(uint16 slave, ec_eepromFMMUt* FMMU) +{ + return ecx_siiFMMU (&ecx_context, slave, FMMU); +} + +uint16 ec_siiSM(uint16 slave, ec_eepromSMt* SM) +{ + return ecx_siiSM (&ecx_context, slave, SM); +} + +uint16 ec_siiSMnext(uint16 slave, ec_eepromSMt* SM, uint16 n) +{ + return ecx_siiSMnext (&ecx_context, slave, SM, n); +} + +int ec_siiPDO(uint16 slave, ec_eepromPDOt* PDO, uint8 t) +{ + return ecx_siiPDO (&ecx_context, slave, PDO, t); +} + +int ec_readstate(void) +{ + return ecx_readstate (&ecx_context); +} + +int ec_writestate(uint16 slave) +{ + return ecx_writestate(&ecx_context, slave); +} + +uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout) +{ + return ecx_statecheck (&ecx_context, slave, reqstate, timeout); +} + +int ec_mbxempty(uint16 slave, int timeout) +{ + return ecx_mbxempty (&ecx_context, slave, timeout); +} + +int ec_mbxsend(uint16 slave,ec_mbxbuft *mbx, int timeout) +{ + return ecx_mbxsend (&ecx_context, slave, mbx, timeout); +} + +int ec_mbxreceive(uint16 slave, ec_mbxbuft *mbx, int timeout) +{ + return ecx_mbxreceive (&ecx_context, slave, mbx, timeout); +} + +void ec_esidump(uint16 slave, uint8 *esibuf) +{ + ecx_esidump (&ecx_context, slave, esibuf); +} + +uint32 ec_readeeprom(uint16 slave, uint16 eeproma, int timeout) +{ + return ecx_readeeprom (&ecx_context, slave, eeproma, timeout); +} + +int ec_writeeeprom(uint16 slave, uint16 eeproma, uint16 data, int timeout) +{ + return ecx_writeeeprom (&ecx_context, slave, eeproma, data, timeout); +} + +int ec_eeprom2master(uint16 slave) +{ + return ecx_eeprom2master(&ecx_context, slave); +} + +int ec_eeprom2pdi(uint16 slave) +{ + return ecx_eeprom2pdi(&ecx_context, slave); +} + +uint16 ec_eeprom_waitnotbusyAP(uint16 aiadr,uint16 *estat, int timeout) +{ + return ecx_eeprom_waitnotbusyAP (&ecx_context, aiadr, estat, timeout); +} + +uint64 ec_readeepromAP(uint16 aiadr, uint16 eeproma, int timeout) +{ + return ecx_readeepromAP (&ecx_context, aiadr, eeproma, timeout); +} + +int ec_writeeepromAP(uint16 aiadr, uint16 eeproma, uint16 data, int timeout) +{ + return ecx_writeeepromAP (&ecx_context, aiadr, eeproma, data, timeout); +} + +uint16 ec_eeprom_waitnotbusyFP(uint16 configadr,uint16 *estat, int timeout) +{ + return ecx_eeprom_waitnotbusyFP (&ecx_context, configadr, estat, timeout); +} + +uint64 ec_readeepromFP(uint16 configadr, uint16 eeproma, int timeout) +{ + return ecx_readeepromFP (&ecx_context, configadr, eeproma, timeout); +} + +int ec_writeeepromFP(uint16 configadr, uint16 eeproma, uint16 data, int timeout) +{ + return ecx_writeeepromFP (&ecx_context, configadr, eeproma, data, timeout); +} + +void ec_readeeprom1(uint16 slave, uint16 eeproma) +{ + ecx_readeeprom1 (&ecx_context, slave, eeproma); +} + +uint32 ec_readeeprom2(uint16 slave, int timeout) +{ + return ecx_readeeprom2 (&ecx_context, slave, timeout); +} + +int ec_send_processdata_group(uint8 group) +{ + return ecx_send_processdata_group (&ecx_context, group); +} + +int ec_receive_processdata_group(uint8 group, int timeout) +{ + return ecx_receive_processdata_group (&ecx_context, group, timeout); +} + +int ec_send_processdata(void) +{ + return ec_send_processdata_group(0); +} + +int ec_receive_processdata(int timeout) +{ + return ec_receive_processdata_group(0, timeout); +} +#endif \ No newline at end of file diff --git a/soem/ethercatmain.h b/soem/ethercatmain.h new file mode 100644 index 0000000..978c603 --- /dev/null +++ b/soem/ethercatmain.h @@ -0,0 +1,552 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatmain.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstrasse 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatmain.c + */ + +#ifndef _ethercatmain_ +#define _ethercatmain_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** max. etries in EtherCAT error list */ +#define EC_MAXELIST 64 +/** max. length of readable name in slavelist and Object Description List */ +#define EC_MAXNAME 40 +/** max. number of slaves in array */ +#define EC_MAXSLAVE 200 +/** max. number of groups */ +#define EC_MAXGROUP 2 +/** max. number of IO segments per group */ +#define EC_MAXIOSEGMENTS 64 +/** max. mailbox size */ +#define EC_MAXMBX 1486 +/** max. eeprom PDO entries */ +#define EC_MAXEEPDO 0x200 +/** max. SM used */ +#define EC_MAXSM 8 +/** max. FMMU used */ +#define EC_MAXFMMU 4 +/** max. Adapter */ +#define EC_MAXLEN_ADAPTERNAME 128 + +typedef struct ec_adapter ec_adaptert; +struct ec_adapter +{ + char name[EC_MAXLEN_ADAPTERNAME]; + char desc[EC_MAXLEN_ADAPTERNAME]; + ec_adaptert *next; +}; + +/** record for FMMU */ +PACKED_BEGIN +typedef struct PACKED +{ + uint32 LogStart; + uint16 LogLength; + uint8 LogStartbit; + uint8 LogEndbit; + uint16 PhysStart; + uint8 PhysStartBit; + uint8 FMMUtype; + uint8 FMMUactive; + uint8 unused1; + uint16 unused2; +} ec_fmmut; +PACKED_END + +/** record for sync manager */ +PACKED_BEGIN +typedef struct PACKED +{ + uint16 StartAddr; + uint16 SMlength; + uint32 SMflags; +} ec_smt; +PACKED_END + +PACKED_BEGIN +typedef struct PACKED +{ + uint16 State; + uint16 Unused; + uint16 ALstatuscode; +} ec_state_status; +PACKED_END + +#define ECT_MBXPROT_AOE 0x0001 +#define ECT_MBXPROT_EOE 0x0002 +#define ECT_MBXPROT_COE 0x0004 +#define ECT_MBXPROT_FOE 0x0008 +#define ECT_MBXPROT_SOE 0x0010 +#define ECT_MBXPROT_VOE 0x0020 + +#define ECT_COEDET_SDO 0x01 +#define ECT_COEDET_SDOINFO 0x02 +#define ECT_COEDET_PDOASSIGN 0x04 +#define ECT_COEDET_PDOCONFIG 0x08 +#define ECT_COEDET_UPLOAD 0x10 +#define ECT_COEDET_SDOCA 0x20 + +#define EC_SMENABLEMASK 0xfffeffff + +/** for list of ethercat slaves detected */ +typedef struct +{ + /** state of slave */ + uint16 state; + /** AL status code */ + uint16 ALstatuscode; + /** Configured address */ + uint16 configadr; + /** Alias address */ + uint16 aliasadr; + /** Manufacturer from EEprom */ + uint32 eep_man; + /** ID from EEprom */ + uint32 eep_id; + /** revision from EEprom */ + uint32 eep_rev; + /** Interface type */ + uint16 Itype; + /** Device type */ + uint16 Dtype; + /** output bits */ + uint16 Obits; + /** output bytes, if Obits < 8 then Obytes = 0 */ + uint32 Obytes; + /** output pointer in IOmap buffer */ + uint8 *outputs; + /** startbit in first output byte */ + uint8 Ostartbit; + /** input bits */ + uint16 Ibits; + /** input bytes, if Ibits < 8 then Ibytes = 0 */ + uint32 Ibytes; + /** input pointer in IOmap buffer */ + uint8 *inputs; + /** startbit in first input byte */ + uint8 Istartbit; + /** SM structure */ + ec_smt SM[EC_MAXSM]; + /** SM type 0=unused 1=MbxWr 2=MbxRd 3=Outputs 4=Inputs */ + uint8 SMtype[EC_MAXSM]; + /** FMMU structure */ + ec_fmmut FMMU[EC_MAXFMMU]; + /** FMMU0 function */ + uint8 FMMU0func; + /** FMMU1 function */ + uint8 FMMU1func; + /** FMMU2 function */ + uint8 FMMU2func; + /** FMMU3 function */ + uint8 FMMU3func; + /** length of write mailbox in bytes, if no mailbox then 0 */ + uint16 mbx_l; + /** mailbox write offset */ + uint16 mbx_wo; + /** length of read mailbox in bytes */ + uint16 mbx_rl; + /** mailbox read offset */ + uint16 mbx_ro; + /** mailbox supported protocols */ + uint16 mbx_proto; + /** Counter value of mailbox link layer protocol 1..7 */ + uint8 mbx_cnt; + /** has DC capabillity */ + boolean hasdc; + /** Physical type; Ebus, EtherNet combinations */ + uint8 ptype; + /** topology: 1 to 3 links */ + uint8 topology; + /** active ports bitmap : ....3210 , set if respective port is active **/ + uint8 activeports; + /** consumed ports bitmap : ....3210, used for internal delay measurement **/ + uint8 consumedports; + /** slave number for parent, 0=master */ + uint16 parent; + /** port number on parent this slave is connected to **/ + uint8 parentport; + /** port number on this slave the parent is connected to **/ + uint8 entryport; + /** DC receivetimes on port A */ + int32 DCrtA; + /** DC receivetimes on port B */ + int32 DCrtB; + /** DC receivetimes on port C */ + int32 DCrtC; + /** DC receivetimes on port D */ + int32 DCrtD; + /** propagation delay */ + int32 pdelay; + /** next DC slave */ + uint16 DCnext; + /** previous DC slave */ + uint16 DCprevious; + /** DC cyle time in ns */ + int32 DCcycle; + /** DC shift from clock modulus boundary */ + int32 DCshift; + /** DC sync activation, 0=off, 1=on */ + uint8 DCactive; + /** link to config table */ + uint16 configindex; + /** link to SII config */ + uint16 SIIindex; + /** 1 = 8 bytes per read, 0 = 4 bytes per read */ + uint8 eep_8byte; + /** 0 = eeprom to master , 1 = eeprom to PDI */ + uint8 eep_pdi; + /** CoE details */ + uint8 CoEdetails; + /** FoE details */ + uint8 FoEdetails; + /** EoE details */ + uint8 EoEdetails; + /** SoE details */ + uint8 SoEdetails; + /** E-bus current */ + int16 Ebuscurrent; + /** if >0 block use of LRW in processdata */ + uint8 blockLRW; + /** group */ + uint8 group; + /** first unused FMMU */ + uint8 FMMUunused; + /** TRUE is slave is not responding at all */ + boolean islost; + /** registered configuration function PO->SO */ + int (*PO2SOconfig)(uint16 slave); + /** readable name */ + char name[EC_MAXNAME + 1]; +} ec_slavet; + +/** for list of ethercat slave groups */ +typedef struct +{ + /** logical start address for this group */ + uint32 logstartaddr; + /** output bytes, if Obits < 8 then Obytes = 0 */ + uint32 Obytes; + /** output pointer in IOmap buffer */ + uint8 *outputs; + /** input bytes, if Ibits < 8 then Ibytes = 0 */ + uint32 Ibytes; + /** input pointer in IOmap buffer */ + uint8 *inputs; + /** has DC capabillity */ + boolean hasdc; + /** next DC slave */ + uint16 DCnext; + /** E-bus current */ + int16 Ebuscurrent; + /** if >0 block use of LRW in processdata */ + uint8 blockLRW; + /** IO segegments used */ + uint16 nsegments; + /** 1st input segment */ + uint16 Isegment; + /** Offset in input segment */ + uint16 Ioffset; + /** Expected workcounter outputs */ + uint16 outputsWKC; + /** Expected workcounter inputs */ + uint16 inputsWKC; + /** check slave states */ + boolean docheckstate; + /** IO segmentation list. Datagrams must not break SM in two. */ + uint32 IOsegment[EC_MAXIOSEGMENTS]; +} ec_groupt; + +/** SII FMMU structure */ +typedef struct +{ + uint16 Startpos; + uint8 nFMMU; + uint8 FMMU0; + uint8 FMMU1; + uint8 FMMU2; + uint8 FMMU3; +} ec_eepromFMMUt; + +/** SII SM structure */ +typedef struct +{ + uint16 Startpos; + uint8 nSM; + uint16 PhStart; + uint16 Plength; + uint8 Creg; + uint8 Sreg; /* dont care */ + uint8 Activate; + uint8 PDIctrl; /* dont care */ +} ec_eepromSMt; + +/** record to store rxPDO and txPDO table from eeprom */ +typedef struct +{ + uint16 Startpos; + uint16 Length; + uint16 nPDO; + uint16 Index[EC_MAXEEPDO]; + uint16 SyncM[EC_MAXEEPDO]; + uint16 BitSize[EC_MAXEEPDO]; + uint16 SMbitsize[EC_MAXSM]; +} ec_eepromPDOt; + +/** mailbox buffer array */ +typedef uint8 ec_mbxbuft[EC_MAXMBX + 1]; + +/** standard ethercat mailbox header */ +PACKED_BEGIN +typedef struct PACKED +{ + uint16 length; + uint16 address; + uint8 priority; + uint8 mbxtype; +} ec_mbxheadert; +PACKED_END + +/** ALstatus and ALstatus code */ +PACKED_BEGIN +typedef struct PACKED +{ + uint16 alstatus; + uint16 unused; + uint16 alstatuscode; +} ec_alstatust; +PACKED_END + +/** stack structure to store segmented LRD/LWR/LRW constructs */ +typedef struct +{ + uint8 pushed; + uint8 pulled; + uint8 idx[EC_MAXBUF]; + void *data[EC_MAXBUF]; + uint16 length[EC_MAXBUF]; +} ec_idxstackT; + +/** ringbuf for error storage */ +typedef struct +{ + int16 head; + int16 tail; + ec_errort Error[EC_MAXELIST + 1]; +} ec_eringt; + +/** SyncManager Communication Type structure for CA */ +PACKED_BEGIN +typedef struct PACKED +{ + uint8 n; + uint8 nu1; + uint8 SMtype[EC_MAXSM]; +} ec_SMcommtypet; +PACKED_END + +/** SDO assign structure for CA */ +PACKED_BEGIN +typedef struct PACKED +{ + uint8 n; + uint8 nu1; + uint16 index[256]; +} ec_PDOassignt; +PACKED_END + +/** SDO description structure for CA */ +PACKED_BEGIN +typedef struct PACKED +{ + uint8 n; + uint8 nu1; + uint32 PDO[256]; +} ec_PDOdesct; +PACKED_END + +/** Context structure , referenced by all ecx functions*/ +typedef struct +{ + /** port reference, may include red_port */ + ecx_portt *port; + /** slavelist reference */ + ec_slavet *slavelist; + /** number of slaves found in configuration */ + int *slavecount; + /** maximum number of slaves allowed in slavelist */ + int maxslave; + /** grouplist reference */ + ec_groupt *grouplist; + /** maximum number of groups allowed in grouplist */ + int maxgroup; + /** internal, reference to eeprom cache buffer */ + uint8 *esibuf; + /** internal, reference to eeprom cache map */ + uint32 *esimap; + /** internal, current slave for eeprom cache */ + uint16 esislave; + /** internal, reference to error list */ + ec_eringt *elist; + /** internal, reference to processdata stack buffer info */ + ec_idxstackT *idxstack; + /** reference to ecaterror state */ + boolean *ecaterror; + /** internal, position of DC datagram in process data packet */ + uint16 DCtO; + /** internal, length of DC datagram */ + uint16 DCl; + /** reference to last DC time from slaves */ + int64 *DCtime; + /** internal, SM buffer */ + ec_SMcommtypet *SMcommtype; + /** internal, PDO assign list */ + ec_PDOassignt *PDOassign; + /** internal, PDO description list */ + ec_PDOdesct *PDOdesc; + /** internal, SM list from eeprom */ + ec_eepromSMt *eepSM; + /** internal, FMMU list from eeprom */ + ec_eepromFMMUt *eepFMMU; + /** registered FoE hook */ + int (*FOEhook)(uint16 slave, int packetnumber, int datasize); +} ecx_contextt; + +#ifdef EC_VER1 +/** global struct to hold default master context */ +extern ecx_contextt ecx_context; +/** main slave data structure array */ +extern ec_slavet ec_slave[EC_MAXSLAVE]; +/** number of slaves found by configuration function */ +extern int ec_slavecount; +/** slave group structure */ +extern ec_groupt ec_group[EC_MAXGROUP]; +extern boolean EcatError; +extern int64 ec_DCtime; + +void ec_pusherror(const ec_errort *Ec); +boolean ec_poperror(ec_errort *Ec); +boolean ec_iserror(void); +void ec_packeterror(uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode); +int ec_init(char * ifname); +int ec_init_redundant(char *ifname, char *if2name); +void ec_close(void); +uint8 ec_siigetbyte(uint16 slave, uint16 address); +int16 ec_siifind(uint16 slave, uint16 cat); +void ec_siistring(char *str, uint16 slave, uint16 Sn); +uint16 ec_siiFMMU(uint16 slave, ec_eepromFMMUt* FMMU); +uint16 ec_siiSM(uint16 slave, ec_eepromSMt* SM); +uint16 ec_siiSMnext(uint16 slave, ec_eepromSMt* SM, uint16 n); +int ec_siiPDO(uint16 slave, ec_eepromPDOt* PDO, uint8 t); +int ec_readstate(void); +int ec_writestate(uint16 slave); +uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout); +int ec_mbxempty(uint16 slave, int timeout); +int ec_mbxsend(uint16 slave,ec_mbxbuft *mbx, int timeout); +int ec_mbxreceive(uint16 slave, ec_mbxbuft *mbx, int timeout); +void ec_esidump(uint16 slave, uint8 *esibuf); +uint32 ec_readeeprom(uint16 slave, uint16 eeproma, int timeout); +int ec_writeeeprom(uint16 slave, uint16 eeproma, uint16 data, int timeout); +int ec_eeprom2master(uint16 slave); +int ec_eeprom2pdi(uint16 slave); +uint64 ec_readeepromAP(uint16 aiadr, uint16 eeproma, int timeout); +int ec_writeeepromAP(uint16 aiadr, uint16 eeproma, uint16 data, int timeout); +uint64 ec_readeepromFP(uint16 configadr, uint16 eeproma, int timeout); +int ec_writeeepromFP(uint16 configadr, uint16 eeproma, uint16 data, int timeout); +void ec_readeeprom1(uint16 slave, uint16 eeproma); +uint32 ec_readeeprom2(uint16 slave, int timeout); +int ec_send_processdata_group(uint8 group); +int ec_receive_processdata_group(uint8 group, int timeout); +int ec_send_processdata(void); +int ec_receive_processdata(int timeout); +#endif + +ec_adaptert * ec_find_adapters(void); +void ec_free_adapters(ec_adaptert * adapter); +uint8 ec_nextmbxcnt(uint8 cnt); +void ec_clearmbx(ec_mbxbuft *Mbx); +void ecx_pusherror(ecx_contextt *context, const ec_errort *Ec); +boolean ecx_poperror(ecx_contextt *context, ec_errort *Ec); +boolean ecx_iserror(ecx_contextt *context); +void ecx_packeterror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode); +int ecx_init(ecx_contextt *context, char * ifname); +int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, char *ifname, char *if2name); +void ecx_close(ecx_contextt *context); +uint8 ecx_siigetbyte(ecx_contextt *context, uint16 slave, uint16 address); +int16 ecx_siifind(ecx_contextt *context, uint16 slave, uint16 cat); +void ecx_siistring(ecx_contextt *context, char *str, uint16 slave, uint16 Sn); +uint16 ecx_siiFMMU(ecx_contextt *context, uint16 slave, ec_eepromFMMUt* FMMU); +uint16 ecx_siiSM(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM); +uint16 ecx_siiSMnext(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM, uint16 n); +int ecx_siiPDO(ecx_contextt *context, uint16 slave, ec_eepromPDOt* PDO, uint8 t); +int ecx_readstate(ecx_contextt *context); +int ecx_writestate(ecx_contextt *context, uint16 slave); +uint16 ecx_statecheck(ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout); +int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout); +int ecx_mbxsend(ecx_contextt *context, uint16 slave,ec_mbxbuft *mbx, int timeout); +int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout); +void ecx_esidump(ecx_contextt *context, uint16 slave, uint8 *esibuf); +uint32 ecx_readeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout); +int ecx_writeeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout); +int ecx_eeprom2master(ecx_contextt *context, uint16 slave); +int ecx_eeprom2pdi(ecx_contextt *context, uint16 slave); +uint64 ecx_readeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout); +int ecx_writeeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout); +uint64 ecx_readeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout); +int ecx_writeeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout); +void ecx_readeeprom1(ecx_contextt *context, uint16 slave, uint16 eeproma); +uint32 ecx_readeeprom2(ecx_contextt *context, uint16 slave, int timeout); +int ecx_send_processdata_group(ecx_contextt *context, uint8 group); +int ecx_receive_processdata_group(ecx_contextt *context, uint8 group, int timeout); +int ecx_send_processdata(ecx_contextt *context); +int ecx_receive_processdata(ecx_contextt *context, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatprint.c b/soem/ethercatprint.c new file mode 100644 index 0000000..8b84678 --- /dev/null +++ b/soem/ethercatprint.c @@ -0,0 +1,399 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatprint.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Module to convert EtherCAT errors to readable messages. + * + * SDO abort messages and AL status codes are used to relay slave errors to + * the user application. This module converts the binary codes to readble text. + * For the defined error codes see the EtherCAT protocol documentation. + */ + +#include +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatmain.h" + +#define EC_MAXERRORNAME 127 + +/** SDO error list type definition */ +typedef struct +{ + /** Error code returned from SDO */ + uint32 errorcode; + /** Readable error description */ + char errordescription[EC_MAXERRORNAME + 1]; +} ec_sdoerrorlist_t; + +/** AL status code list type definition */ +typedef struct +{ + /** AL status code */ + uint16 ALstatuscode; + /** Readable description */ + char ALstatuscodedescription[EC_MAXERRORNAME + 1]; +} ec_ALstatuscodelist_t; + +/** SoE error list type definition */ +typedef struct +{ + /** SoE error code */ + uint16 errorcode; + /** Readable description */ + char errordescription[EC_MAXERRORNAME + 1]; +} ec_soeerrorlist_t; + +/** MBX error list type definition */ +typedef struct +{ + /** MBX error code */ + uint16 errorcode; + /** Readable description */ + char errordescription[EC_MAXERRORNAME + 1]; +} ec_mbxerrorlist_t; + +char estring[EC_MAXERRORNAME]; + +/** SDO error list definition */ +const ec_sdoerrorlist_t ec_sdoerrorlist[] = { + {0x00000000, "No error" }, + {0x05030000, "Toggle bit not changed" }, + {0x05040000, "SDO protocol timeout" }, + {0x05040001, "Client/Server command specifier not valid or unknown" }, + {0x05040005, "Out of memory" }, + {0x06010000, "Unsupported access to an object" }, + {0x06010001, "Attempt to read to a write only object" }, + {0x06010002, "Attempt to write to a read only object" }, + {0x06010003, "Subindex can not be written, SI0 must be 0 for write access" }, + {0x06010004, "SDO Complete access not supported for variable length objects" }, + {0x06010005, "Object length exceeds mailbox size" }, + {0x06010006, "Object mapped to RxPDO, SDO download blocked" }, + {0x06020000, "The object does not exist in the object directory" }, + {0x06040041, "The object can not be mapped into the PDO" }, + {0x06040042, "The number and length of the objects to be mapped would exceed the PDO length" }, + {0x06040043, "General parameter incompatibility reason" }, + {0x06040047, "General internal incompatibility in the device" }, + {0x06060000, "Access failed due to a hardware error" }, + {0x06070010, "Data type does not match, length of service parameter does not match" }, + {0x06070012, "Data type does not match, length of service parameter too high" }, + {0x06070013, "Data type does not match, length of service parameter too low" }, + {0x06090011, "Subindex does not exist" }, + {0x06090030, "Value range of parameter exceeded (only for write access)" }, + {0x06090031, "Value of parameter written too high" }, + {0x06090032, "Value of parameter written too low" }, + {0x06090036, "Maximum value is less than minimum value" }, + {0x08000000, "General error" }, + {0x08000020, "Data cannot be transferred or stored to the application" }, + {0x08000021, "Data cannot be transferred or stored to the application because of local control" }, + {0x08000022, "Data cannot be transferred or stored to the application because of the present device state" }, + {0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present" }, + {0xffffffff, "Unknown" } +}; + +/** AL status code list definition */ +const ec_ALstatuscodelist_t ec_ALstatuscodelist[] = { + {0x0000 , "No error" }, + {0x0001 , "Unspecified error" }, + {0x0002 , "No memory" }, + {0x0011 , "Invalid requested state change" }, + {0x0012 , "Unknown requested state" }, + {0x0013 , "Bootstrap not supported" }, + {0x0014 , "No valid firmware" }, + {0x0015 , "Invalid mailbox configuration" }, + {0x0016 , "Invalid mailbox configuration" }, + {0x0017 , "Invalid sync manager configuration" }, + {0x0018 , "No valid inputs available" }, + {0x0019 , "No valid outputs" }, + {0x001A , "Synchronization error" }, + {0x001B , "Sync manager watchdog" }, + {0x001C , "Invalid sync Manager types" }, + {0x001D , "Invalid output configuration" }, + {0x001E , "Invalid input configuration" }, + {0x001F , "Invalid watchdog configuration" }, + {0x0020 , "Slave needs cold start" }, + {0x0021 , "Slave needs INIT" }, + {0x0022 , "Slave needs PREOP" }, + {0x0023 , "Slave needs SAFEOP" }, + {0x0024 , "Invalid input mapping" }, + {0x0025 , "Invalid output mapping" }, + {0x0026 , "Inconsistent settings" }, + {0x0027 , "Freerun not supported" }, + {0x0028 , "Synchronisation not supported" }, + {0x0029 , "Freerun needs 3buffer mode" }, + {0x002A , "Background watchdog" }, + {0x002B , "No valid Inputs and Outputs" }, + {0x002C , "Fatal sync error" }, + {0x002D , "No sync error" }, // was "Invalid Output FMMU Configuration" + {0x002E , "Invalid input FMMU configuration" }, + {0x0030 , "Invalid DC SYNC configuration" }, + {0x0031 , "Invalid DC latch configuration" }, + {0x0032 , "PLL error" }, + {0x0033 , "DC sync IO error" }, + {0x0034 , "DC sync timeout error" }, + {0x0035 , "DC invalid sync cycle time" }, + {0x0035 , "DC invalid sync0 cycle time" }, + {0x0035 , "DC invalid sync1 cycle time" }, + {0x0042 , "MBX_EOE" }, + {0x0043 , "MBX_COE" }, + {0x0044 , "MBX_FOE" }, + {0x0045 , "MBX_SOE" }, + {0x004F , "MBX_VOE" }, + {0x0050 , "EEPROM no access" }, + {0x0051 , "EEPROM error" }, + {0x0060 , "Slave restarted locally" }, + {0x0061 , "Device identification value updated" }, + {0x00f0 , "Application controller available" }, + {0xffff , "Unknown" } +}; + +/** SoE error list definition */ +const ec_soeerrorlist_t ec_soeerrorlist[] = { + {0x0000, "No error" }, + {0x1001, "No IDN" }, + {0x1009, "Invalid access to element 1" }, + {0x2001, "No Name" }, + {0x2002, "Name transmission too short" }, + {0x2003, "Name transmission too long" }, + {0x2004, "Name cannot be changed (read only)" }, + {0x2005, "Name is write-protected at this time" }, + {0x3002, "Attribute transmission too short" }, + {0x3003, "Attribute transmission too long" }, + {0x3004, "Attribute cannot be changed (read only)" }, + {0x3005, "Attribute is write-protected at this time" }, + {0x4001, "No units" }, + {0x4002, "Unit transmission too short" }, + {0x4003, "Unit transmission too long" }, + {0x4004, "Unit cannot be changed (read only)" }, + {0x4005, "Unit is write-protected at this time" }, + {0x5001, "No minimum input value" }, + {0x5002, "Minimum input value transmission too short" }, + {0x5003, "Minimum input value transmission too long" }, + {0x5004, "Minimum input value cannot be changed (read only)" }, + {0x5005, "Minimum input value is write-protected at this time" }, + {0x6001, "No maximum input value" }, + {0x6002, "Maximum input value transmission too short" }, + {0x6003, "Maximum input value transmission too long" }, + {0x6004, "Maximum input value cannot be changed (read only)" }, + {0x6005, "Maximum input value is write-protected at this time" }, + {0x7002, "Operation data transmission too short" }, + {0x7003, "Operation data transmission too long" }, + {0x7004, "Operation data cannot be changed (read only)" }, + {0x7005, "Operation data is write-protected at this time (state)" }, + {0x7006, "Operation data is smaller than the minimum input value" }, + {0x7007, "Operation data is smaller than the maximum input value" }, + {0x7008, "Invalid operation data:Configured IDN will not be supported" }, + {0x7009, "Operation data write protected by a password" }, + {0x700A, "Operation data is write protected, it is configured cyclically" }, + {0x700B, "Invalid indirect addressing: (e.g., data container, list handling)" }, + {0x700C, "Operation data is write protected, due to other settings" }, + {0x700D, "Reserved" }, + {0x7010, "Procedure command already active" }, + {0x7011, "Procedure command not interruptible" }, + {0x7012, "Procedure command at this time not executable (state)" }, + {0x7013, "Procedure command not executable (invalid or false parameters)" }, + {0x7014, "No data state" }, + {0x8001, "No default value" }, + {0x8002, "Default value transmission too long" }, + {0x8004, "Default value cannot be changed, read only" }, + {0x800A, "Invalid drive number" }, + {0x800A, "General error" }, + {0x800A, "No element addressed" }, + {0xffff, "Unknown" } +}; + +/** MBX error list definition */ +const ec_mbxerrorlist_t ec_mbxerrorlist[] = { + {0x0000, "No error" }, + {0x0001, "Syntax of 6 octet Mailbox Header is wrong" }, + {0x0002, "The mailbox protocol is not supported" }, + {0x0003, "Channel Field contains wrong value"}, + {0x0004, "The service is no supported"}, + {0x0005, "Invalid mailbox header"}, + {0x0006, "Length of received mailbox data is too short"}, + {0x0007, "No more memory in slave"}, + {0x0008, "The lenght of data is inconsistent"}, + {0xffff, "Unknown"} +}; + +/** Look up text string that belongs to SDO error code. + * + * @param[in] sdoerrorcode = SDO error code as defined in EtherCAT protocol + * @return readable string + */ +const char* ec_sdoerror2string( uint32 sdoerrorcode) +{ + int i = 0; + + while ( (ec_sdoerrorlist[i].errorcode != 0xffffffffUL) && + (ec_sdoerrorlist[i].errorcode != sdoerrorcode) ) + { + i++; + } + + return ec_sdoerrorlist[i].errordescription; +} + +/** Look up text string that belongs to AL status code. + * + * @param[in] ALstatuscode = AL status code as defined in EtherCAT protocol + * @return readable string + */ +char* ec_ALstatuscode2string( uint16 ALstatuscode) +{ + int i = 0; + + while ( (ec_ALstatuscodelist[i].ALstatuscode != 0xffff) && + (ec_ALstatuscodelist[i].ALstatuscode != ALstatuscode) ) + { + i++; + } + + return (char *) ec_ALstatuscodelist[i].ALstatuscodedescription; +} + +/** Look up text string that belongs to SoE error code. + * + * @param[in] errorcode = SoE error code as defined in EtherCAT protocol + * @return readable string + */ +char* ec_soeerror2string( uint16 errorcode) +{ + int i = 0; + + while ( (ec_soeerrorlist[i].errorcode != 0xffff) && + (ec_soeerrorlist[i].errorcode != errorcode) ) + { + i++; + } + + return (char *) ec_soeerrorlist[i].errordescription; +} + +/** Look up text string that belongs to MBX error code. + * + * @param[in] errorcode = MBX error code as defined in EtherCAT protocol + * @return readable string + */ +char* ec_mbxerror2string( uint16 errorcode) +{ + int i = 0; + + while ( (ec_mbxerrorlist[i].errorcode != 0xffff) && + (ec_mbxerrorlist[i].errorcode != errorcode) ) + { + i++; + } + + return (char *) ec_mbxerrorlist[i].errordescription; +} + +/** Look up error in ec_errorlist and convert to text string. + * + * @param[in] context = context struct + * @return readable string + */ +char* ecx_elist2string(ecx_contextt *context) +{ + ec_errort Ec; + char timestr[20]; + + if (ecx_poperror(context, &Ec)) + { + sprintf(timestr, "Time:%12.3f", Ec.Time.sec + (Ec.Time.usec / 1000000.0) ); + switch (Ec.Etype) + { + case EC_ERR_TYPE_SDO_ERROR: + { + sprintf(estring, "%s SDO slave:%d index:%4.4x.%2.2x error:%8.8x %s\n", + timestr, Ec.Slave, Ec.Index, Ec.SubIdx, (unsigned)Ec.AbortCode, ec_sdoerror2string(Ec.AbortCode)); + break; + } + case EC_ERR_TYPE_EMERGENCY: + { + sprintf(estring, "%s EMERGENCY slave:%d error:%4.4x\n", + timestr, Ec.Slave, Ec.ErrorCode); + break; + } + case EC_ERR_TYPE_PACKET_ERROR: + { + sprintf(estring, "%s PACKET slave:%d index:%4.4x.%2.2x error:%d\n", + timestr, Ec.Slave, Ec.Index, Ec.SubIdx, Ec.ErrorCode); + break; + } + case EC_ERR_TYPE_SDOINFO_ERROR: + { + sprintf(estring, "%s SDO slave:%d index:%4.4x.%2.2x error:%8.8x %s\n", + timestr, Ec.Slave, Ec.Index, Ec.SubIdx, (unsigned)Ec.AbortCode, ec_sdoerror2string(Ec.AbortCode)); + break; + } + case EC_ERR_TYPE_SOE_ERROR: + { + sprintf(estring, "%s SoE slave:%d IDN:%4.4x error:%4.4x %s\n", + timestr, Ec.Slave, Ec.Index, (unsigned)Ec.AbortCode, ec_soeerror2string(Ec.ErrorCode)); + break; + } + case EC_ERR_TYPE_MBX_ERROR: + { + sprintf(estring, "%s MBX slave:%d error:%4.4x %s\n", + timestr, Ec.Slave, Ec.ErrorCode, ec_mbxerror2string(Ec.ErrorCode)); + break; + } + default: + { + sprintf(estring, "%s error:%8.8x\n", + timestr, (unsigned)Ec.AbortCode); + break; + } + } + return (char*) estring; + } + else + { + return ""; + } +} + +#ifdef EC_VER1 +char* ec_elist2string(void) +{ + return ecx_elist2string(&ecx_context); +} +#endif diff --git a/soem/ethercatprint.h b/soem/ethercatprint.h new file mode 100644 index 0000000..a5ccfa1 --- /dev/null +++ b/soem/ethercatprint.h @@ -0,0 +1,67 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatprint.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatprint.c + */ + +#ifndef _ethercatprint_ +#define _ethercatprint_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +char* ec_sdoerror2string( uint16 sdoerrorcode); +char* ec_ALstatuscode2string( uint16 ALstatuscode); +char* ec_soeerror2string( uint16 errorcode); +char* ecx_elist2string(ecx_contextt *context); + +#ifdef EC_VER1 +char* ec_elist2string(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soem/ethercatsoe.c b/soem/ethercatsoe.c new file mode 100644 index 0000000..23826e7 --- /dev/null +++ b/soem/ethercatsoe.c @@ -0,0 +1,425 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatsoe.c + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * Thanks to Hidde Verstoep for testing and improving the SoE module + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Servo over EtherCAT (SoE) Module. + */ + +#include +#include +#include "osal.h" +#include "oshw.h" +#include "ethercattype.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatsoe.h" + +#define EC_SOE_MAX_DRIVES 8 + +/** SoE (Servo over EtherCAT) mailbox structure */ +PACKED_BEGIN +typedef struct PACKED +{ + ec_mbxheadert MbxHeader; + uint8 opCode :3; + uint8 incomplete :1; + uint8 error :1; + uint8 driveNo :3; + uint8 elementflags; + union + { + uint16 idn; + uint16 fragmentsleft; + }; +} ec_SoEt; +PACKED_END + +/** Report SoE error. + * + * @param[in] context = context struct + * @param[in] Slave = Slave number + * @param[in] idn = IDN that generated error + * @param[in] Error = Error code, see EtherCAT documentation for list + */ +void ecx_SoEerror(ecx_contextt *context, uint16 Slave, uint16 idn, uint16 Error) +{ + ec_errort Ec; + + memset(&Ec, 0, sizeof(Ec)); + Ec.Time = osal_current_time(); + Ec.Slave = Slave; + Ec.Index = idn; + Ec.SubIdx = 0; + *(context->ecaterror) = TRUE; + Ec.Etype = EC_ERR_TYPE_SOE_ERROR; + Ec.ErrorCode = Error; + ecx_pusherror(context, &Ec); +} + +/** SoE read, blocking. + * + * The IDN object of the selected slave and DriveNo is read. If a response + * is larger than the mailbox size then the response is segmented. The function + * will combine all segments and copy them to the parameter buffer. + * + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] driveNo = Drive number in slave + * @param[in] elementflags = Flags to select what properties of IDN are to be transfered. + * @param[in] idn = IDN. + * @param[in,out] psize = Size in bytes of parameter buffer, returns bytes read from SoE. + * @param[out] p = Pointer to parameter buffer + * @param[in] timeout = Timeout in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout) +{ + ec_SoEt *SoEp, *aSoEp; + uint16 totalsize, framedatasize; + int wkc; + uint8 *bp; + uint8 *mp; + uint16 *errorcode; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + boolean NotLast; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timeout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aSoEp = (ec_SoEt *)&MbxIn; + SoEp = (ec_SoEt *)&MbxOut; + SoEp->MbxHeader.length = htoes(sizeof(ec_SoEt) - sizeof(ec_mbxheadert)); + SoEp->MbxHeader.address = htoes(0x0000); + SoEp->MbxHeader.priority = 0x00; + /* get new mailbox count value, used as session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + SoEp->MbxHeader.mbxtype = ECT_MBXT_SOE + (cnt << 4); /* SoE */ + SoEp->opCode = ECT_SOE_READREQ; + SoEp->incomplete = 0; + SoEp->error = 0; + SoEp->driveNo = driveNo; + SoEp->elementflags = elementflags; + SoEp->idn = htoes(idn); + totalsize = 0; + bp = p; + mp = (uint8 *)&MbxIn + sizeof(ec_SoEt); + NotLast = TRUE; + /* send SoE request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) /* succeeded to place mailbox in slave ? */ + { + while (NotLast) + { + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + /* slave response should be SoE, ReadRes */ + if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) && + (aSoEp->opCode == ECT_SOE_READRES) && + (aSoEp->error == 0) && + (aSoEp->driveNo == driveNo) && + (aSoEp->elementflags == elementflags)) + { + framedatasize = etohs(aSoEp->MbxHeader.length) - sizeof(ec_SoEt) + sizeof(ec_mbxheadert); + totalsize += framedatasize; + /* Does parameter fit in parameter buffer ? */ + if (totalsize <= *psize) + { + /* copy parameter data in parameter buffer */ + memcpy(bp, mp, framedatasize); + /* increment buffer pointer */ + bp += framedatasize; + } + else + { + framedatasize -= totalsize - *psize; + totalsize = *psize; + /* copy parameter data in parameter buffer */ + if (framedatasize > 0) memcpy(bp, mp, framedatasize); + } + + if (!aSoEp->incomplete) + { + NotLast = FALSE; + *psize = totalsize; + } + } + /* other slave response */ + else + { + NotLast = FALSE; + if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) && + (aSoEp->opCode == ECT_SOE_READRES) && + (aSoEp->error == 1)) + { + mp = (uint8 *)&MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16)); + errorcode = (uint16 *)mp; + ecx_SoEerror(context, slave, idn, *errorcode); + } + else + { + ecx_packeterror(context, slave, idn, 0, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + else + { + NotLast = FALSE; + ecx_packeterror(context, slave, idn, 0, 4); /* no response */ + } + } + } + return wkc; +} + +/** SoE write, blocking. + * + * The IDN object of the selected slave and DriveNo is written. If a response + * is larger than the mailbox size then the response is segmented. + * + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[in] driveNo = Drive number in slave + * @param[in] elementflags = Flags to select what properties of IDN are to be transfered. + * @param[in] idn = IDN. + * @param[in] psize = Size in bytes of parameter buffer. + * @param[out] p = Pointer to parameter buffer + * @param[in] timeout = Timeout in us, standard is EC_TIMEOUTRXM + * @return Workcounter from last slave response + */ +int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout) +{ + ec_SoEt *SoEp, *aSoEp; + uint16 framedatasize, maxdata; + int wkc; + uint8 *mp; + uint8 *hp; + uint16 *errorcode; + ec_mbxbuft MbxIn, MbxOut; + uint8 cnt; + boolean NotLast; + + ec_clearmbx(&MbxIn); + /* Empty slave out mailbox if something is in. Timeout set to 0 */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0); + ec_clearmbx(&MbxOut); + aSoEp = (ec_SoEt *)&MbxIn; + SoEp = (ec_SoEt *)&MbxOut; + SoEp->MbxHeader.address = htoes(0x0000); + SoEp->MbxHeader.priority = 0x00; + SoEp->opCode = ECT_SOE_WRITEREQ; + SoEp->error = 0; + SoEp->driveNo = driveNo; + SoEp->elementflags = elementflags; + hp = p; + mp = (uint8 *)&MbxOut + sizeof(ec_SoEt); + maxdata = context->slavelist[slave].mbx_l - sizeof(ec_SoEt); + NotLast = TRUE; + while (NotLast) + { + framedatasize = psize; + NotLast = FALSE; + SoEp->idn = htoes(idn); + SoEp->incomplete = 0; + if (framedatasize > maxdata) + { + framedatasize = maxdata; /* segmented transfer needed */ + NotLast = TRUE; + SoEp->incomplete = 1; + SoEp->fragmentsleft = psize / maxdata; + } + SoEp->MbxHeader.length = htoes(sizeof(ec_SoEt) - sizeof(ec_mbxheadert) + framedatasize); + /* get new mailbox counter, used for session handle */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + SoEp->MbxHeader.mbxtype = ECT_MBXT_SOE + (cnt << 4); /* SoE */ + /* copy parameter data to mailbox */ + memcpy(mp, hp, framedatasize); + hp += framedatasize; + psize -= framedatasize; + /* send SoE request to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc > 0) /* succeeded to place mailbox in slave ? */ + { + if (!NotLast || !ecx_mbxempty(context, slave, timeout)) + { + /* clean mailboxbuffer */ + ec_clearmbx(&MbxIn); + /* read slave response */ + wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout); + if (wkc > 0) /* succeeded to read slave response ? */ + { + NotLast = FALSE; + /* slave response should be SoE, WriteRes */ + if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) && + (aSoEp->opCode == ECT_SOE_WRITERES) && + (aSoEp->error == 0) && + (aSoEp->driveNo == driveNo) && + (aSoEp->elementflags == elementflags)) + { + /* SoE write succeeded */ + } + /* other slave response */ + else + { + if (((aSoEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_SOE) && + (aSoEp->opCode == ECT_SOE_READRES) && + (aSoEp->error == 1)) + { + mp = (uint8 *)&MbxIn + (etohs(aSoEp->MbxHeader.length) + sizeof(ec_mbxheadert) - sizeof(uint16)); + errorcode = (uint16 *)mp; + ecx_SoEerror(context, slave, idn, *errorcode); + } + else + { + ecx_packeterror(context, slave, idn, 0, 1); /* Unexpected frame returned */ + } + wkc = 0; + } + } + else + { + ecx_packeterror(context, slave, idn, 0, 4); /* no response */ + } + } + } + } + return wkc; +} + +/** SoE read AT and MTD mapping. + * + * SoE has standard indexes defined for mapping. This function + * tries to read them and collect a full input and output mapping size + * of designated slave. + * + * @param[in] context = context struct + * @param[in] slave = Slave number + * @param[out] Osize = Size in bits of output mapping (MTD) found + * @param[out] Isize = Size in bits of input mapping (AT) found + * @return >0 if mapping succesful. + */ +int ecx_readIDNmap(ecx_contextt *context, uint16 slave, int *Osize, int *Isize) +{ + int retVal = 0; + int wkc; + int psize; + int driveNr; + uint16 entries, itemcount; + ec_SoEmappingt SoEmapping; + ec_SoEattributet SoEattribute; + + *Isize = 0; + *Osize = 0; + for(driveNr = 0; driveNr < EC_SOE_MAX_DRIVES; driveNr++) + { + psize = sizeof(SoEmapping); + /* read output mapping via SoE */ + wkc = ecx_SoEread(context, slave, driveNr, EC_SOE_VALUE_B, EC_IDN_MDTCONFIG, &psize, &SoEmapping, EC_TIMEOUTRXM); + if ((wkc > 0) && (psize >= 4) && ((entries = etohs(SoEmapping.currentlength) / 2) > 0) && (entries <= EC_SOE_MAXMAPPING)) + { + /* command word (uint16) is always mapped but not in list */ + *Osize = 16; + for (itemcount = 0 ; itemcount < entries ; itemcount++) + { + psize = sizeof(SoEattribute); + /* read attribute of each IDN in mapping list */ + wkc = ecx_SoEread(context, slave, driveNr, EC_SOE_ATTRIBUTE_B, SoEmapping.idn[itemcount], &psize, &SoEattribute, EC_TIMEOUTRXM); + if ((wkc > 0) && (!SoEattribute.list)) + { + /* length : 0 = 8bit, 1 = 16bit .... */ + *Osize += (int)8 << SoEattribute.length; + } + } + } + psize = sizeof(SoEmapping); + /* read input mapping via SoE */ + wkc = ecx_SoEread(context, slave, driveNr, EC_SOE_VALUE_B, EC_IDN_ATCONFIG, &psize, &SoEmapping, EC_TIMEOUTRXM); + if ((wkc > 0) && (psize >= 4) && ((entries = etohs(SoEmapping.currentlength) / 2) > 0) && (entries <= EC_SOE_MAXMAPPING)) + { + /* status word (uint16) is always mapped but not in list */ + *Isize = 16; + for (itemcount = 0 ; itemcount < entries ; itemcount++) + { + psize = sizeof(SoEattribute); + /* read attribute of each IDN in mapping list */ + wkc = ecx_SoEread(context, slave, driveNr, EC_SOE_ATTRIBUTE_B, SoEmapping.idn[itemcount], &psize, &SoEattribute, EC_TIMEOUTRXM); + if ((wkc > 0) && (!SoEattribute.list)) + { + /* length : 0 = 8bit, 1 = 16bit .... */ + *Isize += (int)8 << SoEattribute.length; + } + } + } + } + + /* found some I/O bits ? */ + if ((*Isize > 0) || (*Osize > 0)) + { + retVal = 1; + } + return retVal; +} + +#ifdef EC_VER1 +int ec_SoEread(uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout) +{ + return ecx_SoEread(&ecx_context, slave, driveNo, elementflags, idn, psize, p, timeout); +} + +int ec_SoEwrite(uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout) +{ + return ecx_SoEwrite(&ecx_context, slave, driveNo, elementflags, idn, psize, p, timeout); +} + +int ec_readIDNmap(uint16 slave, int *Osize, int *Isize) +{ + return ecx_readIDNmap(&ecx_context, slave, Osize, Isize); +} +#endif diff --git a/soem/ethercatsoe.h b/soem/ethercatsoe.h new file mode 100644 index 0000000..70d46d4 --- /dev/null +++ b/soem/ethercatsoe.h @@ -0,0 +1,165 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercatsoe.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * Headerfile for ethercatsoe.c + */ + +#ifndef _ethercatsoe_ +#define _ethercatsoe_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define EC_SOE_DATASTATE_B 0x01 +#define EC_SOE_NAME_B 0x02 +#define EC_SOE_ATTRIBUTE_B 0x04 +#define EC_SOE_UNIT_B 0x08 +#define EC_SOE_MIN_B 0x10 +#define EC_SOE_MAX_B 0x20 +#define EC_SOE_VALUE_B 0x40 +#define EC_SOE_DEFAULT_B 0x80 + +#define EC_SOE_MAXNAME 60 +#define EC_SOE_MAXMAPPING 64 + +#define EC_IDN_MDTCONFIG 24 +#define EC_IDN_ATCONFIG 16 + +/** SoE name structure */ +PACKED_BEGIN +typedef struct PACKED +{ + /** current length in bytes of list */ + uint16 currentlength; + /** maximum length in bytes of list */ + uint16 maxlength; + char name[EC_SOE_MAXNAME]; +} ec_SoEnamet; +PACKED_END + +/** SoE list structure */ +PACKED_BEGIN +typedef struct PACKED +{ + /** current length in bytes of list */ + uint16 currentlength; + /** maximum length in bytes of list */ + uint16 maxlength; + union + { + uint8 byte[8]; + uint16 word[4]; + uint32 dword[2]; + uint64 lword[1]; + }; +} ec_SoElistt; +PACKED_END + +/** SoE IDN mapping structure */ +PACKED_BEGIN +typedef struct PACKED +{ + /** current length in bytes of list */ + uint16 currentlength; + /** maximum length in bytes of list */ + uint16 maxlength; + uint16 idn[EC_SOE_MAXMAPPING]; +} ec_SoEmappingt; +PACKED_END + +#define EC_SOE_LENGTH_1 0x00 +#define EC_SOE_LENGTH_2 0x01 +#define EC_SOE_LENGTH_4 0x02 +#define EC_SOE_LENGTH_8 0x03 +#define EC_SOE_TYPE_BINARY 0x00 +#define EC_SOE_TYPE_UINT 0x01 +#define EC_SOE_TYPE_INT 0x02 +#define EC_SOE_TYPE_HEX 0x03 +#define EC_SOE_TYPE_STRING 0x04 +#define EC_SOE_TYPE_IDN 0x05 +#define EC_SOE_TYPE_FLOAT 0x06 +#define EC_SOE_TYPE_PARAMETER 0x07 + +/** SoE attribute structure */ +PACKED_BEGIN +typedef struct PACKED +{ + /** evaluation factor for display purposes */ + uint32 evafactor :16; + /** length of IDN element(s) */ + uint32 length :2; + /** IDN is list */ + uint32 list :1; + /** IDN is command */ + uint32 command :1; + /** datatype */ + uint32 datatype :3; + uint32 reserved1 :1; + /** decimals to display if float datatype */ + uint32 decimals :4; + /** write protected in pre-op */ + uint32 wppreop :1; + /** write protected in safe-op */ + uint32 wpsafeop :1; + /** write protected in op */ + uint32 wpop :1; + uint32 reserved2 :1; +} ec_SoEattributet; +PACKED_END + +#ifdef EC_VER1 +int ec_SoEread(uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout); +int ec_SoEwrite(uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout); +int ec_readIDNmap(uint16 slave, int *Osize, int *Isize); +#endif + +int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout); +int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout); +int ecx_readIDNmap(ecx_contextt *context, uint16 slave, int *Osize, int *Isize); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/soem/ethercattype.h b/soem/ethercattype.h new file mode 100644 index 0000000..54243d3 --- /dev/null +++ b/soem/ethercattype.h @@ -0,0 +1,591 @@ +/* + * Simple Open EtherCAT Master Library + * + * File : ethercattype.h + * Version : 1.3.0 + * Date : 24-02-2013 + * Copyright (C) 2005-2013 Speciaal Machinefabriek Ketels v.o.f. + * Copyright (C) 2005-2013 Arthur Ketels + * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven + * + * SOEM is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * The EtherCAT Technology, the trade name and logo EtherCAT are the intellectual + * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for + * the sole purpose of creating, using and/or selling or otherwise distributing + * an EtherCAT network master provided that an EtherCAT Master License is obtained + * from Beckhoff Automation GmbH. + * + * In case you did not receive a copy of the EtherCAT Master License along with + * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany + * (www.beckhoff.com). + */ + +/** \file + * \brief + * General typedefs and defines for EtherCAT. + * + * Defines that could need optimalisation for specific applications + * are the EC_TIMEOUTxxx. Assumptions for the standard settings are a + * standard linux PC or laptop and a wired connection to maximal 100 slaves. + * For use with wireless connections or lots of slaves the timouts need + * increasing. For fast systems running Xenomai and RT-net or alike the + * timeouts need to be shorter. + */ + +#ifndef _EC_TYPE_H +#define _EC_TYPE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Define Little or Big endian target */ +#define EC_LITTLE_ENDIAN + +/** define EC_VER1 if version 1 default context and functions are needed + * comment if application uses only ecx_ functions and own context */ +#define EC_VER1 + +#include + +/** return value general error */ +#define EC_ERROR -3 +/** return value no frame returned */ +#define EC_NOFRAME -1 +/** return value unknown frame received */ +#define EC_OTHERFRAME -2 +/** maximum EtherCAT frame length in bytes */ +#define EC_MAXECATFRAME 1518 +/** maximum EtherCAT LRW frame length in bytes */ +/* MTU - Ethernet header - length - datagram header - WCK - FCS */ +#define EC_MAXLRWDATA (EC_MAXECATFRAME - 14 - 2 - 10 - 2 - 4) +/** size of DC datagram used in first LRW frame */ +#define EC_FIRSTDCDATAGRAM 20 +/** standard frame buffer size in bytes */ +#define EC_BUFSIZE EC_MAXECATFRAME +/** datagram type EtherCAT */ +#define EC_ECATTYPE 0x1000 +/** number of frame buffers per channel (tx, rx1 rx2) */ +#define EC_MAXBUF 16 +/** timeout value in us for tx frame to return to rx */ +#define EC_TIMEOUTRET 2000 +/** timeout value in us for safe data transfer, max. triple retry */ +#define EC_TIMEOUTRET3 (EC_TIMEOUTRET * 3) +/** timeout value in us for return "safe" variant (f.e. wireless) */ +#define EC_TIMEOUTSAFE 20000 +/** timeout value in us for EEPROM access */ +#define EC_TIMEOUTEEP 20000 +/** timeout value in us for tx mailbox cycle */ +#define EC_TIMEOUTTXM 20000 +/** timeout value in us for rx mailbox cycle */ +#define EC_TIMEOUTRXM 700000 +/** timeout value in us for check statechange */ +#define EC_TIMEOUTSTATE 2000000 +/** size of EEPROM bitmap cache */ +#define EC_MAXEEPBITMAP 128 +/** size of EEPROM cache buffer */ +#define EC_MAXEEPBUF EC_MAXEEPBITMAP << 5 +/** default number of retries if wkc <= 0 */ +#define EC_DEFAULTRETRIES 3 + +/** definition for frame buffers */ +typedef uint8 ec_bufT[EC_BUFSIZE]; + +/** ethernet header definition */ +PACKED_BEGIN +typedef struct PACKED +{ + /** destination MAC */ + uint16 da0,da1,da2; + /** source MAC */ + uint16 sa0,sa1,sa2; + /** ethernet type */ + uint16 etype; +} ec_etherheadert; +PACKED_END + +/** ethernet header size */ +#define ETH_HEADERSIZE sizeof(ec_etherheadert) + +/** EtherCAT datagram header definition */ +PACKED_BEGIN +typedef struct PACKED +{ + /** length of EtherCAT datagram */ + uint16 elength; + /** EtherCAT command, see ec_cmdtype */ + uint8 command; + /** index, used in SOEM for Tx to Rx recombination */ + uint8 index; + /** ADP */ + uint16 ADP; + /** ADO */ + uint16 ADO; + /** length of data portion in datagram */ + uint16 dlength; + /** interrupt, currently unused */ + uint16 irpt; +} ec_comt; +PACKED_END + +/** EtherCAT header size */ +#define EC_HEADERSIZE sizeof(ec_comt) +/** size of ec_comt.elength item in EtherCAT header */ +#define EC_ELENGTHSIZE sizeof(uint16) +/** offset position of command in EtherCAT header */ +#define EC_CMDOFFSET EC_ELENGTHSIZE +/** size of workcounter item in EtherCAT datagram */ +#define EC_WKCSIZE sizeof(uint16) +/** definition of datagram follows bit in ec_comt.dlength */ +#define EC_DATAGRAMFOLLOWS (1 << 15) + +/** Possible error codes returned. */ +typedef enum +{ + /** No error */ + EC_ERR_OK = 0, + /** Library already initialized. */ + EC_ERR_ALREADY_INITIALIZED, + /** Library not initialized. */ + EC_ERR_NOT_INITIALIZED, + /** Timeout occured during execution of the function. */ + EC_ERR_TIMEOUT, + /** No slaves were found. */ + EC_ERR_NO_SLAVES, + /** Function failed. */ + EC_ERR_NOK +} ec_err; + +/** Possible EtherCAT slave states */ +typedef enum +{ + /** Init state*/ + EC_STATE_INIT = 0x01, + /** Pre-operational. */ + EC_STATE_PRE_OP = 0x02, + /** Boot state*/ + EC_STATE_BOOT = 0x03, + /** Safe-operational. */ + EC_STATE_SAFE_OP = 0x04, + /** Operational */ + EC_STATE_OPERATIONAL = 0x08, + /** Error or ACK error */ + EC_STATE_ACK = 0x10, + EC_STATE_ERROR = 0x10 +} ec_state; + +/** Possible buffer states */ +typedef enum +{ + /** Empty */ + EC_BUF_EMPTY = 0x00, + /** Allocated, but not filled */ + EC_BUF_ALLOC = 0x01, + /** Transmitted */ + EC_BUF_TX = 0x02, + /** Received, but not consumed */ + EC_BUF_RCVD = 0x03, + /** Cycle completed */ + EC_BUF_COMPLETE = 0x04 +} ec_bufstate; + +/** Ethercat data types */ +typedef enum +{ + ECT_BOOLEAN = 0x0001, + ECT_INTEGER8 = 0x0002, + ECT_INTEGER16 = 0x0003, + ECT_INTEGER32 = 0x0004, + ECT_UNSIGNED8 = 0x0005, + ECT_UNSIGNED16 = 0x0006, + ECT_UNSIGNED32 = 0x0007, + ECT_REAL32 = 0x0008, + ECT_VISIBLE_STRING = 0x0009, + ECT_OCTET_STRING = 0x000A, + ECT_UNICODE_STRING = 0x000B, + ECT_TIME_OF_DAY = 0x000C, + ECT_TIME_DIFFERENCE = 0x000D, + ECT_DOMAIN = 0x000F, + ECT_INTEGER24 = 0x0010, + ECT_REAL64 = 0x0011, + ECT_INTEGER64 = 0x0015, + ECT_UNSIGNED24 = 0x0016, + ECT_UNSIGNED64 = 0x001B, + ECT_BIT1 = 0x0030, + ECT_BIT2 = 0x0031, + ECT_BIT3 = 0x0032, + ECT_BIT4 = 0x0033, + ECT_BIT5 = 0x0034, + ECT_BIT6 = 0x0035, + ECT_BIT7 = 0x0036, + ECT_BIT8 = 0x0037 +} ec_datatype; + +/** Ethercat command types */ +typedef enum +{ + /** No operation */ + EC_CMD_NOP = 0x00, + /** Auto Increment Read */ + EC_CMD_APRD, + /** Auto Increment Write */ + EC_CMD_APWR, + /** Auto Increment Read Write */ + EC_CMD_APRW, + /** Configured Address Read */ + EC_CMD_FPRD, + /** Configured Address Write */ + EC_CMD_FPWR, + /** Configured Address Read Write */ + EC_CMD_FPRW, + /** Broadcast Read */ + EC_CMD_BRD, + /** Broaddcast Write */ + EC_CMD_BWR, + /** Broadcast Read Write */ + EC_CMD_BRW, + /** Logical Memory Read */ + EC_CMD_LRD, + /** Logical Memory Write */ + EC_CMD_LWR, + /** Logical Memory Read Write */ + EC_CMD_LRW, + /** Auto Increment Read Mulitple Write */ + EC_CMD_ARMW, + /** Configured Read Mulitple Write */ + EC_CMD_FRMW + /** Reserved */ +} ec_cmdtype; + +/** Ethercat EEprom command types */ +typedef enum +{ + /** No operation */ + EC_ECMD_NOP = 0x0000, + /** Read */ + EC_ECMD_READ = 0x0100, + /** Write */ + EC_ECMD_WRITE = 0x0201, + /** Reload */ + EC_ECMD_RELOAD = 0x0300 +} ec_ecmdtype; + +/** EEprom state machine read size */ +#define EC_ESTAT_R64 0x0040 +/** EEprom state machine busy flag */ +#define EC_ESTAT_BUSY 0x8000 +/** EEprom state machine error flag mask */ +#define EC_ESTAT_EMASK 0x7800 +/** EEprom state machine error acknowledge */ +#define EC_ESTAT_NACK 0x2000 + +/* Ethercat SSI (Slave Information Interface) */ + +/** Start address SII sections in Eeprom */ +#define ECT_SII_START 0x0040 + +enum +{ + /** SII category strings */ + ECT_SII_STRING = 10, + /** SII category general */ + ECT_SII_GENERAL = 30, + /** SII category FMMU */ + ECT_SII_FMMU = 40, + /** SII category SM */ + ECT_SII_SM = 41, + /** SII category PDO */ + ECT_SII_PDO = 50 +}; + +/** Item offsets in SII general section */ +enum +{ + ECT_SII_MANUF = 0x0008, + ECT_SII_ID = 0x000a, + ECT_SII_REV = 0x000c, + ECT_SII_BOOTRXMBX = 0x0014, + ECT_SII_BOOTTXMBX = 0x0016, + ECT_SII_MBXSIZE = 0x0019, + ECT_SII_TXMBXADR = 0x001a, + ECT_SII_RXMBXADR = 0x0018, + ECT_SII_MBXPROTO = 0x001c +}; + +/** Mailbox types definitions */ +enum +{ + /** Error mailbox type */ + ECT_MBXT_ERR = 0x00, + /** ADS over EtherCAT mailbox type */ + ECT_MBXT_AOE, + /** Ethernet over EtherCAT mailbox type */ + ECT_MBXT_EOE, + /** CANopen over EtherCAT mailbox type */ + ECT_MBXT_COE, + /** File over EtherCAT mailbox type */ + ECT_MBXT_FOE, + /** Servo over EtherCAT mailbox type */ + ECT_MBXT_SOE, + /** Vendor over EtherCAT mailbox type */ + ECT_MBXT_VOE = 0x0f +}; + +/** CoE mailbox types */ +enum +{ + ECT_COES_EMERGENCY = 0x01, + ECT_COES_SDOREQ, + ECT_COES_SDORES, + ECT_COES_TXPDO, + ECT_COES_RXPDO, + ECT_COES_TXPDO_RR, + ECT_COES_RXPDO_RR, + ECT_COES_SDOINFO +}; + +/** CoE SDO commands */ +enum +{ + ECT_SDO_DOWN_INIT = 0x21, + ECT_SDO_DOWN_EXP = 0x23, + ECT_SDO_DOWN_INIT_CA = 0x31, + ECT_SDO_UP_REQ = 0x40, + ECT_SDO_UP_REQ_CA = 0x50, + ECT_SDO_SEG_UP_REQ = 0x60, + ECT_SDO_ABORT = 0x80 +}; + +/** CoE Object Description commands */ +enum +{ + ECT_GET_ODLIST_REQ = 0x01, + ECT_GET_ODLIST_RES = 0x02, + ECT_GET_OD_REQ = 0x03, + ECT_GET_OD_RES = 0x04, + ECT_GET_OE_REQ = 0x05, + ECT_GET_OE_RES = 0x06, + ECT_SDOINFO_ERROR = 0x07 +}; + +/** FoE opcodes */ +enum +{ + ECT_FOE_READ = 0x01, + ECT_FOE_WRITE, + ECT_FOE_DATA, + ECT_FOE_ACK, + ECT_FOE_ERROR, + ECT_FOE_BUSY +}; + +/** SoE opcodes */ +enum +{ + ECT_SOE_READREQ = 0x01, + ECT_SOE_READRES, + ECT_SOE_WRITEREQ, + ECT_SOE_WRITERES, + ECT_SOE_NOTIFICATION, + ECT_SOE_EMERGENCY +}; + +/** Ethercat registers */ +enum +{ + ECT_REG_TYPE = 0x0000, + ECT_REG_PORTDES = 0x0007, + ECT_REG_ESCSUP = 0x0008, + ECT_REG_STADR = 0x0010, + ECT_REG_ALIAS = 0x0012, + ECT_REG_DLCTL = 0x0100, + ECT_REG_DLPORT = 0x0101, + ECT_REG_DLALIAS = 0x0103, + ECT_REG_DLSTAT = 0x0110, + ECT_REG_ALCTL = 0x0120, + ECT_REG_ALSTAT = 0x0130, + ECT_REG_ALSTATCODE = 0x0134, + ECT_REG_PDICTL = 0x0140, + ECT_REG_IRQMASK = 0x0200, + ECT_REG_RXERR = 0x0300, + ECT_REG_FRXERR = 0x0308, + ECT_REG_EPUECNT = 0x030C, + ECT_REG_PECNT = 0x030D, + ECT_REG_PECODE = 0x030E, + ECT_REG_LLCNT = 0x0310, + ECT_REG_WDCNT = 0x0442, + ECT_REG_EEPCFG = 0x0500, + ECT_REG_EEPCTL = 0x0502, + ECT_REG_EEPSTAT = 0x0502, + ECT_REG_EEPADR = 0x0504, + ECT_REG_EEPDAT = 0x0508, + ECT_REG_FMMU0 = 0x0600, + ECT_REG_FMMU1 = ECT_REG_FMMU0 + 0x10, + ECT_REG_FMMU2 = ECT_REG_FMMU1 + 0x10, + ECT_REG_FMMU3 = ECT_REG_FMMU2 + 0x10, + ECT_REG_SM0 = 0x0800, + ECT_REG_SM1 = ECT_REG_SM0 + 0x08, + ECT_REG_SM2 = ECT_REG_SM1 + 0x08, + ECT_REG_SM3 = ECT_REG_SM2 + 0x08, + ECT_REG_SM0STAT = ECT_REG_SM0 + 0x05, + ECT_REG_SM1STAT = ECT_REG_SM1 + 0x05, + ECT_REG_SM1ACT = ECT_REG_SM1 + 0x06, + ECT_REG_SM1CONTR = ECT_REG_SM1 + 0x07, + ECT_REG_DCTIME0 = 0x0900, + ECT_REG_DCTIME1 = 0x0904, + ECT_REG_DCTIME2 = 0x0908, + ECT_REG_DCTIME3 = 0x090C, + ECT_REG_DCSYSTIME = 0x0910, + ECT_REG_DCSOF = 0x0918, + ECT_REG_DCSYSOFFSET = 0x0920, + ECT_REG_DCSYSDELAY = 0x0928, + ECT_REG_DCSYSDIFF = 0x092C, + ECT_REG_DCSPEEDCNT = 0x0930, + ECT_REG_DCTIMEFILT = 0x0934, + ECT_REG_DCCUC = 0x0980, + ECT_REG_DCSYNCACT = 0x0981, + ECT_REG_DCSTART0 = 0x0990, + ECT_REG_DCCYCLE0 = 0x09A0, + ECT_REG_DCCYCLE1 = 0x09A4 +}; + +/** standard SDO Sync Manager Communication Type */ +#define ECT_SDO_SMCOMMTYPE 0x1c00 +/** standard SDO PDO assignment */ +#define ECT_SDO_PDOASSIGN 0x1c10 +/** standard SDO RxPDO assignment */ +#define ECT_SDO_RXPDOASSIGN 0x1c12 +/** standard SDO TxPDO assignment */ +#define ECT_SDO_TXPDOASSIGN 0x1c13 + +/** Ethercat packet type */ +#define ETH_P_ECAT 0x88A4 + +/** Error types */ +typedef enum +{ + EC_ERR_TYPE_SDO_ERROR = 0, + EC_ERR_TYPE_EMERGENCY = 1, + EC_ERR_TYPE_PACKET_ERROR = 3, + EC_ERR_TYPE_SDOINFO_ERROR = 4, + EC_ERR_TYPE_FOE_ERROR = 5, + EC_ERR_TYPE_FOE_BUF2SMALL = 6, + EC_ERR_TYPE_FOE_PACKETNUMBER = 7, + EC_ERR_TYPE_SOE_ERROR = 8, + EC_ERR_TYPE_MBX_ERROR = 9 +} ec_err_type; + +/** Struct to retrieve errors. */ +typedef struct +{ + /** Time at which the error was generated. */ + ec_timet Time; + /** Signal bit, error set but not read */ + boolean Signal; + /** Slave number that generated the error */ + uint16 Slave; + /** CoE SDO index that generated the error */ + uint16 Index; + /** CoE SDO subindex that generated the error */ + uint8 SubIdx; + /** Type of error */ + ec_err_type Etype; + union + { + /** General abortcode */ + int32 AbortCode; + /** Specific error for Emergency mailbox */ + struct + { + uint16 ErrorCode; + uint8 ErrorReg; + uint8 b1; + uint16 w1; + uint16 w2; + }; + }; +} ec_errort; + +/** Helper macros */ +/** Macro to make a word from 2 bytes */ +#define MK_WORD(msb, lsb) ((((uint16)(msb))<<8) | (lsb)) +/** Macro to get hi byte of a word */ +#define HI_BYTE(w) ((w) >> 8) +/** Macro to get low byte of a word */ +#define LO_BYTE(w) ((w) & 0x00ff) +/** Macro to swap hi and low byte of a word */ +#define SWAP(w) ((((w)& 0xff00) >> 8) | (((w) & 0x00ff) << 8)) +/** Macro to get hi word of a dword */ +#define LO_WORD(l) ((l) & 0xffff) +/** Macro to get hi word of a dword */ +#define HI_WORD(l) ((l) >> 16) + +#define get_unaligned(ptr) \ + ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) + +#define put_unaligned32(val, ptr) \ + (memcpy((ptr), &(val), 4)) + +#define put_unaligned64(val, ptr) \ + (memcpy((ptr), &(val), 8)) + +#if !defined(EC_BIG_ENDIAN) && defined(EC_LITTLE_ENDIAN) + + #define htoes(A) (A) + #define htoel(A) (A) + #define htoell(A) (A) + #define etohs(A) (A) + #define etohl(A) (A) + #define etohll(A) (A) + +#elif !defined(EC_LITTLE_ENDIAN) && defined(EC_BIG_ENDIAN) + + #define htoes(A) ((((uint16)(A) & 0xff00) >> 8) | \ + (((uint16)(A) & 0x00ff) << 8)) + #define htoel(A) ((((uint32)(A) & 0xff000000) >> 24) | \ + (((uint32)(A) & 0x00ff0000) >> 8) | \ + (((uint32)(A) & 0x0000ff00) << 8) | \ + (((uint32)(A) & 0x000000ff) << 24)) + #define htoell(A) ((((uint64)(A) & (uint64)0xff00000000000000ULL) >> 56) | \ + (((uint64)(A) & (uint64)0x00ff000000000000ULL) >> 40) | \ + (((uint64)(A) & (uint64)0x0000ff0000000000ULL) >> 24) | \ + (((uint64)(A) & (uint64)0x000000ff00000000ULL) >> 8) | \ + (((uint64)(A) & (uint64)0x00000000ff000000ULL) << 8) | \ + (((uint64)(A) & (uint64)0x0000000000ff0000ULL) << 24) | \ + (((uint64)(A) & (uint64)0x000000000000ff00ULL) << 40) | \ + (((uint64)(A) & (uint64)0x00000000000000ffULL) << 56)) + + #define etohs htoes + #define etohl htoel + #define etohll htoell + +#else + + #error "Must define one of EC_BIG_ENDIAN or EC_LITTLE_ENDIAN" + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _EC_TYPE_H */ diff --git a/test/.late b/test/.late new file mode 100644 index 0000000..e69de29 diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..6cf8eee --- /dev/null +++ b/test/Makefile @@ -0,0 +1,21 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 175 2012-06-21 07:14:12Z rtlaka $ +#------------------------------------------------------------------------------ + +SUBDIRS = $(BSP) +include $(PRJ_ROOT)/make/subdir.mk diff --git a/test/linux/Makefile b/test/linux/Makefile new file mode 100644 index 0000000..015c3b0 --- /dev/null +++ b/test/linux/Makefile @@ -0,0 +1,33 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 178 2012-06-21 11:51:19Z rtlaka $ +#------------------------------------------------------------------------------ + +SUBDIRS = ebox eepromtool red_test simple_test slaveinfo firm_update + +all: subdirs + +subdirs: + @for dir in $(SUBDIRS); do \ + ($(MAKE) -C $$dir all) || exit; \ + done + +clean: + @for dir in $(SUBDIRS); do \ + ($(MAKE) -C $$dir clean) \ + done + diff --git a/test/linux/aliastool.c b/test/linux/aliastool.c new file mode 100644 index 0000000..873d31b --- /dev/null +++ b/test/linux/aliastool.c @@ -0,0 +1,436 @@ +/** \file + * \brief EEprom tool for Simple Open EtherCAT master + * + * Usage : eepromtool ifname slave OPTION fname|alias + * ifname is NIC interface, f.e. eth0 + * slave = slave number in EtherCAT order 1..n + * -r read EEPROM, output binary format + * -ri read EEPROM, output Intel Hex format + * -w write EEPROM, input binary format + * -wi write EEPROM, input Intel Hex format + * -i display EEPROM information + * -walias write slave alias in EEPROM + * + * (c)Arthur Ketels 2010-2012 + */ + +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +//#include "ethercatfoe.h" +//#include "ethercatconfig.h" +//#include "ethercatprint.h" + +#define MAXBUF 32768 +#define STDBUF 2048 +#define MINBUF 128 + +#define MODE_NONE 0 +#define MODE_READBIN 1 +#define MODE_READINTEL 2 +#define MODE_WRITEBIN 3 +#define MODE_WRITEINTEL 4 +#define MODE_WRITEALIAS 5 +#define MODE_INFO 6 + +#define MAXSLENGTH 256 + +uint8 ebuf[MAXBUF]; +uint8 ob; +uint16 ow; +int os; +int slave; +int alias; +struct timeval tstart,tend, tdif; +int wkc; +int mode; +char sline[MAXSLENGTH]; + +#define IHEXLENGTH 0x20 + +int input_bin(char *fname, int *length) +{ + FILE *fp; + + int cc = 0, c; + + fp = fopen(fname, "rb"); + if(fp == NULL) + return 0; + while (((c = fgetc(fp)) != EOF) && (cc < MAXBUF)) + ebuf[cc++] = (uint8)c; + *length = cc; + fclose(fp); + + return 1; +} + +int input_intelhex(char *fname, int *start, int *length) +{ + FILE *fp; + + int c, sc, retval = 1; + int ll, ladr, lt, sn, i, lval; + int hstart, hlength, sum; + + fp = fopen(fname, "r"); + if(fp == NULL) + return 0; + hstart = MAXBUF; + hlength = 0; + sum = 0; + do + { + memset(sline, 0x00, MAXSLENGTH); + sc = 0; + while (((c = fgetc(fp)) != EOF) && (c != 0x0A) && (sc < (MAXSLENGTH -1))) + sline[sc++] = (uint8)c; + if ((c != EOF) && ((sc < 11) || (sline[0] != ':'))) + { + c = EOF; + retval = 0; + printf("Invalid Intel Hex format.\n"); + } + if (c != EOF) + { + sn = sscanf(sline , ":%2x%4x%2x", &ll, &ladr, <); + if ((sn == 3) && ((ladr + ll) <= MAXBUF) && (lt == 0)) + { + sum = ll + (ladr >> 8) + (ladr & 0xff) + lt; + if(ladr < hstart) hstart = ladr; + for(i = 0; i < ll ; i++) + { + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + ebuf[ladr + i] = (uint8)lval; + sum += (uint8)lval; + } + if(((ladr + ll) - hstart) > hlength) + hlength = (ladr + ll) - hstart; + sum = (0x100 - sum) & 0xff; + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + if (!sn || ((sum - lval) != 0)) + { + c = EOF; + retval = 0; + printf("Invalid checksum.\n"); + } + } + } + } + while (c != EOF); + if (retval) + { + *length = hlength; + *start = hstart; + } + fclose(fp); + + return retval; +} + +int output_bin(char *fname, int length) +{ + FILE *fp; + + int cc; + + fp = fopen(fname, "wb"); + if(fp == NULL) + return 0; + for (cc = 0 ; cc < length ; cc++) + fputc( ebuf[cc], fp); + fclose(fp); + + return 1; +} + +int output_intelhex(char *fname, int length) +{ + FILE *fp; + + int cc = 0, ll, sum, i; + + fp = fopen(fname, "w"); + if(fp == NULL) + return 0; + while (cc < length) + { + ll = length - cc; + if (ll > IHEXLENGTH) ll = IHEXLENGTH; + sum = ll + (cc >> 8) + (cc & 0xff); + fprintf(fp, ":%2.2X%4.4X00", ll, cc); + for (i = 0; i < ll; i++) + { + fprintf(fp, "%2.2X", ebuf[cc + i]); + sum += ebuf[cc + i]; + } + fprintf(fp, "%2.2X\n", (0x100 - sum) & 0xff); + cc += ll; + } + fprintf(fp, ":00000001FF\n"); + fclose(fp); + + return 1; +} + +int eeprom_read(int slave, int start, int length) +{ + int i, wkc, ainc = 4; + uint16 estat, aiadr; + uint32 b4; + uint64 b8; + uint8 eepctl; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + estat = 0x0000; + aiadr = 1 - slave; + wkc=ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET); /* read eeprom status */ + estat = etohs(estat); + if (estat & EC_ESTAT_R64) + { + ainc = 8; + for (i = start ; i < (start + length) ; i+=ainc) + { + b8 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = b8; + ebuf[i+1] = b8 >> 8; + ebuf[i+2] = b8 >> 16; + ebuf[i+3] = b8 >> 24; + ebuf[i+4] = b8 >> 32; + ebuf[i+5] = b8 >> 40; + ebuf[i+6] = b8 >> 48; + ebuf[i+7] = b8 >> 56; + } + } + else + { + for (i = start ; i < (start + length) ; i+=ainc) + { + b4 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = b4; + ebuf[i+1] = b4 >> 8; + ebuf[i+2] = b4 >> 16; + ebuf[i+3] = b4 >> 24; + } + } + + return 1; + } + + return 0; +} + +int eeprom_write(int slave, int start, int length) +{ + int i, wkc, dc = 0; + uint16 aiadr, *wbuf; + uint8 eepctl; + int ret; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + aiadr = 1 - slave; + wbuf = (uint16 *)&ebuf[0]; + for (i = start ; i < (start + length) ; i+=2) + { + ret = ec_writeeepromAP(aiadr, i >> 1 , *(wbuf + (i >> 1)), EC_TIMEOUTEEP); + if (++dc >= 100) + { + dc = 0; + printf("."); + fflush(stdout); + } + } + + return 1; + } + + return 0; +} + +int eeprom_writealias(int slave, int alias) +{ + int i, wkc, dc = 0; + uint16 aiadr, *wbuf; + uint8 eepctl; + int ret; + + if((ec_slavecount >= slave) && (slave > 0) && (alias <= 0xffff)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + ret = ec_writeeepromAP(aiadr, 0x04 , alias, EC_TIMEOUTEEP); + + return ret; + } + + return 0; +} + +void eepromtool(char *ifname, int slave, int mode, char *fname) +{ + int w, rc = 0, estart, esize; + uint16 *wbuf; + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + + w = 0x0000; + wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE); /* detect number of slaves */ + if (wkc > 0) + { + ec_slavecount = wkc; + + printf("%d slaves found.\n",ec_slavecount); + if((ec_slavecount >= slave) && (slave > 0)) + { + if ((mode == MODE_INFO) || (mode == MODE_READBIN) || (mode == MODE_READINTEL)) + { + rc = gettimeofday(&tstart, NULL); + eeprom_read(slave, 0x0000, MINBUF); // read first 128 bytes + + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d data\n", slave); + printf(" PDI Control : %4.4X\n",*(wbuf + 0x00)); + printf(" PDI Config : %4.4X\n",*(wbuf + 0x01)); + printf(" Config Alias : %4.4X\n",*(wbuf + 0x04)); + printf(" Checksum : %4.4X\n",*(wbuf + 0x07)); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + printf(" Mailbox Protocol : %4.4X\n",*(wbuf + 0x1C)); + esize = (*(wbuf + 0x3E) + 1) * 128; + if (esize > MAXBUF) esize = MAXBUF; + printf(" Size : %4.4X = %d bytes\n",*(wbuf + 0x3E), esize); + printf(" Version : %4.4X\n",*(wbuf + 0x3F)); + } + if ((mode == MODE_READBIN) || (mode == MODE_READINTEL)) + { + if (esize > MINBUF) + eeprom_read(slave, MINBUF, esize - MINBUF); // read reminder + + rc = gettimeofday(&tend, NULL); + timersub(&tend, &tstart, &tdif); + if (mode == MODE_READINTEL) output_intelhex(fname, esize); + if (mode == MODE_READBIN) output_bin(fname, esize); + + printf("\nTotal EEPROM read time :%ldms\n", (tdif.tv_usec+(tdif.tv_sec*1000000L)) / 1000); + } + if ((mode == MODE_WRITEBIN) || (mode == MODE_WRITEINTEL)) + { + estart = 0; + if (mode == MODE_WRITEINTEL) rc = input_intelhex(fname, &estart, &esize); + if (mode == MODE_WRITEBIN) rc = input_bin(fname, &esize); + + if (rc > 0) + { + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d\n", slave); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + + printf("Busy"); + fflush(stdout); + rc = gettimeofday(&tstart, NULL); + eeprom_write(slave, estart, esize); + rc = gettimeofday(&tend, NULL); + timersub(&tend, &tstart, &tdif); + + printf("\nTotal EEPROM write time :%ldms\n", (tdif.tv_usec+(tdif.tv_sec*1000000L)) / 1000); + } + else + printf("Error reading file, abort.\n"); + } + if (mode == MODE_WRITEALIAS) + { + if(eeprom_writealias(slave, alias)) + printf("Alias %4.4X written successfully to slave %d\n"); + else + printf("Alias not written\n"); + } + } + else + printf("Slave number outside range.\n"); + } + else + printf("No slaves found!\n"); + printf("End, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + printf("No socket connection on %s\nExcecute as root\n",ifname); +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nEEPROM tool\n"); + + mode = MODE_NONE; + if (argc > 3) + { + slave = atoi(argv[2]); + if ((strncmp(argv[3], "-i", sizeof("-i")) == 0)) mode = MODE_INFO; + if (argc > 4) + { + if ((strncmp(argv[3], "-r", sizeof("-r")) == 0)) mode = MODE_READBIN; + if ((strncmp(argv[3], "-ri", sizeof("-ri")) == 0)) mode = MODE_READINTEL; + if ((strncmp(argv[3], "-w", sizeof("-w")) == 0)) mode = MODE_WRITEBIN; + if ((strncmp(argv[3], "-wi", sizeof("-wi")) == 0)) mode = MODE_WRITEINTEL; + if ((strncmp(argv[3], "-walias", sizeof("-walias")) == 0)) + { + mode = MODE_WRITEALIAS; + alias = atoi(argv(4)); + } + } + /* start tool */ + eepromtool(argv[1],slave,mode,argv[4]); + } + else + { + printf("Usage: eepromtool ifname slave OPTION fname|alias\n"); + printf("ifname = eth0 for example\n"); + printf("slave = slave number in EtherCAT order 1..n\n"); + printf(" -i display EEPROM information\n"); + printf(" -walias write slave alias\n"); + printf(" -r read EEPROM, output binary format\n"); + printf(" -ri read EEPROM, output Intel Hex format\n"); + printf(" -w write EEPROM, input binary format\n"); + printf(" -wi write EEPROM, input Intel Hex format\n"); + } + + printf("End program\n"); + + return (0); +} diff --git a/test/linux/ebox/Makefile b/test/linux/ebox/Makefile new file mode 100644 index 0000000..00472ed --- /dev/null +++ b/test/linux/ebox/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = ebox + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/ebox/ebox.c b/test/linux/ebox/ebox.c new file mode 100644 index 0000000..5e4e1c2 --- /dev/null +++ b/test/linux/ebox/ebox.c @@ -0,0 +1,394 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : ebox [ifname] [cycletime] + * ifname is NIC interface, f.e. eth0 + * cycletime in us, f.e. 500 + * + * This test is specifically build for the E/BOX. + * + * (c)Arthur Ketels 2011 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatconfig.h" +#include "ethercatdc.h" + +#define NSEC_PER_SEC 1000000000 + +typedef struct PACKED +{ + uint8 status; + uint8 counter; + uint8 din; + int32 ain[2]; + uint32 tsain; + int32 enc[2]; +} in_EBOXt; + +typedef struct PACKED +{ + uint8 counter; + int16 stream[100]; +} in_EBOX_streamt; + +typedef struct PACKED +{ + uint8 control; + uint8 dout; + int16 aout[2]; + uint16 pwmout[2]; +} out_EBOXt; + +typedef struct PACKED +{ + uint8 control; +} out_EBOX_streamt; + +// total samples to capture +#define MAXSTREAM 200000 +// sample interval in ns, here 8us -> 125kHz +// maximum data rate for E/BOX v1.0.1 is around 150kHz +#define SYNC0TIME 8000 + +struct sched_param schedp; +char IOmap[4096]; +pthread_t thread1; +struct timeval tv,t1,t2; +int dorun = 0; +int deltat, tmax=0; +int64 toff; +int DCdiff; +int os; +uint32 ob; +int16 ob2; +uint8 ob3; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +int64 integral=0; +uint32 cyclecount; +in_EBOX_streamt *in_EBOX; +out_EBOX_streamt *out_EBOX; +double ain[2]; +int ainc; +int streampos; +int16 stream1[MAXSTREAM]; +int16 stream2[MAXSTREAM]; + +int output_cvs(char *fname, int length) +{ + FILE *fp; + + int i; + + fp = fopen(fname, "w"); + if(fp == NULL) + return 0; + for (i = 0; i < length; i++) + { + fprintf(fp, "%d %d %d\n", i, stream1[i], stream2[i]); + } + fclose(fp); + + return 1; +} + +void eboxtest(char *ifname) +{ + int cnt, i; + + printf("Starting E/BOX test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + // check if first slave is an E/BOX + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0)) + { + // reprogram PDO mapping to set slave in stream mode + // this can only be done in pre-OP state + os=sizeof(ob2); ob2 = 0x1601; + ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + os=sizeof(ob2); ob2 = 0x1a01; + ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + } + + ec_config_map(&IOmap); + + ec_configdc(); + + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + + /* configure DC options for every DC capable slave found in the list */ + printf("DC capable : %d\n",ec_configdc()); + + /* check configuration */ + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0) + ) + { + printf("E/BOX found.\n"); + + /* connect struct pointers to slave I/O pointers */ + in_EBOX = (in_EBOX_streamt*) ec_slave[1].inputs; + out_EBOX = (out_EBOX_streamt*) ec_slave[1].outputs; + + /* read indevidual slave state and store in ec_slave[] */ + ec_readstate(); + for(cnt = 1; cnt <= ec_slavecount ; cnt++) + { + printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + } + printf("Request operational state for all slaves\n"); + + /* send one processdata cycle to init SM in slaves */ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* request OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + ain[0] = 0; + ain[1] = 0; + ainc = 0; + dorun = 1; + usleep(100000); // wait for linux to sync on DC + ec_dcsync0(1, TRUE, SYNC0TIME, 0); // SYNC0 on slave 1 + /* acyclic loop 20ms */ + for(i = 1; i <= 200; i++) + { + /* read DC difference register for slave 2 */ + // ec_FPRD(ec_slave[1].configadr, ECT_REG_DCSYSDIFF, sizeof(DCdiff), &DCdiff, EC_TIMEOUTRET); + // if(DCdiff<0) { DCdiff = - (int32)((uint32)DCdiff & 0x7ffffff); } + printf("PD cycle %5d DCtime %12lld Cnt:%3d Data: %6d %6d %6d %6d %6d %6d %6d %6d \n", + cyclecount, ec_DCtime, in_EBOX->counter, in_EBOX->stream[0], in_EBOX->stream[1], + in_EBOX->stream[2], in_EBOX->stream[3], in_EBOX->stream[4], in_EBOX->stream[5], + in_EBOX->stream[98], in_EBOX->stream[99]); + usleep(20000); + } + dorun = 0; + // printf("\nCnt %d : Ain0 = %f Ain2 = %f\n", ainc, ain[0] / ainc, ain[1] / ainc); + } + else + { + printf("Not all slaves reached operational state.\n"); + } + } + else + { + printf("E/BOX not found in slave configuration.\n"); + } + ec_dcsync0(1, FALSE, 8000, 0); // SYNC0 off + printf("Request safe operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_SAFE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + ec_slave[0].state = EC_STATE_PRE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach state */ + ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0)) + { + // restore PDO to standard mode + // this can only be done is pre-op state + os=sizeof(ob2); ob2 = 0x1600; + ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + os=sizeof(ob2); ob2 = 0x1a00; + ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + } + printf("Streampos %d\n", streampos); + output_cvs("stream.txt", streampos); + } + else + { + printf("No slaves found!\n"); + } + printf("End E/BOX, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +/* add ns to timespec */ +void add_timespec(struct timespec *ts, int64 addtime) +{ + int64 sec, nsec; + + nsec = addtime % NSEC_PER_SEC; + sec = (addtime - nsec) / NSEC_PER_SEC; + ts->tv_sec += sec; + ts->tv_nsec += nsec; + if ( ts->tv_nsec > NSEC_PER_SEC ) + { + nsec = ts->tv_nsec % NSEC_PER_SEC; + ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC; + ts->tv_nsec = nsec; + } +} + +/* PI calculation to get linux time synced to DC time */ +void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime) +{ + int64 delta; + /* set linux sync point 50us later than DC sync, just as example */ + delta = (reftime - 50000) % cycletime; + if(delta> (cycletime /2)) { delta= delta - cycletime; } + if(delta>0){ integral++; } + if(delta<0){ integral--; } + *offsettime = -(delta / 100) - (integral /20); +} + +/* RT EtherCAT thread */ +void ecatthread( void *ptr ) +{ + struct timespec ts; + struct timeval tp; + int rc; + int ht; + int i; + int pcounter = 0; + int64 cycletime; + + rc = pthread_mutex_lock(&mutex); + rc = gettimeofday(&tp, NULL); + + /* Convert from timeval to timespec */ + ts.tv_sec = tp.tv_sec; + ht = (tp.tv_usec / 1000) + 1; /* round to nearest ms */ + ts.tv_nsec = ht * 1000000; + cycletime = *(int*)ptr * 1000; /* cycletime in ns */ + toff = 0; + dorun = 0; + while(1) + { + /* calculate next cycle start */ + add_timespec(&ts, cycletime + toff); + /* wait to cycle start */ + rc = pthread_cond_timedwait(&cond, &mutex, &ts); + if (dorun>0) + { + rc = gettimeofday(&tp, NULL); + + ec_send_processdata(); + + ec_receive_processdata(EC_TIMEOUTRET); + + cyclecount++; + + + if((in_EBOX->counter != pcounter) && (streampos < (MAXSTREAM - 1))) + { + // check if we have timing problems in master + // if so, overwrite stream data so it shows up clearly in plots. + if(in_EBOX->counter > (pcounter + 1)) + { + for(i = 0 ; i < 50 ; i++) + { + stream1[streampos] = 20000; + stream2[streampos++] = -20000; + } + } + else + { + for(i = 0 ; i < 50 ; i++) + { + stream1[streampos] = in_EBOX->stream[i * 2]; + stream2[streampos++] = in_EBOX->stream[(i * 2) + 1]; + } + } + pcounter = in_EBOX->counter; + } + + /* calulate toff to get linux time and DC synced */ + ec_sync(ec_DCtime, cycletime, &toff); + } + } +} + +int main(int argc, char *argv[]) +{ + int iret1; + int ctime; + struct sched_param param; + int policy = SCHED_OTHER; + + printf("SOEM (Simple Open EtherCAT Master)\nE/BOX test\n"); + + memset(&schedp, 0, sizeof(schedp)); + /* do not set priority above 49, otherwise sockets are starved */ + schedp.sched_priority = 30; + sched_setscheduler(0, SCHED_FIFO, &schedp); + + do + { + usleep(1000); + } + while (dorun); + + if (argc > 1) + { + dorun = 1; + if( argc > 2) + ctime = atoi(argv[2]); + else + ctime = 1000; // 1ms cycle time + /* create RT thread */ + iret1 = pthread_create( &thread1, NULL, (void *) &ecatthread, (void*) &ctime); + memset(¶m, 0, sizeof(param)); + /* give it higher priority */ + param.sched_priority = 40; + iret1 = pthread_setschedparam(thread1, policy, ¶m); + + /* start acyclic part */ + eboxtest(argv[1]); + } + else + { + printf("Usage: ebox ifname [cycletime]\nifname = eth0 for example\ncycletime in us\n"); + } + + schedp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &schedp); + + printf("End program\n"); + + return (0); +} diff --git a/test/linux/eepromtool/Makefile b/test/linux/eepromtool/Makefile new file mode 100644 index 0000000..afd36b4 --- /dev/null +++ b/test/linux/eepromtool/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = eepromtool + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/eepromtool/eepromtool.c b/test/linux/eepromtool/eepromtool.c new file mode 100644 index 0000000..c3bc4b5 --- /dev/null +++ b/test/linux/eepromtool/eepromtool.c @@ -0,0 +1,485 @@ +/** \file + * \brief EEprom tool for Simple Open EtherCAT master + * + * Usage : eepromtool ifname slave OPTION fname|alias + * ifname is NIC interface, f.e. eth0 + * slave = slave number in EtherCAT order 1..n + * -r read EEPROM, output binary format + * -ri read EEPROM, output Intel Hex format + * -w write EEPROM, input binary format + * -wi write EEPROM, input Intel Hex format + * -i display EEPROM information + * -walias write slave alias in EEPROM + * + * (c)Arthur Ketels 2010-2012 + */ + +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +//#include "ethercatfoe.h" +//#include "ethercatconfig.h" +//#include "ethercatprint.h" + +#define MAXBUF 32768 +#define STDBUF 2048 +#define MINBUF 128 +#define CRCBUF 14 + +#define MODE_NONE 0 +#define MODE_READBIN 1 +#define MODE_READINTEL 2 +#define MODE_WRITEBIN 3 +#define MODE_WRITEINTEL 4 +#define MODE_WRITEALIAS 5 +#define MODE_INFO 6 + +#define MAXSLENGTH 256 + +uint8 ebuf[MAXBUF]; +uint8 ob; +uint16 ow; +int os; +int slave; +int alias; +struct timeval tstart,tend, tdif; +int wkc; +int mode; +char sline[MAXSLENGTH]; + +#define IHEXLENGTH 0x20 + +void calc_crc(uint8 *crc, uint8 b) +{ + int j; + *crc ^= b; + for(j = 0; j <= 7 ; j++ ) + { + if(*crc & 0x80) + *crc = (*crc << 1) ^ 0x07; + else + *crc = (*crc << 1); + } +} + +uint16 SIIcrc(uint8 *buf) +{ + int i; + uint8 crc; + + crc = 0xff; + for( i = 0 ; i <= 13 ; i++ ) + { + calc_crc(&crc , *(buf++)); + } + return (uint16)crc; +} + +int input_bin(char *fname, int *length) +{ + FILE *fp; + + int cc = 0, c; + + fp = fopen(fname, "rb"); + if(fp == NULL) + return 0; + while (((c = fgetc(fp)) != EOF) && (cc < MAXBUF)) + ebuf[cc++] = (uint8)c; + *length = cc; + fclose(fp); + + return 1; +} + +int input_intelhex(char *fname, int *start, int *length) +{ + FILE *fp; + + int c, sc, retval = 1; + int ll, ladr, lt, sn, i, lval; + int hstart, hlength, sum; + + fp = fopen(fname, "r"); + if(fp == NULL) + return 0; + hstart = MAXBUF; + hlength = 0; + sum = 0; + do + { + memset(sline, 0x00, MAXSLENGTH); + sc = 0; + while (((c = fgetc(fp)) != EOF) && (c != 0x0A) && (sc < (MAXSLENGTH -1))) + sline[sc++] = (uint8)c; + if ((c != EOF) && ((sc < 11) || (sline[0] != ':'))) + { + c = EOF; + retval = 0; + printf("Invalid Intel Hex format.\n"); + } + if (c != EOF) + { + sn = sscanf(sline , ":%2x%4x%2x", &ll, &ladr, <); + if ((sn == 3) && ((ladr + ll) <= MAXBUF) && (lt == 0)) + { + sum = ll + (ladr >> 8) + (ladr & 0xff) + lt; + if(ladr < hstart) hstart = ladr; + for(i = 0; i < ll ; i++) + { + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + ebuf[ladr + i] = (uint8)lval; + sum += (uint8)lval; + } + if(((ladr + ll) - hstart) > hlength) + hlength = (ladr + ll) - hstart; + sum = (0x100 - sum) & 0xff; + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + if (!sn || ((sum - lval) != 0)) + { + c = EOF; + retval = 0; + printf("Invalid checksum.\n"); + } + } + } + } + while (c != EOF); + if (retval) + { + *length = hlength; + *start = hstart; + } + fclose(fp); + + return retval; +} + +int output_bin(char *fname, int length) +{ + FILE *fp; + + int cc; + + fp = fopen(fname, "wb"); + if(fp == NULL) + return 0; + for (cc = 0 ; cc < length ; cc++) + fputc( ebuf[cc], fp); + fclose(fp); + + return 1; +} + +int output_intelhex(char *fname, int length) +{ + FILE *fp; + + int cc = 0, ll, sum, i; + + fp = fopen(fname, "w"); + if(fp == NULL) + return 0; + while (cc < length) + { + ll = length - cc; + if (ll > IHEXLENGTH) ll = IHEXLENGTH; + sum = ll + (cc >> 8) + (cc & 0xff); + fprintf(fp, ":%2.2X%4.4X00", ll, cc); + for (i = 0; i < ll; i++) + { + fprintf(fp, "%2.2X", ebuf[cc + i]); + sum += ebuf[cc + i]; + } + fprintf(fp, "%2.2X\n", (0x100 - sum) & 0xff); + cc += ll; + } + fprintf(fp, ":00000001FF\n"); + fclose(fp); + + return 1; +} + +int eeprom_read(int slave, int start, int length) +{ + int i, wkc, ainc = 4; + uint16 estat, aiadr; + uint32 b4; + uint64 b8; + uint8 eepctl; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + estat = 0x0000; + aiadr = 1 - slave; + wkc=ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET); /* read eeprom status */ + estat = etohs(estat); + if (estat & EC_ESTAT_R64) + { + ainc = 8; + for (i = start ; i < (start + length) ; i+=ainc) + { + b8 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = b8; + ebuf[i+1] = b8 >> 8; + ebuf[i+2] = b8 >> 16; + ebuf[i+3] = b8 >> 24; + ebuf[i+4] = b8 >> 32; + ebuf[i+5] = b8 >> 40; + ebuf[i+6] = b8 >> 48; + ebuf[i+7] = b8 >> 56; + } + } + else + { + for (i = start ; i < (start + length) ; i+=ainc) + { + b4 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = b4; + ebuf[i+1] = b4 >> 8; + ebuf[i+2] = b4 >> 16; + ebuf[i+3] = b4 >> 24; + } + } + + return 1; + } + + return 0; +} + +int eeprom_write(int slave, int start, int length) +{ + int i, wkc, dc = 0; + uint16 aiadr, *wbuf; + uint8 eepctl; + int ret; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + aiadr = 1 - slave; + wbuf = (uint16 *)&ebuf[0]; + for (i = start ; i < (start + length) ; i+=2) + { + ret = ec_writeeepromAP(aiadr, i >> 1 , *(wbuf + (i >> 1)), EC_TIMEOUTEEP); + if (++dc >= 100) + { + dc = 0; + printf("."); + fflush(stdout); + } + } + + return 1; + } + + return 0; +} + +int eeprom_writealias(int slave, int alias, uint16 crc) +{ + int wkc; + uint16 aiadr; + uint8 eepctl; + int ret; + + if((ec_slavecount >= slave) && (slave > 0) && (alias <= 0xffff)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ + + ret = ec_writeeepromAP(aiadr, 0x04 , alias, EC_TIMEOUTEEP); + if (ret) + ret = ec_writeeepromAP(aiadr, 0x07 , crc, EC_TIMEOUTEEP); + + return ret; + } + + return 0; +} + +void eepromtool(char *ifname, int slave, int mode, char *fname) +{ + int w, rc = 0, estart, esize; + uint16 *wbuf; + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + + w = 0x0000; + wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE); /* detect number of slaves */ + if (wkc > 0) + { + ec_slavecount = wkc; + + printf("%d slaves found.\n",ec_slavecount); + if((ec_slavecount >= slave) && (slave > 0)) + { + if ((mode == MODE_INFO) || (mode == MODE_READBIN) || (mode == MODE_READINTEL)) + { + rc = gettimeofday(&tstart, NULL); + eeprom_read(slave, 0x0000, MINBUF); // read first 128 bytes + + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d data\n", slave); + printf(" PDI Control : %4.4X\n",*(wbuf + 0x00)); + printf(" PDI Config : %4.4X\n",*(wbuf + 0x01)); + printf(" Config Alias : %4.4X\n",*(wbuf + 0x04)); + printf(" Checksum : %4.4X\n",*(wbuf + 0x07)); + printf(" calculated : %4.4X\n",SIIcrc(&ebuf[0])); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + printf(" Mailbox Protocol : %4.4X\n",*(wbuf + 0x1C)); + esize = (*(wbuf + 0x3E) + 1) * 128; + if (esize > MAXBUF) esize = MAXBUF; + printf(" Size : %4.4X = %d bytes\n",*(wbuf + 0x3E), esize); + printf(" Version : %4.4X\n",*(wbuf + 0x3F)); + } + if ((mode == MODE_READBIN) || (mode == MODE_READINTEL)) + { + if (esize > MINBUF) + eeprom_read(slave, MINBUF, esize - MINBUF); // read reminder + + rc = gettimeofday(&tend, NULL); + timersub(&tend, &tstart, &tdif); + if (mode == MODE_READINTEL) output_intelhex(fname, esize); + if (mode == MODE_READBIN) output_bin(fname, esize); + + printf("\nTotal EEPROM read time :%ldms\n", (tdif.tv_usec+(tdif.tv_sec*1000000L)) / 1000); + } + if ((mode == MODE_WRITEBIN) || (mode == MODE_WRITEINTEL)) + { + estart = 0; + if (mode == MODE_WRITEINTEL) rc = input_intelhex(fname, &estart, &esize); + if (mode == MODE_WRITEBIN) rc = input_bin(fname, &esize); + + if (rc > 0) + { + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d\n", slave); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + + printf("Busy"); + fflush(stdout); + rc = gettimeofday(&tstart, NULL); + eeprom_write(slave, estart, esize); + rc = gettimeofday(&tend, NULL); + timersub(&tend, &tstart, &tdif); + + printf("\nTotal EEPROM write time :%ldms\n", (tdif.tv_usec+(tdif.tv_sec*1000000L)) / 1000); + } + else + printf("Error reading file, abort.\n"); + } + if (mode == MODE_WRITEALIAS) + { + if( eeprom_read(slave, 0x0000, CRCBUF) ) // read first 14 bytes + { + wbuf = (uint16 *)&ebuf[0]; + *(wbuf + 0x04) = alias; + if(eeprom_writealias(slave, alias, SIIcrc(&ebuf[0]))) + { + printf("Alias %4.4X written successfully to slave %d\n", alias, slave); + } + else + { + printf("Alias not written\n"); + } + } + else + { + printf("Could not read slave EEPROM"); + } + } + } + else + { + printf("Slave number outside range.\n"); + } + } + else + { + printf("No slaves found!\n"); + } + printf("End, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nEEPROM tool\n"); + + mode = MODE_NONE; + if (argc > 3) + { + slave = atoi(argv[2]); + if ((strncmp(argv[3], "-i", sizeof("-i")) == 0)) mode = MODE_INFO; + if (argc > 4) + { + if ((strncmp(argv[3], "-r", sizeof("-r")) == 0)) mode = MODE_READBIN; + if ((strncmp(argv[3], "-ri", sizeof("-ri")) == 0)) mode = MODE_READINTEL; + if ((strncmp(argv[3], "-w", sizeof("-w")) == 0)) mode = MODE_WRITEBIN; + if ((strncmp(argv[3], "-wi", sizeof("-wi")) == 0)) mode = MODE_WRITEINTEL; + if ((strncmp(argv[3], "-walias", sizeof("-walias")) == 0)) + { + mode = MODE_WRITEALIAS; + alias = atoi(argv[4]); + } + } + /* start tool */ + eepromtool(argv[1],slave,mode,argv[4]); + } + else + { + printf("Usage: eepromtool ifname slave OPTION fname|alias\n"); + printf("ifname = eth0 for example\n"); + printf("slave = slave number in EtherCAT order 1..n\n"); + printf(" -i display EEPROM information\n"); + printf(" -walias write slave alias\n"); + printf(" -r read EEPROM, output binary format\n"); + printf(" -ri read EEPROM, output Intel Hex format\n"); + printf(" -w write EEPROM, input binary format\n"); + printf(" -wi write EEPROM, input Intel Hex format\n"); + } + + printf("End program\n"); + + return (0); +} diff --git a/test/linux/firm_update/Makefile b/test/linux/firm_update/Makefile new file mode 100644 index 0000000..0b3ec6f --- /dev/null +++ b/test/linux/firm_update/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 178 2012-06-21 11:51:19Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = firm_update + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/firm_update/firm_update.c b/test/linux/firm_update/firm_update.c new file mode 100644 index 0000000..de4ca58 --- /dev/null +++ b/test/linux/firm_update/firm_update.c @@ -0,0 +1,166 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage: firm_update ifname1 slave fname + * ifname is NIC interface, f.e. eth0 + * slave = slave number in EtherCAT order 1..n + * fname = binary file to store in slave + * CAUTION! Using the wrong file can result in a bricked slave! + * + * This is a slave firmware update test. + * + * (c)Arthur Ketels 2011 + */ + +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" + +#define FWBUFSIZE (8 * 1024 * 1024) + +uint8 ob; +uint16 ow; +uint32 data; +char filename[256]; +char filebuffer[FWBUFSIZE]; // 8MB buffer +int filesize; +int j; +uint16 argslave; + +int input_bin(char *fname, int *length) +{ + FILE *fp; + + int cc = 0, c; + + fp = fopen(fname, "rb"); + if(fp == NULL) + return 0; + while (((c = fgetc(fp)) != EOF) && (cc < FWBUFSIZE)) + filebuffer[cc++] = (uint8)c; + *length = cc; + fclose(fp); + return 1; +} + + +void boottest(char *ifname, uint16 slave, char *filename) +{ + printf("Starting firmware update example\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + + + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + printf("Request init state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_INIT; + ec_writestate(slave); + + /* wait for slave to reach INIT state */ + ec_statecheck(slave, EC_STATE_INIT, EC_TIMEOUTSTATE * 4); + printf("Slave %d state to INIT.\n", slave); + + /* read BOOT mailbox data, master -> slave */ + data = ec_readeeprom(slave, ECT_SII_BOOTRXMBX, EC_TIMEOUTEEP); + ec_slave[slave].SM[0].StartAddr = (uint16)LO_WORD(data); + ec_slave[slave].SM[0].SMlength = (uint16)HI_WORD(data); + /* store boot write mailbox address */ + ec_slave[slave].mbx_wo = (uint16)LO_WORD(data); + /* store boot write mailbox size */ + ec_slave[slave].mbx_l = (uint16)HI_WORD(data); + + /* read BOOT mailbox data, slave -> master */ + data = ec_readeeprom(slave, ECT_SII_BOOTTXMBX, EC_TIMEOUTEEP); + ec_slave[slave].SM[1].StartAddr = (uint16)LO_WORD(data); + ec_slave[slave].SM[1].SMlength = (uint16)HI_WORD(data); + /* store boot read mailbox address */ + ec_slave[slave].mbx_ro = (uint16)LO_WORD(data); + /* store boot read mailbox size */ + ec_slave[slave].mbx_rl = (uint16)HI_WORD(data); + + printf(" SM0 A:%4.4x L:%4d F:%8.8x\n", ec_slave[slave].SM[0].StartAddr, ec_slave[slave].SM[0].SMlength, + (int)ec_slave[slave].SM[0].SMflags); + printf(" SM1 A:%4.4x L:%4d F:%8.8x\n", ec_slave[slave].SM[1].StartAddr, ec_slave[slave].SM[1].SMlength, + (int)ec_slave[slave].SM[1].SMflags); + /* program SM0 mailbox in for slave */ + ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM0, sizeof(ec_smt), &ec_slave[slave].SM[0], EC_TIMEOUTRET); + /* program SM1 mailbox out for slave */ + ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET); + + printf("Request BOOT state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_BOOT; + ec_writestate(slave); + + /* wait for slave to reach BOOT state */ + if (ec_statecheck(slave, EC_STATE_BOOT, EC_TIMEOUTSTATE * 10) == EC_STATE_BOOT) + { + printf("Slave %d state to BOOT.\n", slave); + + if (input_bin(filename, &filesize)) + { + printf("File read OK, %d bytes.\n",filesize); + printf("FoE write...."); + j = ec_FOEwrite(slave, filename, 0, filesize , &filebuffer, EC_TIMEOUTSTATE); + printf("result %d.\n",j); + printf("Request init state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_INIT; + ec_writestate(slave); + } + else + printf("File not read OK.\n"); + } + + } + else + { + printf("No slaves found!\n"); + } + printf("End firmware update example, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nFirmware update example\n"); + + if (argc > 3) + { + argslave = atoi(argv[2]); + boottest(argv[1], argslave, argv[3]); + } + else + { + printf("Usage: firm_update ifname1 slave fname\n"); + printf("ifname = eth0 for example\n"); + printf("slave = slave number in EtherCAT order 1..n\n"); + printf("fname = binary file to store in slave\n"); + printf("CAUTION! Using the wrong file can result in a bricked slave!\n"); + } + + printf("End program\n"); + return (0); +} diff --git a/test/linux/red_test/Makefile b/test/linux/red_test/Makefile new file mode 100644 index 0000000..79b2062 --- /dev/null +++ b/test/linux/red_test/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = red_test + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/red_test/red_test.c b/test/linux/red_test/red_test.c new file mode 100644 index 0000000..bb580a2 --- /dev/null +++ b/test/linux/red_test/red_test.c @@ -0,0 +1,343 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : red_test [ifname1] [ifname2] [cycletime] + * ifname is NIC interface, f.e. eth0 + * cycletime in us, f.e. 500 + * + * This is a redundancy test. + * + * (c)Arthur Ketels 2008 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatconfig.h" +#include "ethercatdc.h" +#include "ethercatprint.h" + +#define NSEC_PER_SEC 1000000000 +#define EC_TIMEOUTMON 500 + +struct sched_param schedp; +char IOmap[4096]; +pthread_t thread1, thread2; +struct timeval tv, t1, t2; +int dorun = 0; +int deltat, tmax = 0; +int64 toff, gl_delta; +int DCdiff; +int os; +uint8 ob; +uint16 ob2; +uint8 *digout = 0; +int expectedWKC; +boolean needlf; +volatile int wkc; +boolean inOP; +uint8 currentgroup = 0; + + +void redtest(char *ifname, char *ifname2) +{ + int cnt, i, j, oloop, iloop; + + printf("Starting Redundant test\n"); + + /* initialise SOEM, bind socket to ifname */ +// if (ec_init_redundant(ifname, ifname2)) + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config(FALSE, &IOmap) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + + /* configure DC options for every DC capable slave found in the list */ + ec_configdc(); + + /* read indevidual slave state and store in ec_slave[] */ + ec_readstate(); + for(cnt = 1; cnt <= ec_slavecount ; cnt++) + { + printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + printf(" Out:%8.8x,%4d In:%8.8x,%4d\n", + (int)ec_slave[cnt].outputs, ec_slave[cnt].Obytes, (int)ec_slave[cnt].inputs, ec_slave[cnt].Ibytes); + /* check for EL2004 or EL2008 */ + if( !digout && ((ec_slave[cnt].eep_id == 0x0af83052) || (ec_slave[cnt].eep_id == 0x07d83052))) + { + digout = ec_slave[cnt].outputs; + } + } + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + + printf("Request operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* request OP state for all slaves */ + ec_writestate(0); + /* activate cyclic process data */ + dorun = 1; + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); + oloop = ec_slave[0].Obytes; + if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1; + if (oloop > 8) oloop = 8; + iloop = ec_slave[0].Ibytes; + if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1; + if (iloop > 8) iloop = 8; + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + inOP = TRUE; + /* acyclic loop 5000 x 20ms = 10s */ + for(i = 1; i <= 5000; i++) + { + printf("Processdata cycle %5d , Wck %3d, DCtime %12lld, dt %12lld, O:", + dorun, wkc , ec_DCtime, gl_delta); + for(j = 0 ; j < oloop; j++) + { + printf(" %2.2x", *(ec_slave[0].outputs + j)); + } + printf(" I:"); + for(j = 0 ; j < iloop; j++) + { + printf(" %2.2x", *(ec_slave[0].inputs + j)); + } + printf("\r"); + fflush(stdout); + osal_usleep(20000); + } + dorun = 0; + inOP = FALSE; + } + else + { + printf("Not all slaves reached operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_OPERATIONAL) + { + printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + printf("Request safe operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_SAFE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + } + else + { + printf("No slaves found!\n"); + } + printf("End redundant test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +/* add ns to timespec */ +void add_timespec(struct timespec *ts, int64 addtime) +{ + int64 sec, nsec; + + nsec = addtime % NSEC_PER_SEC; + sec = (addtime - nsec) / NSEC_PER_SEC; + ts->tv_sec += sec; + ts->tv_nsec += nsec; + if ( ts->tv_nsec > NSEC_PER_SEC ) + { + nsec = ts->tv_nsec % NSEC_PER_SEC; + ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC; + ts->tv_nsec = nsec; + } +} + +/* PI calculation to get linux time synced to DC time */ +void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime) +{ + static int64 integral = 0; + int64 delta; + /* set linux sync point 50us later than DC sync, just as example */ + delta = (reftime - 50000) % cycletime; + if(delta> (cycletime / 2)) { delta= delta - cycletime; } + if(delta>0){ integral++; } + if(delta<0){ integral--; } + *offsettime = -(delta / 100) - (integral / 20); + gl_delta = delta; +} + +/* RT EtherCAT thread */ +OSAL_THREAD_FUNC_RT ecatthread(void *ptr) +{ + struct timespec ts, tleft; + struct timeval tp; + int rc; + int ht; + int64 cycletime; + + rc = clock_gettime(CLOCK_MONOTONIC, &ts); + ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */ + ts.tv_nsec = ht * 1000000; + cycletime = *(int*)ptr * 1000; /* cycletime in ns */ + toff = 0; + dorun = 0; + ec_send_processdata(); + while(1) + { + /* calculate next cycle start */ + add_timespec(&ts, cycletime + toff); + /* wait to cycle start */ + rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft); + if (dorun>0) + { + wkc = ec_receive_processdata(EC_TIMEOUTRET); + + dorun++; + /* if we have some digital output, cycle */ + if( digout ) *digout = (uint8) ((dorun / 16) & 0xff); + + if (ec_slave[0].hasdc) + { + /* calulate toff to get linux time and DC synced */ + ec_sync(ec_DCtime, cycletime, &toff); + } + ec_send_processdata(); + } + } +} + +OSAL_THREAD_FUNC ecatcheck( void *ptr ) +{ + int slave; + + while(1) + { + if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)) + { + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > 0) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (!ec_slave[slave].state) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(!ec_slave[slave].state) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); + } + osal_usleep(10000); + } +} + +#define stack64k (64 * 1024) + +int main(int argc, char *argv[]) +{ + int iret1, iret2; + int ctime; + + printf("SOEM (Simple Open EtherCAT Master)\nRedundancy test\n"); + + if (argc > 3) + { + dorun = 0; + ctime = atoi(argv[3]); + + /* create RT thread */ + iret1 = osal_thread_create_rt(&thread1, stack64k * 2, &ecatthread, (void*) &ctime); + + /* create thread to handle slave error handling in OP */ + iret2 = osal_thread_create(&thread2, stack64k * 4, &ecatcheck, NULL); + + /* start acyclic part */ + redtest(argv[1],argv[2]); + } + else + { + printf("Usage: red_test ifname1 ifname2 cycletime\nifname = eth0 for example\ncycletime in us\n"); + } + + printf("End program\n"); + + return (0); +} diff --git a/test/linux/simple_test/Makefile b/test/linux/simple_test/Makefile new file mode 100644 index 0000000..1212f2b --- /dev/null +++ b/test/linux/simple_test/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = simple_test + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/simple_test/simple_test.c b/test/linux/simple_test/simple_test.c new file mode 100644 index 0000000..94b5984 --- /dev/null +++ b/test/linux/simple_test/simple_test.c @@ -0,0 +1,253 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : simple_test [ifname1] + * ifname is NIC interface, f.e. eth0 + * + * This is a minimal test. + * + * (c)Arthur Ketels 2010 - 2011 + */ + +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatdc.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" + +#define EC_TIMEOUTMON 500 + +char IOmap[4096]; +OSAL_THREAD_HANDLE thread1; +int expectedWKC; +boolean needlf; +volatile int wkc; +boolean inOP; +uint8 currentgroup = 0; + +void simpletest(char *ifname) +{ + int i, j, oloop, iloop, wkc_count, chk; + needlf = FALSE; + inOP = FALSE; + + printf("Starting simple test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + + + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + ec_config_map(&IOmap); + + ec_configdc(); + + printf("Slaves mapped, state to SAFE_OP.\n"); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 4); + + oloop = ec_slave[0].Obytes; + if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1; + if (oloop > 8) oloop = 8; + iloop = ec_slave[0].Ibytes; + if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1; + if (iloop > 8) iloop = 8; + + printf("segments : %d : %d %d %d %d\n",ec_group[0].nsegments ,ec_group[0].IOsegment[0],ec_group[0].IOsegment[1],ec_group[0].IOsegment[2],ec_group[0].IOsegment[3]); + + printf("Request operational state for all slaves\n"); + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* send one valid process data to make outputs in slaves happy*/ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + /* request OP state for all slaves */ + ec_writestate(0); + chk = 40; + /* wait for all slaves to reach OP state */ + do + { + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + ec_statecheck(0, EC_STATE_OPERATIONAL, 50000); + } + while (chk-- && (ec_slave[0].state != EC_STATE_OPERATIONAL)); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + wkc_count = 0; + inOP = TRUE; + /* cyclic loop */ + for(i = 1; i <= 10000; i++) + { + ec_send_processdata(); + wkc = ec_receive_processdata(EC_TIMEOUTRET); + + if(wkc >= expectedWKC) + { + printf("Processdata cycle %4d, WKC %d , O:", i, wkc); + + for(j = 0 ; j < oloop; j++) + { + printf(" %2.2x", *(ec_slave[0].outputs + j)); + } + + printf(" I:"); + for(j = 0 ; j < iloop; j++) + { + printf(" %2.2x", *(ec_slave[0].inputs + j)); + } + printf(" T:%lld\r",ec_DCtime); + needlf = TRUE; + } + usleep(5000); + + } + inOP = FALSE; + } + else + { + printf("Not all slaves reached operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_OPERATIONAL) + { + printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + printf("\nRequest init state for all slaves\n"); + ec_slave[0].state = EC_STATE_INIT; + /* request INIT state for all slaves */ + ec_writestate(0); + } + else + { + printf("No slaves found!\n"); + } + printf("End simple test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +OSAL_THREAD_FUNC ecatcheck( void *ptr ) +{ + int slave; + + while(1) + { + if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)) + { + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > 0) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (!ec_slave[slave].state) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(!ec_slave[slave].state) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); + } + usleep(10000); + } +} + +int main(int argc, char *argv[]) +{ + int iret1; + printf("SOEM (Simple Open EtherCAT Master)\nSimple test\n"); + + if (argc > 1) + { + /* create thread to handle slave error handling in OP */ +// iret1 = pthread_create( &thread1, NULL, (void *) &ecatcheck, (void*) &ctime); + osal_thread_create(&thread1, 128000, &ecatcheck, (void*) &ctime); + /* start cyclic part */ + simpletest(argv[1]); + } + else + { + printf("Usage: simple_test ifname1\nifname = eth0 for example\n"); + } + + printf("End program\n"); + return (0); +} diff --git a/test/linux/slaveinfo/Makefile b/test/linux/slaveinfo/Makefile new file mode 100644 index 0000000..124d89e --- /dev/null +++ b/test/linux/slaveinfo/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 125 2012-04-01 17:36:17Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = slaveinfo + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/linux/slaveinfo/slaveinfo.c b/test/linux/slaveinfo/slaveinfo.c new file mode 100644 index 0000000..b74f00c --- /dev/null +++ b/test/linux/slaveinfo/slaveinfo.c @@ -0,0 +1,640 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : slaveinfo [ifname] [-sdo] [-map] + * Ifname is NIC interface, f.e. eth0. + * Optional -sdo to display CoE object dictionary. + * Optional -map to display slave PDO mapping + * + * This shows the configured slave data. + * + * (c)Arthur Ketels 2010 - 2011 + */ + +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatconfig.h" +#include "ethercatcoe.h" +#include "ethercatdc.h" +#include "ethercatprint.h" + +char IOmap[4096]; +ec_ODlistt ODlist; +ec_OElistt OElist; +boolean printSDO = FALSE; +boolean printMAP = FALSE; +char usdo[128]; +char hstr[1024]; + +char* dtype2string(uint16 dtype) +{ + switch(dtype) + { + case ECT_BOOLEAN: + sprintf(hstr, "BOOLEAN"); + break; + case ECT_INTEGER8: + sprintf(hstr, "INTEGER8"); + break; + case ECT_INTEGER16: + sprintf(hstr, "INTEGER16"); + break; + case ECT_INTEGER32: + sprintf(hstr, "INTEGER32"); + break; + case ECT_INTEGER24: + sprintf(hstr, "INTEGER24"); + break; + case ECT_INTEGER64: + sprintf(hstr, "INTEGER64"); + break; + case ECT_UNSIGNED8: + sprintf(hstr, "UNSIGNED8"); + break; + case ECT_UNSIGNED16: + sprintf(hstr, "UNSIGNED16"); + break; + case ECT_UNSIGNED32: + sprintf(hstr, "UNSIGNED32"); + break; + case ECT_UNSIGNED24: + sprintf(hstr, "UNSIGNED24"); + break; + case ECT_UNSIGNED64: + sprintf(hstr, "UNSIGNED64"); + break; + case ECT_REAL32: + sprintf(hstr, "REAL32"); + break; + case ECT_REAL64: + sprintf(hstr, "REAL64"); + break; + case ECT_BIT1: + sprintf(hstr, "BIT1"); + break; + case ECT_BIT2: + sprintf(hstr, "BIT2"); + break; + case ECT_BIT3: + sprintf(hstr, "BIT3"); + break; + case ECT_BIT4: + sprintf(hstr, "BIT4"); + break; + case ECT_BIT5: + sprintf(hstr, "BIT5"); + break; + case ECT_BIT6: + sprintf(hstr, "BIT6"); + break; + case ECT_BIT7: + sprintf(hstr, "BIT7"); + break; + case ECT_BIT8: + sprintf(hstr, "BIT8"); + break; + case ECT_VISIBLE_STRING: + sprintf(hstr, "VISIBLE_STRING"); + break; + case ECT_OCTET_STRING: + sprintf(hstr, "OCTET_STRING"); + break; + default: + sprintf(hstr, "Type 0x%4.4X", dtype); + } + return hstr; +} + +char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype) +{ + int l = sizeof(usdo) - 1, i; + uint8 *u8; + int8 *i8; + uint16 *u16; + int16 *i16; + uint32 *u32; + int32 *i32; + uint64 *u64; + int64 *i64; + float *sr; + double *dr; + char es[32]; + + memset(&usdo, 0, 128); + ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM); + if (EcatError) + { + return ec_elist2string(); + } + else + { + switch(dtype) + { + case ECT_BOOLEAN: + u8 = (uint8*) &usdo[0]; + if (*u8) sprintf(hstr, "TRUE"); + else sprintf(hstr, "FALSE"); + break; + case ECT_INTEGER8: + i8 = (int8*) &usdo[0]; + sprintf(hstr, "0x%2.2x %d", *i8, *i8); + break; + case ECT_INTEGER16: + i16 = (int16*) &usdo[0]; + sprintf(hstr, "0x%4.4x %d", *i16, *i16); + break; + case ECT_INTEGER32: + case ECT_INTEGER24: + i32 = (int32*) &usdo[0]; + sprintf(hstr, "0x%8.8x %d", *i32, *i32); + break; + case ECT_INTEGER64: + i64 = (int64*) &usdo[0]; + sprintf(hstr, "0x%16.16llx %lld", *i64, *i64); + break; + case ECT_UNSIGNED8: + u8 = (uint8*) &usdo[0]; + sprintf(hstr, "0x%2.2x %u", *u8, *u8); + break; + case ECT_UNSIGNED16: + u16 = (uint16*) &usdo[0]; + sprintf(hstr, "0x%4.4x %u", *u16, *u16); + break; + case ECT_UNSIGNED32: + case ECT_UNSIGNED24: + u32 = (uint32*) &usdo[0]; + sprintf(hstr, "0x%8.8x %u", *u32, *u32); + break; + case ECT_UNSIGNED64: + u64 = (uint64*) &usdo[0]; + sprintf(hstr, "0x%16.16llx %llu", *u64, *u64); + break; + case ECT_REAL32: + sr = (float*) &usdo[0]; + sprintf(hstr, "%f", *sr); + break; + case ECT_REAL64: + dr = (double*) &usdo[0]; + sprintf(hstr, "%f", *dr); + break; + case ECT_BIT1: + case ECT_BIT2: + case ECT_BIT3: + case ECT_BIT4: + case ECT_BIT5: + case ECT_BIT6: + case ECT_BIT7: + case ECT_BIT8: + u8 = (uint8*) &usdo[0]; + sprintf(hstr, "0x%x", *u8); + break; + case ECT_VISIBLE_STRING: + strcpy(hstr, usdo); + break; + case ECT_OCTET_STRING: + hstr[0] = 0x00; + for (i = 0 ; i < l ; i++) + { + sprintf(es, "0x%2.2x ", usdo[i]); + strcat( hstr, es); + } + break; + default: + sprintf(hstr, "Unknown type"); + } + return hstr; + } +} + +/** Read PDO assign structure */ +int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset) +{ + uint16 idxloop, nidx, subidxloop, rdat, idx, subidx; + uint8 subcnt; + int wkc, bsize = 0, rdl; + int32 rdat2; + uint8 bitlen, obj_subidx; + uint16 obj_idx; + int abs_offset, abs_bit; + + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign subindex 0 ( = number of PDO's) */ + wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + rdat = etohs(rdat); + /* positive result from slave ? */ + if ((wkc > 0) && (rdat > 0)) + { + /* number of available sub indexes */ + nidx = rdat; + bsize = 0; + /* read all PDO's */ + for (idxloop = 1; idxloop <= nidx; idxloop++) + { + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign */ + wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + /* result is index of PDO */ + idx = etohl(rdat); + if (idx > 0) + { + rdl = sizeof(subcnt); subcnt = 0; + /* read number of subindexes of PDO */ + wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM); + subidx = subcnt; + /* for each subindex */ + for (subidxloop = 1; subidxloop <= subidx; subidxloop++) + { + rdl = sizeof(rdat2); rdat2 = 0; + /* read SDO that is mapped in PDO */ + wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM); + rdat2 = etohl(rdat2); + /* extract bitlength of SDO */ + bitlen = LO_BYTE(rdat2); + bsize += bitlen; + obj_idx = (uint16)(rdat2 >> 16); + obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff); + abs_offset = mapoffset + (bitoffset / 8); + abs_bit = bitoffset % 8; + ODlist.Slave = slave; + ODlist.Index[0] = obj_idx; + OElist.Entries = 0; + wkc = 0; + /* read object entry from dictionary if not a filler (0x0000:0x00) */ + if(obj_idx || obj_subidx) + wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist); + printf(" [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen); + if((wkc > 0) && OElist.Entries) + { + printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]); + } + else + printf("\n"); + bitoffset += bitlen; + }; + }; + }; + }; + /* return total found bitlength (PDO) */ + return bsize; +} + +int si_map_sdo(int slave) +{ + int wkc, rdl; + int retVal = 0; + uint8 nSM, iSM, tSM; + int Tsize, outputs_bo, inputs_bo; + uint8 SMt_bug_add; + + printf("PDO mapping according to CoE :\n"); + SMt_bug_add = 0; + outputs_bo = 0; + inputs_bo = 0; + rdl = sizeof(nSM); nSM = 0; + /* read SyncManager Communication Type object count */ + wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM); + /* positive result from slave ? */ + if ((wkc > 0) && (nSM > 2)) + { + /* make nSM equal to number of defined SM */ + nSM--; + /* limit to maximum number of SM defined, if true the slave can't be configured */ + if (nSM > EC_MAXSM) + nSM = EC_MAXSM; + /* iterate for every SM type defined */ + for (iSM = 2 ; iSM <= nSM ; iSM++) + { + rdl = sizeof(tSM); tSM = 0; + /* read SyncManager Communication Type */ + wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM); + if (wkc > 0) + { + if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave! + { + SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4 + printf("Activated SM type workaround, possible incorrect mapping.\n"); + } + if(tSM) + tSM += SMt_bug_add; // only add if SMt > 0 + + if (tSM == 3) // outputs + { + /* read the assign RXPDO */ + printf(" SM%1d outputs\n addr b index: sub bitl data_type name\n", iSM); + Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo ); + outputs_bo += Tsize; + } + if (tSM == 4) // inputs + { + /* read the assign TXPDO */ + printf(" SM%1d inputs\n addr b index: sub bitl data_type name\n", iSM); + Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo ); + inputs_bo += Tsize; + } + } + } + } + + /* found some I/O bits ? */ + if ((outputs_bo > 0) || (inputs_bo > 0)) + retVal = 1; + return retVal; +} + +int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset) +{ + uint16 a , w, c, e, er, Size; + uint8 eectl; + uint16 obj_idx; + uint8 obj_subidx; + uint8 obj_name; + uint8 obj_datatype; + uint8 bitlen; + int totalsize; + ec_eepromPDOt eepPDO; + ec_eepromPDOt *PDO; + int abs_offset, abs_bit; + char str_name[EC_MAXNAME + 1]; + + eectl = ec_slave[slave].eep_pdi; + Size = 0; + totalsize = 0; + PDO = &eepPDO; + PDO->nPDO = 0; + PDO->Length = 0; + PDO->Index[1] = 0; + for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0; + if (t > 1) + t = 1; + PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t); + if (PDO->Startpos > 0) + { + a = PDO->Startpos; + w = ec_siigetbyte(slave, a++); + w += (ec_siigetbyte(slave, a++) << 8); + PDO->Length = w; + c = 1; + /* traverse through all PDOs */ + do + { + PDO->nPDO++; + PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++); + PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8); + PDO->BitSize[PDO->nPDO] = 0; + c++; + /* number of entries in PDO */ + e = ec_siigetbyte(slave, a++); + PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++); + a++; + obj_name = ec_siigetbyte(slave, a++); + a += 2; + c += 2; + if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */ + { + str_name[0] = 0; + if(obj_name) + ec_siistring(str_name, slave, obj_name); + if (t) + printf(" SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name); + else + printf(" SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name); + printf(" addr b index: sub bitl data_type name\n"); + /* read all entries defined in PDO */ + for (er = 1; er <= e; er++) + { + c += 4; + obj_idx = ec_siigetbyte(slave, a++); + obj_idx += (ec_siigetbyte(slave, a++) << 8); + obj_subidx = ec_siigetbyte(slave, a++); + obj_name = ec_siigetbyte(slave, a++); + obj_datatype = ec_siigetbyte(slave, a++); + bitlen = ec_siigetbyte(slave, a++); + abs_offset = mapoffset + (bitoffset / 8); + abs_bit = bitoffset % 8; + + PDO->BitSize[PDO->nPDO] += bitlen; + a += 2; + + str_name[0] = 0; + if(obj_name) + ec_siistring(str_name, slave, obj_name); + + printf(" [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen); + printf(" %-12s %s\n", dtype2string(obj_datatype), str_name); + bitoffset += bitlen; + totalsize += bitlen; + } + PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO]; + Size += PDO->BitSize[PDO->nPDO]; + c++; + } + else /* PDO deactivated because SM is 0xff or > EC_MAXSM */ + { + c += 4 * e; + a += 8 * e; + c++; + } + if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */ + } + while (c < PDO->Length); + } + if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */ + return totalsize; +} + + +int si_map_sii(int slave) +{ + int retVal = 0; + int Tsize, outputs_bo, inputs_bo; + + printf("PDO mapping according to SII :\n"); + + outputs_bo = 0; + inputs_bo = 0; + /* read the assign RXPDOs */ + Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo ); + outputs_bo += Tsize; + /* read the assign TXPDOs */ + Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo ); + inputs_bo += Tsize; + /* found some I/O bits ? */ + if ((outputs_bo > 0) || (inputs_bo > 0)) + retVal = 1; + return retVal; +} + +void si_sdo(int cnt) +{ + int i, j; + + ODlist.Entries = 0; + memset(&ODlist, 0, sizeof(ODlist)); + if( ec_readODlist(cnt, &ODlist)) + { + printf(" CoE Object Description found, %d entries.\n",ODlist.Entries); + for( i = 0 ; i < ODlist.Entries ; i++) + { + ec_readODdescription(i, &ODlist); + while(EcatError) printf("%s", ec_elist2string()); + printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n", + ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]); + memset(&OElist, 0, sizeof(OElist)); + ec_readOE(i, &ODlist, &OElist); + while(EcatError) printf("%s", ec_elist2string()); + for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++) + { + if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0)) + { + printf(" Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n", + j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]); + if ((OElist.ObjAccess[j] & 0x0007)) + { + printf(" Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j])); + } + } + } + } + } + else + { + while(EcatError) printf("%s", ec_elist2string()); + } +} + +void slaveinfo(char *ifname) +{ + int cnt, i, j, nSM; + uint16 ssigen; + int expectedWKC; + + printf("Starting slaveinfo\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config(FALSE, &IOmap) > 0 ) + { + ec_configdc(); + while(EcatError) printf("%s", ec_elist2string()); + printf("%d slaves found and configured.\n",ec_slavecount); + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 3); + if (ec_slave[0].state != EC_STATE_SAFE_OP ) + { + printf("Not all slaves reached safe operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_SAFE_OP) + { + printf("Slave %d State=%2x StatusCode=%4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + + + ec_readstate(); + for( cnt = 1 ; cnt <= ec_slavecount ; cnt++) + { + printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport); + printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 , + (ec_slave[cnt].activeports & 0x02) > 0 , + (ec_slave[cnt].activeports & 0x04) > 0 , + (ec_slave[cnt].activeports & 0x08) > 0 ); + printf(" Configured address: %4.4x\n", ec_slave[cnt].configadr); + printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev); + for(nSM = 0 ; nSM < EC_MAXSM ; nSM++) + { + if(ec_slave[cnt].SM[nSM].StartAddr > 0) + printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, ec_slave[cnt].SM[nSM].StartAddr, ec_slave[cnt].SM[nSM].SMlength, + (int)ec_slave[cnt].SM[nSM].SMflags, ec_slave[cnt].SMtype[nSM]); + } + for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++) + { + printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j, + (int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit, + ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit, + ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive); + } + printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n", + ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func); + printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto); + ssigen = ec_siifind(cnt, ECT_SII_GENERAL); + /* SII general section */ + if (ssigen) + { + ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07); + ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08); + ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09); + ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a); + if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0) + { + ec_slave[cnt].blockLRW = 1; + ec_slave[0].blockLRW++; + } + ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e); + ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8; + ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent; + } + printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n", + ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails); + printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n", + ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW); + if ((ec_slave[cnt].mbx_proto & 0x04) && printSDO) + si_sdo(cnt); + if(printMAP) + { + if (ec_slave[cnt].mbx_proto & 0x04) + si_map_sdo(cnt); + else + si_map_sii(cnt); + } + } + } + else + { + printf("No slaves found!\n"); + } + printf("End slaveinfo, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nSlaveinfo\n"); + + if (argc > 1) + { + if ((argc > 2) && (strncmp(argv[2], "-sdo", sizeof("-sdo")) == 0)) printSDO = TRUE; + if ((argc > 2) && (strncmp(argv[2], "-map", sizeof("-map")) == 0)) printMAP = TRUE; + /* start slaveinfo */ + slaveinfo(argv[1]); + } + else + { + printf("Usage: slaveinfo ifname [options]\nifname = eth0 for example\nOptions :\n -sdo : print SDO info\n -map : print mapping\n"); + } + + printf("End program\n"); + return (0); +} diff --git a/test/rtk/main.c b/test/rtk/main.c new file mode 100644 index 0000000..47f6847 --- /dev/null +++ b/test/rtk/main.c @@ -0,0 +1,525 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * This is a minimal example running rt-kernel TTOS. Check + * tutorial files in documentations for som steps to get your + * system running. + * (c)Andreas Karlsson 2012 + */ + +#include +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" +#include "string.h" +#include +#include + +#include + +#define pPORTFIO_SET ((vuint16_t *)PORTFIO_SET) +#define pPORTFIO_CLEAR ((vuint16_t *)PORTFIO_CLEAR) +#define pPORTFIO_DIR ((vuint16_t *)PORTFIO_DIR) + +#define EK1100_1 1 +#define EL4001_1 2 +#define EL3061_1 3 +#define EL1008_1 4 +#define EL1008_2 5 +#define EL2622_1 6 +#define EL2622_2 7 +#define EL2622_3 8 +#define EL2622_4 9 +#define NUMBER_OF_SLAVES 9 + + +typedef struct +{ + uint8 in1; + uint8 in2; + uint8 in3; + uint8 in4; + uint8 in5; + uint8 in6; + uint8 in7; + uint8 in8; +} in_EL1008_t; + +typedef struct +{ + uint8 out1; + uint8 out2; +} out_EL2622_t; + +typedef struct +{ + int16 out1; +} out_EL4001_t; + +typedef struct +{ + int32 in1; +} in_EL3061_t; + +out_EL4001_t slave_EL4001_1; +in_EL3061_t slave_EL3061_1; +in_EL1008_t slave_EL1008_1; +in_EL1008_t slave_EL1008_2; +out_EL2622_t slave_EL2622_1; +out_EL2622_t slave_EL2622_2; +out_EL2622_t slave_EL2622_3; + +uint32 network_configuration(void) +{ + /* Do we got expected number of slaves from config */ + if (ec_slavecount < NUMBER_OF_SLAVES) + return 0; + + /* Verify slave by slave that it is correct*/ + if (strcmp(ec_slave[EK1100_1].name,"EK1100")) + return 0; + else if (strcmp(ec_slave[EL4001_1].name,"EL4001")) + return 0; + else if (strcmp(ec_slave[EL3061_1].name,"EL3061")) + return 0; + else if (strcmp(ec_slave[EL1008_1].name,"EL1008")) + return 0; + else if (strcmp(ec_slave[EL1008_2].name,"EL1008")) + return 0; + else if (strcmp(ec_slave[EL2622_1].name,"EL2622")) + return 0; + else if (strcmp(ec_slave[EL2622_2].name,"EL2622")) + return 0; + else if (strcmp(ec_slave[EL2622_3].name,"EL2622")) + return 0; + else if (strcmp(ec_slave[EL2622_4].name,"EL2622")) + return 0; + + return 1; +} + +int32 get_input_int32(uint16 slave_no,uint8 module_index) +{ + int32 return_value; + uint8 *data_ptr; + /* Get the IO map pointer from the ec_slave struct */ + data_ptr = ec_slave[slave_no].inputs; + /* Move pointer to correct module index */ + data_ptr += module_index * 4; + /* Read value byte by byte since all targets can't handle misaligned + * addresses + */ + return_value = *data_ptr++; + return_value += (*data_ptr++ << 8); + return_value += (*data_ptr++ << 16); + return_value += (*data_ptr++ << 24); + + return return_value; +} + +void set_input_int32 (uint16 slave_no, uint8 module_index, int32 value) +{ + uint8 *data_ptr; + /* Get the IO map pointer from the ec_slave struct */ + data_ptr = ec_slave[slave_no].inputs; + /* Move pointer to correct module index */ + data_ptr += module_index * 4; + /* Read value byte by byte since all targets can handle misaligned + * addresses + */ + *data_ptr++ = (value >> 0) & 0xFF; + *data_ptr++ = (value >> 8) & 0xFF; + *data_ptr++ = (value >> 16) & 0xFF; + *data_ptr++ = (value >> 24) & 0xFF; +} + +uint8 get_input_bit (uint16 slave_no,uint8 module_index) +{ + /* Get the the startbit position in slaves IO byte */ + uint8 startbit = ec_slave[slave_no].Istartbit; + /* Mask bit and return boolean 0 or 1 */ + if (*ec_slave[slave_no].inputs & BIT (module_index - 1 + startbit)) + return 1; + else + return 0; +} + +int16 get_output_int16(uint16 slave_no,uint8 module_index) +{ + int16 return_value; + uint8 *data_ptr; + + /* Get the IO map pointer from the ec_slave struct */ + data_ptr = ec_slave[slave_no].outputs; + /* Move pointer to correct module index */ + data_ptr += module_index * 2; + /* Read value byte by byte since all targets can handle misaligned + * addresses + */ + return_value = *data_ptr++; + return_value += (*data_ptr++ << 8); + + return return_value; +} + +void set_output_int16 (uint16 slave_no, uint8 module_index, int16 value) +{ + uint8 *data_ptr; + /* Get the IO map pointer from the ec_slave struct */ + data_ptr = ec_slave[slave_no].outputs; + /* Move pointer to correct module index */ + data_ptr += module_index * 2; + /* Read value byte by byte since all targets can handle misaligned + * addresses + */ + *data_ptr++ = (value >> 0) & 0xFF; + *data_ptr++ = (value >> 8) & 0xFF; +} + +uint8 get_output_bit (uint16 slave_no,uint8 module_index) +{ + /* Get the the startbit position in slaves IO byte */ + uint8 startbit = ec_slave[slave_no].Ostartbit; + /* Mask bit and return boolean 0 or 1 */ + if (*ec_slave[slave_no].outputs & BIT (module_index - 1 + startbit)) + return 1; + else + return 0; +} + +void set_output_bit (uint16 slave_no, uint8 module_index, uint8 value) +{ + /* Get the the startbit position in slaves IO byte */ + uint8 startbit = ec_slave[slave_no].Ostartbit; + /* Set or Clear bit */ + if (value == 0) + *ec_slave[slave_no].outputs &= ~(1 << (module_index - 1 + startbit)); + else + *ec_slave[slave_no].outputs |= (1 << (module_index - 1 + startbit)); +} + + +extern tt_sched_t * tt_sched[]; + +char IOmap[128]; +int dorun = 0; + +uint8_t load1s, load5s, load10s; +uint32_t error_counter = 0; + +void tt_error (uint32_t task_ix); +void tt_error (uint32_t task_ix) +{ + error_counter++; +} + +static void my_cyclic_callback (void * arg) +{ + while (1) + { + stats_get_load (&load1s, &load5s, &load10s); + rprintp ("Processor load was %d:%d:%d (1s:5s:10s) with TT errors: %d\n", + load1s, load5s, load10s,error_counter); + task_delay(20000); + } +} + + +void read_io (void * arg) +{ + /* Function connected to cyclic TTOS task + * The function is executed cyclic according + * sceduel specified in schedule.tt + */ + *pPORTFIO_SET = BIT (6); + /* Send and receive processdata + * Note that you need som synchronization + * case you modifey IO in local application + */ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + *pPORTFIO_CLEAR = BIT (6); +} + + +void simpletest(void *arg) +{ + + char *ifname = arg; + int cnt, i, j; + + *pPORTFIO_DIR |= BIT (6); + + rprintp("Starting simple test\n"); + + /* initialise SOEM */ + if (ec_init(ifname)) + { + rprintp("ec_init succeeded.\n"); + + /* find and auto-config slaves */ + if ( ec_config_init(FALSE) > 0 ) + { + rprintp("%d slaves found and configured.\n",ec_slavecount); + + /* Check network setup */ + if (network_configuration()) + { + /* Run IO mapping */ + ec_config_map(&IOmap); + + rprintp("Slaves mapped, state to SAFE_OP.\n"); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + + /* Print som information on the mapped network */ + for( cnt = 1 ; cnt <= ec_slavecount ; cnt++) + { + rprintp("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + rprintp(" Configured address: %x\n", ec_slave[cnt].configadr); + rprintp(" Outputs address: %x\n", ec_slave[cnt].outputs); + rprintp(" Inputs address: %x\n", ec_slave[cnt].inputs); + + for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++) + { + rprintp(" FMMU%1d Ls:%x Ll:%4d Lsb:%d Leb:%d Ps:%x Psb:%d Ty:%x Act:%x\n", j, + (int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit, + ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit, + ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive); + } + rprintp(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n", + ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func); + + } + + rprintp("Request operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* send one valid process data to make outputs in slaves happy*/ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + /* request OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + rprintp("Operational state reached for all slaves.\n"); + } + else + { + rprintp("Not all slaves reached operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_OPERATIONAL) + { + rprintp("Slave %d State=0x%04x StatusCode=0x%04x\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode); + } + } + } + + + /* Simple blinking lamps BOX demo */ + uint8 digout = 0; + + slave_EL4001_1.out1 = (int16)0x3FFF; + set_output_int16(EL4001_1,0,slave_EL4001_1.out1); + + task_spawn ("t_StatsPrint", my_cyclic_callback, 20, 1024, (void *)NULL); + tt_start_wait (tt_sched[0]); + + while(1) + { + dorun = 0; + slave_EL1008_1.in1 = get_input_bit(EL1008_1,1); // Start button + slave_EL1008_1.in2 = get_input_bit(EL1008_1,2); // Turnkey RIGHT + slave_EL1008_1.in3 = get_input_bit(EL1008_1,3); // Turnkey LEFT + + /* (Turnkey MIDDLE + Start button) OR Turnkey RIGHT OR Turnkey LEFT + Turnkey LEFT: Light positions bottom to top. Loop, slow operation. + Turnkey MIDDLE: Press start button to light positions bottom to top. No loop, fast operation. + Turnkey RIGHT: Light positions bottom to top. Loop, fast operation. + */ + if (slave_EL1008_1.in1 || slave_EL1008_1.in2 || slave_EL1008_1.in3) + { + digout = 0; + /* *ec_slave[6].outputs = digout; */ + /* set_output_bit(slave_name #,index as 1 output on module , value */ + set_output_bit(EL2622_1,1,(digout & BIT (0))); /* Start button */ + set_output_bit(EL2622_1,2,(digout & BIT (1))); /* Turnkey RIGHT */ + set_output_bit(EL2622_2,1,(digout & BIT (2))); /* Turnkey LEFT */ + set_output_bit(EL2622_2,2,(digout & BIT (3))); + set_output_bit(EL2622_3,1,(digout & BIT (4))); + set_output_bit(EL2622_3,2,(digout & BIT (5))); + + while(dorun < 95) + { + dorun++; + + if (slave_EL1008_1.in3) + task_delay(tick_from_ms(20)); + else + task_delay(tick_from_ms(5)); + + digout = (uint8) (digout | BIT((dorun / 16) & 0xFF)); + + set_output_bit(EL2622_1,1,(digout & BIT (0))); /* LED1 */ + set_output_bit(EL2622_1,2,(digout & BIT (1))); /* LED2 */ + set_output_bit(EL2622_2,1,(digout & BIT (2))); /* LED3 */ + set_output_bit(EL2622_2,2,(digout & BIT (3))); /* LED4 */ + set_output_bit(EL2622_3,1,(digout & BIT (4))); /* LED5 */ + set_output_bit(EL2622_3,2,(digout & BIT (5))); /* LED6 */ + + slave_EL1008_1.in1 = get_input_bit(EL1008_1,2); /* Turnkey RIGHT */ + slave_EL1008_1.in2 = get_input_bit(EL1008_1,3); /* Turnkey LEFT */ + slave_EL3061_1.in1 = get_input_int32(EL3061_1,0); /* Read AI */ + } + } + task_delay(tick_from_ms(2)); + + } + } + else + { + rprintp("Mismatch of network units!\n"); + } + } + else + { + rprintp("No slaves found!\n"); + } + rprintp("End simple test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + rprintp("ec_init failed"); + } + rprintp("End program\n"); +} + +static void test_osal_timer_timeout_us (const uint32 timeout_us) +{ + osal_timert timer; + + ASSERT (timeout_us > 4000); + + osal_timer_start (&timer, timeout_us); + ASSERT (osal_timer_is_expired (&timer) == false); + osal_usleep (timeout_us - 2000); + ASSERT (osal_timer_is_expired (&timer) == false); + osal_usleep (4000); + ASSERT (osal_timer_is_expired (&timer)); +} + +static void test_osal_timer (void) +{ + test_osal_timer_timeout_us (10*1000); /* 10ms */ + test_osal_timer_timeout_us (100*1000); /* 100ms */ + test_osal_timer_timeout_us (1000*1000); /* 1s */ + test_osal_timer_timeout_us (2000*1000); /* 2s */ +} + +#define USECS_PER_SEC 1000000 +#define USECS_PER_TICK (USECS_PER_SEC / CFG_TICKS_PER_SECOND) +#ifndef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#endif + +static int32 time_difference_us (const ec_timet stop, const ec_timet start) +{ + int32 difference_us; + + ASSERT (stop.sec >= start.sec); + if (stop.sec == start.sec) + { + ASSERT (stop.usec >= start.usec); + } + + difference_us = (stop.sec - start.sec) * USECS_PER_SEC; + difference_us += ((int32)stop.usec - (int32)start.usec); + + ASSERT (difference_us >= 0); + return difference_us; +} + +/** + * Test osal_current_time() by using it for measuring how long an osal_usleep() + * takes, in specified number of microseconds. + */ +static void test_osal_current_time_for_delay_us (const int32 sleep_time_us) +{ + ec_timet start; + ec_timet stop; + int32 measurement_us; + int32 deviation_us; + const int32 usleep_accuracy_us = USECS_PER_TICK; + boolean is_deviation_within_tolerance; + + start = osal_current_time (); + osal_usleep (sleep_time_us); + stop = osal_current_time (); + + measurement_us = time_difference_us (stop, start); + deviation_us = ABS (measurement_us - sleep_time_us); + is_deviation_within_tolerance = deviation_us <= usleep_accuracy_us; + ASSERT (is_deviation_within_tolerance); +} + +static void test_osal_current_time (void) +{ + test_osal_current_time_for_delay_us (0); + test_osal_current_time_for_delay_us (1); + test_osal_current_time_for_delay_us (500); + test_osal_current_time_for_delay_us (999); + test_osal_current_time_for_delay_us (USECS_PER_TICK); + test_osal_current_time_for_delay_us (USECS_PER_TICK-1); + test_osal_current_time_for_delay_us (USECS_PER_TICK+1); + test_osal_current_time_for_delay_us (2 * 1000 * 1000); /* 2s */ +} + +#include + +static void test_oshw_htons (void) +{ + uint16 network; + uint16 host; + + host = 0x1234; + network = oshw_htons (host); + ASSERT (network == htons (host)); +} + +static void test_oshw_ntohs (void) +{ + uint16 host; + uint16 network; + + network = 0x1234; + host = oshw_ntohs (network); + ASSERT (host == ntohs (network)); +} + +int main (void) +{ + test_oshw_htons (); + test_oshw_ntohs (); + test_osal_timer (); + test_osal_current_time (); + + rprintp("SOEM (Simple Open EtherCAT Master)\nSimple test\n"); + + task_spawn ("simpletest", simpletest, 9, 8192, NULL); + + return (0); +} + diff --git a/test/rtk/schedule.tt b/test/rtk/schedule.tt new file mode 100644 index 0000000..dd9fce1 --- /dev/null +++ b/test/rtk/schedule.tt @@ -0,0 +1,14 @@ +stack_size: 2048 + +tasks: + - name : tReadIO + entry : read_io + arg : 'NULL' + +schedules: + - name : sched1 + period : 1 + events : + - task : tReadIO + start : 0 + stop : 1 \ No newline at end of file diff --git a/test/win32/Makefile b/test/win32/Makefile new file mode 100644 index 0000000..93a4c86 --- /dev/null +++ b/test/win32/Makefile @@ -0,0 +1,33 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +SUBDIRS = ebox eepromtool red_test simple_test slaveinfo firm_update + +all: subdirs + +subdirs: + @for dir in $(SUBDIRS); do \ + ($(MAKE) -C $$dir all) || exit; \ + done + +clean: + @for dir in $(SUBDIRS); do \ + ($(MAKE) -C $$dir clean) \ + done + diff --git a/test/win32/ebox/Makefile b/test/win32/ebox/Makefile new file mode 100644 index 0000000..81e3002 --- /dev/null +++ b/test/win32/ebox/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = ebox + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/ebox/ebox.c b/test/win32/ebox/ebox.c new file mode 100644 index 0000000..5e4e1c2 --- /dev/null +++ b/test/win32/ebox/ebox.c @@ -0,0 +1,394 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : ebox [ifname] [cycletime] + * ifname is NIC interface, f.e. eth0 + * cycletime in us, f.e. 500 + * + * This test is specifically build for the E/BOX. + * + * (c)Arthur Ketels 2011 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatconfig.h" +#include "ethercatdc.h" + +#define NSEC_PER_SEC 1000000000 + +typedef struct PACKED +{ + uint8 status; + uint8 counter; + uint8 din; + int32 ain[2]; + uint32 tsain; + int32 enc[2]; +} in_EBOXt; + +typedef struct PACKED +{ + uint8 counter; + int16 stream[100]; +} in_EBOX_streamt; + +typedef struct PACKED +{ + uint8 control; + uint8 dout; + int16 aout[2]; + uint16 pwmout[2]; +} out_EBOXt; + +typedef struct PACKED +{ + uint8 control; +} out_EBOX_streamt; + +// total samples to capture +#define MAXSTREAM 200000 +// sample interval in ns, here 8us -> 125kHz +// maximum data rate for E/BOX v1.0.1 is around 150kHz +#define SYNC0TIME 8000 + +struct sched_param schedp; +char IOmap[4096]; +pthread_t thread1; +struct timeval tv,t1,t2; +int dorun = 0; +int deltat, tmax=0; +int64 toff; +int DCdiff; +int os; +uint32 ob; +int16 ob2; +uint8 ob3; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +int64 integral=0; +uint32 cyclecount; +in_EBOX_streamt *in_EBOX; +out_EBOX_streamt *out_EBOX; +double ain[2]; +int ainc; +int streampos; +int16 stream1[MAXSTREAM]; +int16 stream2[MAXSTREAM]; + +int output_cvs(char *fname, int length) +{ + FILE *fp; + + int i; + + fp = fopen(fname, "w"); + if(fp == NULL) + return 0; + for (i = 0; i < length; i++) + { + fprintf(fp, "%d %d %d\n", i, stream1[i], stream2[i]); + } + fclose(fp); + + return 1; +} + +void eboxtest(char *ifname) +{ + int cnt, i; + + printf("Starting E/BOX test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + // check if first slave is an E/BOX + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0)) + { + // reprogram PDO mapping to set slave in stream mode + // this can only be done in pre-OP state + os=sizeof(ob2); ob2 = 0x1601; + ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + os=sizeof(ob2); ob2 = 0x1a01; + ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + } + + ec_config_map(&IOmap); + + ec_configdc(); + + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + + /* configure DC options for every DC capable slave found in the list */ + printf("DC capable : %d\n",ec_configdc()); + + /* check configuration */ + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0) + ) + { + printf("E/BOX found.\n"); + + /* connect struct pointers to slave I/O pointers */ + in_EBOX = (in_EBOX_streamt*) ec_slave[1].inputs; + out_EBOX = (out_EBOX_streamt*) ec_slave[1].outputs; + + /* read indevidual slave state and store in ec_slave[] */ + ec_readstate(); + for(cnt = 1; cnt <= ec_slavecount ; cnt++) + { + printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + } + printf("Request operational state for all slaves\n"); + + /* send one processdata cycle to init SM in slaves */ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* request OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + ain[0] = 0; + ain[1] = 0; + ainc = 0; + dorun = 1; + usleep(100000); // wait for linux to sync on DC + ec_dcsync0(1, TRUE, SYNC0TIME, 0); // SYNC0 on slave 1 + /* acyclic loop 20ms */ + for(i = 1; i <= 200; i++) + { + /* read DC difference register for slave 2 */ + // ec_FPRD(ec_slave[1].configadr, ECT_REG_DCSYSDIFF, sizeof(DCdiff), &DCdiff, EC_TIMEOUTRET); + // if(DCdiff<0) { DCdiff = - (int32)((uint32)DCdiff & 0x7ffffff); } + printf("PD cycle %5d DCtime %12lld Cnt:%3d Data: %6d %6d %6d %6d %6d %6d %6d %6d \n", + cyclecount, ec_DCtime, in_EBOX->counter, in_EBOX->stream[0], in_EBOX->stream[1], + in_EBOX->stream[2], in_EBOX->stream[3], in_EBOX->stream[4], in_EBOX->stream[5], + in_EBOX->stream[98], in_EBOX->stream[99]); + usleep(20000); + } + dorun = 0; + // printf("\nCnt %d : Ain0 = %f Ain2 = %f\n", ainc, ain[0] / ainc, ain[1] / ainc); + } + else + { + printf("Not all slaves reached operational state.\n"); + } + } + else + { + printf("E/BOX not found in slave configuration.\n"); + } + ec_dcsync0(1, FALSE, 8000, 0); // SYNC0 off + printf("Request safe operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_SAFE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + ec_slave[0].state = EC_STATE_PRE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach state */ + ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); + if (( ec_slavecount >= 1 ) && + (strcmp(ec_slave[1].name,"E/BOX") == 0)) + { + // restore PDO to standard mode + // this can only be done is pre-op state + os=sizeof(ob2); ob2 = 0x1600; + ec_SDOwrite(1,0x1c12,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + os=sizeof(ob2); ob2 = 0x1a00; + ec_SDOwrite(1,0x1c13,01,FALSE,os,&ob2,EC_TIMEOUTRXM); + } + printf("Streampos %d\n", streampos); + output_cvs("stream.txt", streampos); + } + else + { + printf("No slaves found!\n"); + } + printf("End E/BOX, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +/* add ns to timespec */ +void add_timespec(struct timespec *ts, int64 addtime) +{ + int64 sec, nsec; + + nsec = addtime % NSEC_PER_SEC; + sec = (addtime - nsec) / NSEC_PER_SEC; + ts->tv_sec += sec; + ts->tv_nsec += nsec; + if ( ts->tv_nsec > NSEC_PER_SEC ) + { + nsec = ts->tv_nsec % NSEC_PER_SEC; + ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC; + ts->tv_nsec = nsec; + } +} + +/* PI calculation to get linux time synced to DC time */ +void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime) +{ + int64 delta; + /* set linux sync point 50us later than DC sync, just as example */ + delta = (reftime - 50000) % cycletime; + if(delta> (cycletime /2)) { delta= delta - cycletime; } + if(delta>0){ integral++; } + if(delta<0){ integral--; } + *offsettime = -(delta / 100) - (integral /20); +} + +/* RT EtherCAT thread */ +void ecatthread( void *ptr ) +{ + struct timespec ts; + struct timeval tp; + int rc; + int ht; + int i; + int pcounter = 0; + int64 cycletime; + + rc = pthread_mutex_lock(&mutex); + rc = gettimeofday(&tp, NULL); + + /* Convert from timeval to timespec */ + ts.tv_sec = tp.tv_sec; + ht = (tp.tv_usec / 1000) + 1; /* round to nearest ms */ + ts.tv_nsec = ht * 1000000; + cycletime = *(int*)ptr * 1000; /* cycletime in ns */ + toff = 0; + dorun = 0; + while(1) + { + /* calculate next cycle start */ + add_timespec(&ts, cycletime + toff); + /* wait to cycle start */ + rc = pthread_cond_timedwait(&cond, &mutex, &ts); + if (dorun>0) + { + rc = gettimeofday(&tp, NULL); + + ec_send_processdata(); + + ec_receive_processdata(EC_TIMEOUTRET); + + cyclecount++; + + + if((in_EBOX->counter != pcounter) && (streampos < (MAXSTREAM - 1))) + { + // check if we have timing problems in master + // if so, overwrite stream data so it shows up clearly in plots. + if(in_EBOX->counter > (pcounter + 1)) + { + for(i = 0 ; i < 50 ; i++) + { + stream1[streampos] = 20000; + stream2[streampos++] = -20000; + } + } + else + { + for(i = 0 ; i < 50 ; i++) + { + stream1[streampos] = in_EBOX->stream[i * 2]; + stream2[streampos++] = in_EBOX->stream[(i * 2) + 1]; + } + } + pcounter = in_EBOX->counter; + } + + /* calulate toff to get linux time and DC synced */ + ec_sync(ec_DCtime, cycletime, &toff); + } + } +} + +int main(int argc, char *argv[]) +{ + int iret1; + int ctime; + struct sched_param param; + int policy = SCHED_OTHER; + + printf("SOEM (Simple Open EtherCAT Master)\nE/BOX test\n"); + + memset(&schedp, 0, sizeof(schedp)); + /* do not set priority above 49, otherwise sockets are starved */ + schedp.sched_priority = 30; + sched_setscheduler(0, SCHED_FIFO, &schedp); + + do + { + usleep(1000); + } + while (dorun); + + if (argc > 1) + { + dorun = 1; + if( argc > 2) + ctime = atoi(argv[2]); + else + ctime = 1000; // 1ms cycle time + /* create RT thread */ + iret1 = pthread_create( &thread1, NULL, (void *) &ecatthread, (void*) &ctime); + memset(¶m, 0, sizeof(param)); + /* give it higher priority */ + param.sched_priority = 40; + iret1 = pthread_setschedparam(thread1, policy, ¶m); + + /* start acyclic part */ + eboxtest(argv[1]); + } + else + { + printf("Usage: ebox ifname [cycletime]\nifname = eth0 for example\ncycletime in us\n"); + } + + schedp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &schedp); + + printf("End program\n"); + + return (0); +} diff --git a/test/win32/eepromtool/Makefile b/test/win32/eepromtool/Makefile new file mode 100644 index 0000000..48c7696 --- /dev/null +++ b/test/win32/eepromtool/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = eepromtool + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/eepromtool/eepromtool.c b/test/win32/eepromtool/eepromtool.c new file mode 100644 index 0000000..1eaadb7 --- /dev/null +++ b/test/win32/eepromtool/eepromtool.c @@ -0,0 +1,395 @@ +/** \file + * \brief EEprom tool for Simple Open EtherCAT master + * + * Usage : eepromtool ifname slave OPTION fname + * ifname is NIC interface, f.e. eth0 + * slave = slave number in EtherCAT order 1..n + * -r read EEPROM, output binary format + * -ri read EEPROM, output Intel Hex format + * -w write EEPROM, input binary format + * -wi write EEPROM, input Intel Hex format + * + * (c)Arthur Ketels 2010 + */ + +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +//#include "ethercatfoe.h" +//#include "ethercatconfig.h" +//#include "ethercatprint.h" + +#define MAXBUF 32768 +#define STDBUF 2048 +#define MINBUF 128 + +#define MODE_NONE 0 +#define MODE_READBIN 1 +#define MODE_READINTEL 2 +#define MODE_WRITEBIN 3 +#define MODE_WRITEINTEL 4 + +#define MAXSLENGTH 256 + +uint8 ebuf[MAXBUF]; +uint8 ob; +uint16 ow; +int os; +int slave; +ec_timet tstart,tend, tdif; +int wkc; +int mode; +char sline[MAXSLENGTH]; + +#define IHEXLENGTH 0x20 + +int input_bin(char *fname, int *length) +{ + FILE *fp; + + int cc = 0, c; + + fp = fopen(fname, "rb"); + if(fp == NULL) + return 0; + while (((c = fgetc(fp)) != EOF) && (cc < MAXBUF)) + ebuf[cc++] = (uint8)c; + *length = cc; + fclose(fp); + + return 1; +} + +int input_intelhex(char *fname, int *start, int *length) +{ + FILE *fp; + + int c, sc, retval = 1; + int ll, ladr, lt, sn, i, lval; + int hstart, hlength, sum; + + fp = fopen(fname, "r"); + if(fp == NULL) + return 0; + hstart = MAXBUF; + hlength = 0; + sum = 0; + do + { + memset(sline, 0x00, MAXSLENGTH); + sc = 0; + while (((c = fgetc(fp)) != EOF) && (c != 0x0A) && (sc < (MAXSLENGTH -1))) + sline[sc++] = (uint8)c; + if ((c != EOF) && ((sc < 11) || (sline[0] != ':'))) + { + c = EOF; + retval = 0; + printf("Invalid Intel Hex format.\n"); + } + if (c != EOF) + { + sn = sscanf(sline , ":%2x%4x%2x", &ll, &ladr, <); + if ((sn == 3) && ((ladr + ll) <= MAXBUF) && (lt == 0)) + { + sum = ll + (ladr >> 8) + (ladr & 0xff) + lt; + if(ladr < hstart) hstart = ladr; + for(i = 0; i < ll ; i++) + { + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + ebuf[ladr + i] = (uint8)lval; + sum += (uint8)lval; + } + if(((ladr + ll) - hstart) > hlength) + hlength = (ladr + ll) - hstart; + sum = (0x100 - sum) & 0xff; + sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval); + if (!sn || ((sum - lval) != 0)) + { + c = EOF; + retval = 0; + printf("Invalid checksum.\n"); + } + } + } + } + while (c != EOF); + if (retval) + { + *length = hlength; + *start = hstart; + } + fclose(fp); + + return retval; +} + +int output_bin(char *fname, int length) +{ + FILE *fp; + + int cc; + + fp = fopen(fname, "wb"); + if(fp == NULL) + return 0; + for (cc = 0 ; cc < length ; cc++) + fputc( ebuf[cc], fp); + fclose(fp); + + return 1; +} + +int output_intelhex(char *fname, int length) +{ + FILE *fp; + + int cc = 0, ll, sum, i; + + fp = fopen(fname, "w"); + if(fp == NULL) + return 0; + while (cc < length) + { + ll = length - cc; + if (ll > IHEXLENGTH) ll = IHEXLENGTH; + sum = ll + (cc >> 8) + (cc & 0xff); + fprintf(fp, ":%2.2X%4.4X00", ll, cc); + for (i = 0; i < ll; i++) + { + fprintf(fp, "%2.2X", ebuf[cc + i]); + sum += ebuf[cc + i]; + } + fprintf(fp, "%2.2X\n", (0x100 - sum) & 0xff); + cc += ll; + } + fprintf(fp, ":00000001FF\n"); + fclose(fp); + + return 1; +} + +int eeprom_read(int slave, int start, int length) +{ + int i, wkc, ainc = 4; + uint16 estat, aiadr; + uint32 b4; + uint64 b8; + uint8 eepctl; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* set Eeprom to master */ + + estat = 0x0000; + aiadr = 1 - slave; + wkc=ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET3); /* read eeprom status */ + estat = etohs(estat); + if (estat & EC_ESTAT_R64) + { + ainc = 8; + for (i = start ; i < (start + length) ; i+=ainc) + { + b8 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = (uint8) b8; + ebuf[i+1] = (uint8) (b8 >> 8); + ebuf[i+2] = (uint8) (b8 >> 16); + ebuf[i+3] = (uint8) (b8 >> 24); + ebuf[i+4] = (uint8) (b8 >> 32); + ebuf[i+5] = (uint8) (b8 >> 40); + ebuf[i+6] = (uint8) (b8 >> 48); + ebuf[i+7] = (uint8) (b8 >> 56); + } + } + else + { + for (i = start ; i < (start + length) ; i+=ainc) + { + b4 = (uint32)ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP); + ebuf[i] = (uint8) b4; + ebuf[i+1] = (uint8) (b4 >> 8); + ebuf[i+2] = (uint8) (b4 >> 16); + ebuf[i+3] = (uint8) (b4 >> 24); + } + } + + return 1; + } + + return 0; +} + +int eeprom_write(int slave, int start, int length) +{ + int i, wkc, dc = 0; + uint16 aiadr, *wbuf; + uint8 eepctl; + int ret; + + if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF)) + { + aiadr = 1 - slave; + eepctl = 2; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* force Eeprom from PDI */ + eepctl = 0; + wkc = ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET3); /* set Eeprom to master */ + + aiadr = 1 - slave; + wbuf = (uint16 *)&ebuf[0]; + for (i = start ; i < (start + length) ; i+=2) + { + ret = ec_writeeepromAP(aiadr, i >> 1 , *(wbuf + (i >> 1)), EC_TIMEOUTEEP); + if (++dc >= 100) + { + dc = 0; + printf("."); + fflush(stdout); + } + } + + return 1; + } + + return 0; +} + +void eepromtool(char *ifname, int slave, int mode, char *fname) +{ + int w, rc = 0, estart, esize; + uint16 *wbuf; + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + + w = 0x0000; + wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE); /* detect number of slaves */ + if (wkc > 0) + { + ec_slavecount = wkc; + + printf("%d slaves found.\n",ec_slavecount); + if((ec_slavecount >= slave) && (slave > 0)) + { + if ((mode == MODE_READBIN) || (mode == MODE_READINTEL)) + { + tstart = osal_current_time(); + eeprom_read(slave, 0x0000, MINBUF); // read first 128 bytes + + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d data\n", slave); + printf(" PDI Control : %4.4X\n",*(wbuf + 0x00)); + printf(" PDI Config : %4.4X\n",*(wbuf + 0x01)); + printf(" Config Alias : %4.4X\n",*(wbuf + 0x04)); + printf(" Checksum : %4.4X\n",*(wbuf + 0x07)); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + printf(" Mailbox Protocol : %4.4X\n",*(wbuf + 0x1C)); + esize = (*(wbuf + 0x3E) + 1) * 128; + if (esize > MAXBUF) esize = MAXBUF; + printf(" Size : %4.4X = %d bytes\n",*(wbuf + 0x3E), esize); + printf(" Version : %4.4X\n",*(wbuf + 0x3F)); + + if (esize > MINBUF) + eeprom_read(slave, MINBUF, esize - MINBUF); // read reminder + + tend = osal_current_time(); + osal_time_diff(&tstart, &tend, &tdif); + if (mode == MODE_READINTEL) output_intelhex(fname, esize); + if (mode == MODE_READBIN) output_bin(fname, esize); + + printf("\nTotal EEPROM read time :%ldms\n", (tdif.usec+(tdif.sec*1000000L)) / 1000); + } + if ((mode == MODE_WRITEBIN) || (mode == MODE_WRITEINTEL)) + { + estart = 0; + if (mode == MODE_WRITEINTEL) rc = input_intelhex(fname, &estart, &esize); + if (mode == MODE_WRITEBIN) rc = input_bin(fname, &esize); + + if (rc > 0) + { + wbuf = (uint16 *)&ebuf[0]; + printf("Slave %d\n", slave); + printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08)); + printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A)); + printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C)); + printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E)); + + printf("Busy"); + fflush(stdout); + tstart = osal_current_time(); + eeprom_write(slave, estart, esize); + tend = osal_current_time(); + osal_time_diff(&tstart, &tend, &tdif); + + printf("\nTotal EEPROM write time :%ldms\n", (tdif.usec+(tdif.sec*1000000L)) / 1000); + } + else + printf("Error reading file, abort.\n"); + } + } + else + printf("Slave number outside range.\n"); + } + else + printf("No slaves found!\n"); + printf("End, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + printf("No socket connection on %s\nExcecute as root\n",ifname); +} + +int main(int argc, char *argv[]) +{ + ec_adaptert * adapter = NULL; + printf("SOEM (Simple Open EtherCAT Master)\nEEPROM tool\n"); + + if (argc > 4) + { + slave = atoi(argv[2]); + mode = MODE_NONE; + if ((strncmp(argv[3], "-r", sizeof("-r")) == 0)) mode = MODE_READBIN; + if ((strncmp(argv[3], "-ri", sizeof("-ri")) == 0)) mode = MODE_READINTEL; + if ((strncmp(argv[3], "-w", sizeof("-w")) == 0)) mode = MODE_WRITEBIN; + if ((strncmp(argv[3], "-wi", sizeof("-wi")) == 0)) mode = MODE_WRITEINTEL; + + /* start tool */ + eepromtool(argv[1],slave,mode,argv[4]); + } + else + { + printf("Usage: eepromtool ifname slave OPTION fname\n"); + printf("ifname = adapter name\n"); + printf("slave = slave number in EtherCAT order 1..n\n"); + printf(" -r read EEPROM, output binary format\n"); + printf(" -ri read EEPROM, output Intel Hex format\n"); + printf(" -w write EEPROM, input binary format\n"); + printf(" -wi write EEPROM, input Intel Hex format\n"); + /* Print the list */ + printf ("Available adapters\n"); + adapter = ec_find_adapters (); + while (adapter != NULL) + { + printf ("Description : %s, Device to use for wpcap: %s\n", adapter->desc,adapter->name); + adapter = adapter->next; + } + } + + printf("End program\n"); + + return (0); +} diff --git a/test/win32/firm_update/Makefile b/test/win32/firm_update/Makefile new file mode 100644 index 0000000..3d5ab5f --- /dev/null +++ b/test/win32/firm_update/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = firm_update + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/firm_update/firm_update.c b/test/win32/firm_update/firm_update.c new file mode 100644 index 0000000..de4ca58 --- /dev/null +++ b/test/win32/firm_update/firm_update.c @@ -0,0 +1,166 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage: firm_update ifname1 slave fname + * ifname is NIC interface, f.e. eth0 + * slave = slave number in EtherCAT order 1..n + * fname = binary file to store in slave + * CAUTION! Using the wrong file can result in a bricked slave! + * + * This is a slave firmware update test. + * + * (c)Arthur Ketels 2011 + */ + +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" + +#define FWBUFSIZE (8 * 1024 * 1024) + +uint8 ob; +uint16 ow; +uint32 data; +char filename[256]; +char filebuffer[FWBUFSIZE]; // 8MB buffer +int filesize; +int j; +uint16 argslave; + +int input_bin(char *fname, int *length) +{ + FILE *fp; + + int cc = 0, c; + + fp = fopen(fname, "rb"); + if(fp == NULL) + return 0; + while (((c = fgetc(fp)) != EOF) && (cc < FWBUFSIZE)) + filebuffer[cc++] = (uint8)c; + *length = cc; + fclose(fp); + return 1; +} + + +void boottest(char *ifname, uint16 slave, char *filename) +{ + printf("Starting firmware update example\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + + + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + printf("Request init state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_INIT; + ec_writestate(slave); + + /* wait for slave to reach INIT state */ + ec_statecheck(slave, EC_STATE_INIT, EC_TIMEOUTSTATE * 4); + printf("Slave %d state to INIT.\n", slave); + + /* read BOOT mailbox data, master -> slave */ + data = ec_readeeprom(slave, ECT_SII_BOOTRXMBX, EC_TIMEOUTEEP); + ec_slave[slave].SM[0].StartAddr = (uint16)LO_WORD(data); + ec_slave[slave].SM[0].SMlength = (uint16)HI_WORD(data); + /* store boot write mailbox address */ + ec_slave[slave].mbx_wo = (uint16)LO_WORD(data); + /* store boot write mailbox size */ + ec_slave[slave].mbx_l = (uint16)HI_WORD(data); + + /* read BOOT mailbox data, slave -> master */ + data = ec_readeeprom(slave, ECT_SII_BOOTTXMBX, EC_TIMEOUTEEP); + ec_slave[slave].SM[1].StartAddr = (uint16)LO_WORD(data); + ec_slave[slave].SM[1].SMlength = (uint16)HI_WORD(data); + /* store boot read mailbox address */ + ec_slave[slave].mbx_ro = (uint16)LO_WORD(data); + /* store boot read mailbox size */ + ec_slave[slave].mbx_rl = (uint16)HI_WORD(data); + + printf(" SM0 A:%4.4x L:%4d F:%8.8x\n", ec_slave[slave].SM[0].StartAddr, ec_slave[slave].SM[0].SMlength, + (int)ec_slave[slave].SM[0].SMflags); + printf(" SM1 A:%4.4x L:%4d F:%8.8x\n", ec_slave[slave].SM[1].StartAddr, ec_slave[slave].SM[1].SMlength, + (int)ec_slave[slave].SM[1].SMflags); + /* program SM0 mailbox in for slave */ + ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM0, sizeof(ec_smt), &ec_slave[slave].SM[0], EC_TIMEOUTRET); + /* program SM1 mailbox out for slave */ + ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET); + + printf("Request BOOT state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_BOOT; + ec_writestate(slave); + + /* wait for slave to reach BOOT state */ + if (ec_statecheck(slave, EC_STATE_BOOT, EC_TIMEOUTSTATE * 10) == EC_STATE_BOOT) + { + printf("Slave %d state to BOOT.\n", slave); + + if (input_bin(filename, &filesize)) + { + printf("File read OK, %d bytes.\n",filesize); + printf("FoE write...."); + j = ec_FOEwrite(slave, filename, 0, filesize , &filebuffer, EC_TIMEOUTSTATE); + printf("result %d.\n",j); + printf("Request init state for slave %d\n", slave); + ec_slave[slave].state = EC_STATE_INIT; + ec_writestate(slave); + } + else + printf("File not read OK.\n"); + } + + } + else + { + printf("No slaves found!\n"); + } + printf("End firmware update example, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nFirmware update example\n"); + + if (argc > 3) + { + argslave = atoi(argv[2]); + boottest(argv[1], argslave, argv[3]); + } + else + { + printf("Usage: firm_update ifname1 slave fname\n"); + printf("ifname = eth0 for example\n"); + printf("slave = slave number in EtherCAT order 1..n\n"); + printf("fname = binary file to store in slave\n"); + printf("CAUTION! Using the wrong file can result in a bricked slave!\n"); + } + + printf("End program\n"); + return (0); +} diff --git a/test/win32/red_test/Makefile b/test/win32/red_test/Makefile new file mode 100644 index 0000000..82859a4 --- /dev/null +++ b/test/win32/red_test/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = red_test + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/red_test/red_test.c b/test/win32/red_test/red_test.c new file mode 100644 index 0000000..a57b041 --- /dev/null +++ b/test/win32/red_test/red_test.c @@ -0,0 +1,263 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : red_test [ifname1] [ifname2] [cycletime] + * ifname is NIC interface, f.e. eth0 + * cycletime in us, f.e. 500 + * + * This is a redundancy test. + * + * (c)Arthur Ketels 2008 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatcoe.h" +#include "ethercatconfig.h" +#include "ethercatdc.h" + +#define NSEC_PER_SEC 1000000000 + +struct sched_param schedp; +char IOmap[4096]; +pthread_t thread1; +struct timeval tv, t1, t2; +int dorun = 0; +int deltat, tmax = 0; +int64 toff; +int DCdiff; +int os; +uint8 ob; +uint16 ob2; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +uint8 *digout = 0; +int wcounter; + +void redtest(char *ifname, char *ifname2) +{ + int cnt, i, j, oloop, iloop; + + printf("Starting Redundant test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init_redundant(ifname, ifname2)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config(FALSE, &IOmap) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); + + /* configure DC options for every DC capable slave found in the list */ + ec_configdc(); + + /* read indevidual slave state and store in ec_slave[] */ + ec_readstate(); + for(cnt = 1; cnt <= ec_slavecount ; cnt++) + { + printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + printf(" Out:%8.8x,%4d In:%8.8x,%4d\n", + (int)ec_slave[cnt].outputs, ec_slave[cnt].Obytes, (int)ec_slave[cnt].inputs, ec_slave[cnt].Ibytes); + /* check for EL2004 or EL2008 */ + if( !digout && ((ec_slave[cnt].eep_id == 0x07d43052) || (ec_slave[cnt].eep_id == 0x07d83052))) + { + digout = ec_slave[cnt].outputs; + } + } + printf("Request operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* request OP state for all slaves */ + ec_writestate(0); + /* wait for all slaves to reach OP state */ + ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); + oloop = ec_slave[0].Obytes; + if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1; + if (oloop > 8) oloop = 8; + iloop = ec_slave[0].Ibytes; + if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1; + if (iloop > 8) iloop = 8; + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + dorun = 1; + /* acyclic loop 5000 x 20ms = 10s */ + for(i = 1; i <= 5000; i++) + { + printf("Processdata cycle %5d , Wck %3d, DCtime %12lld, O:", dorun, wcounter , ec_DCtime); + for(j = 0 ; j < oloop; j++) + { + printf(" %2.2x", *(ec_slave[0].outputs + j)); + } + printf(" I:"); + for(j = 0 ; j < iloop; j++) + { + printf(" %2.2x", *(ec_slave[0].inputs + j)); + } + printf("\n"); + usleep(20000); + } + dorun = 0; + } + else + { + printf("Not all slaves reached operational state.\n"); + } + printf("Request safe operational state for all slaves\n"); + ec_slave[0].state = EC_STATE_SAFE_OP; + /* request SAFE_OP state for all slaves */ + ec_writestate(0); + } + else + { + printf("No slaves found!\n"); + } + printf("End redundant test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +/* add ns to timespec */ +void add_timespec(struct timespec *ts, int64 addtime) +{ + int64 sec, nsec; + + nsec = addtime % NSEC_PER_SEC; + sec = (addtime - nsec) / NSEC_PER_SEC; + ts->tv_sec += sec; + ts->tv_nsec += nsec; + if ( ts->tv_nsec > NSEC_PER_SEC ) + { + nsec = ts->tv_nsec % NSEC_PER_SEC; + ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC; + ts->tv_nsec = nsec; + } +} + +/* PI calculation to get linux time synced to DC time */ +void ec_sync(int64 reftime, int64 cycletime , int64 *offsettime) +{ + static int64 integral = 0; + int64 delta; + /* set linux sync point 50us later than DC sync, just as example */ + delta = (reftime - 50000) % cycletime; + if(delta> (cycletime / 2)) { delta= delta - cycletime; } + if(delta>0){ integral++; } + if(delta<0){ integral--; } + *offsettime = -(delta / 100) - (integral / 20); +} + +/* RT EtherCAT thread */ +void ecatthread( void *ptr ) +{ + struct timespec ts; + struct timeval tp; + int rc; + int ht; + int64 cycletime; + + rc = pthread_mutex_lock(&mutex); + rc = gettimeofday(&tp, NULL); + + /* Convert from timeval to timespec */ + ts.tv_sec = tp.tv_sec; + ht = (tp.tv_usec / 1000) + 1; /* round to nearest ms */ + ts.tv_nsec = ht * 1000000; + cycletime = *(int*)ptr * 1000; /* cycletime in ns */ + toff = 0; + dorun = 0; + while(1) + { + /* calculate next cycle start */ + add_timespec(&ts, cycletime + toff); + /* wait to cycle start */ + rc = pthread_cond_timedwait(&cond, &mutex, &ts); + if (dorun>0) + { + rc = gettimeofday(&tp, NULL); + + ec_send_processdata(); + + wcounter = ec_receive_processdata(EC_TIMEOUTRET); + + dorun++; + /* if we have some digital output, cycle */ + if( digout ) *digout = (uint8) ((dorun / 16) & 0xff); + + if (ec_slave[0].hasdc) + { + /* calulate toff to get linux time and DC synced */ + ec_sync(ec_DCtime, cycletime, &toff); + } + } + } +} + +int main(int argc, char *argv[]) +{ + int iret1; + int ctime; + struct sched_param param; + int policy = SCHED_OTHER; + + printf("SOEM (Simple Open EtherCAT Master)\nRedundancy test\n"); + + memset(&schedp, 0, sizeof(schedp)); + /* do not set priority above 49, otherwise sockets are starved */ + schedp.sched_priority = 30; + sched_setscheduler(0, SCHED_FIFO, &schedp); + + do + { + usleep(1000); + } + while (dorun); + + if (argc > 3) + { + dorun = 1; + ctime = atoi(argv[3]); + /* create RT thread */ + iret1 = pthread_create( &thread1, NULL, (void *) &ecatthread, (void*) &ctime); + memset(¶m, 0, sizeof(param)); + /* give it higher priority */ + param.sched_priority = 40; + iret1 = pthread_setschedparam(thread1, policy, ¶m); + + /* start acyclic part */ + redtest(argv[1],argv[2]); + } + else + { + printf("Usage: red_test ifname1 ifname2 cycletime\nifname = eth0 for example\ncycletime in us\n"); + } + + schedp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &schedp); + + printf("End program\n"); + + return (0); +} diff --git a/test/win32/simple_test/Makefile b/test/win32/simple_test/Makefile new file mode 100644 index 0000000..1d1ad5f --- /dev/null +++ b/test/win32/simple_test/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = simple_test + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/simple_test/simple_test.c b/test/win32/simple_test/simple_test.c new file mode 100644 index 0000000..67bf677 --- /dev/null +++ b/test/win32/simple_test/simple_test.c @@ -0,0 +1,381 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : simple_test [ifname1] + * ifname is NIC interface, f.e. eth0 + * + * This is a minimal test. + * + * (c)Arthur Ketels 2010 - 2011 + */ + +#include +#include +//#include + +#include "osal.h" +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatdc.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" + +#define EC_TIMEOUTMON 500 + +char IOmap[4096]; +OSAL_THREAD_HANDLE thread1; +int expectedWKC; +boolean needlf; +volatile int wkc; +volatile int rtcnt; +boolean inOP; +uint8 currentgroup = 0; + +/* most basic RT thread for process data, just does IO transfer */ +void CALLBACK RTthread(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +{ + IOmap[0]++; + + ec_send_processdata(); + wkc = ec_receive_processdata(EC_TIMEOUTRET); + rtcnt++; + /* do RT control stuff here */ +} + +int EL7031setup(uint16 slave) +{ + int retval; + uint16 u16val; + + // map velocity + uint16 map_1c12[4] = {0x0003, 0x1601, 0x1602, 0x1604}; + uint16 map_1c13[3] = {0x0002, 0x1a01, 0x1a03}; + + retval = 0; + + // Set PDO mapping using Complete Access + // Strange, writing CA works, reading CA doesn't + // This is a protocol error of the slave. + retval += ec_SDOwrite(slave, 0x1c12, 0x00, TRUE, sizeof(map_1c12), &map_1c12, EC_TIMEOUTSAFE); + retval += ec_SDOwrite(slave, 0x1c13, 0x00, TRUE, sizeof(map_1c13), &map_1c13, EC_TIMEOUTSAFE); + + // bug in EL7031 old firmware, CompleteAccess for reading is not supported even if the slave says it is. + ec_slave[slave].CoEdetails &= ~ECT_COEDET_SDOCA; + + // set some motor parameters, just as example + u16val = 1200; // max motor current in mA +// retval += ec_SDOwrite(slave, 0x8010, 0x01, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTSAFE); + u16val = 150; // motor coil resistance in 0.01ohm +// retval += ec_SDOwrite(slave, 0x8010, 0x04, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTSAFE); + + // set other nescessary parameters as needed + // ..... + + while(EcatError) printf("%s", ec_elist2string()); + + printf("EL7031 slave %d set, retval = %d\n", slave, retval); + return 1; +} + +int AEPsetup(uint16 slave) +{ + int retval; + uint8 u8val; + uint16 u16val; + + retval = 0; + + u8val = 0; + retval += ec_SDOwrite(slave, 0x1c12, 0x00, FALSE, sizeof(u8val), &u8val, EC_TIMEOUTRXM); + u16val = 0x1603; + retval += ec_SDOwrite(slave, 0x1c12, 0x01, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTRXM); + u8val = 1; + retval += ec_SDOwrite(slave, 0x1c12, 0x00, FALSE, sizeof(u8val), &u8val, EC_TIMEOUTRXM); + + u8val = 0; + retval += ec_SDOwrite(slave, 0x1c13, 0x00, FALSE, sizeof(u8val), &u8val, EC_TIMEOUTRXM); + u16val = 0x1a03; + retval += ec_SDOwrite(slave, 0x1c13, 0x01, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTRXM); + u8val = 1; + retval += ec_SDOwrite(slave, 0x1c13, 0x00, FALSE, sizeof(u8val), &u8val, EC_TIMEOUTRXM); + + u8val = 8; + retval += ec_SDOwrite(slave, 0x6060, 0x00, FALSE, sizeof(u8val), &u8val, EC_TIMEOUTRXM); + + // set some motor parameters, just as example + u16val = 1200; // max motor current in mA +// retval += ec_SDOwrite(slave, 0x8010, 0x01, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTSAFE); + u16val = 150; // motor coil resistance in 0.01ohm +// retval += ec_SDOwrite(slave, 0x8010, 0x04, FALSE, sizeof(u16val), &u16val, EC_TIMEOUTSAFE); + + // set other nescessary parameters as needed + // ..... + + while(EcatError) printf("%s", ec_elist2string()); + + printf("AEP slave %d set, retval = %d\n", slave, retval); + return 1; +} + +void simpletest(char *ifname) +{ + int i, j, oloop, iloop, wkc_count, chk, slc; + UINT mmResult; + + needlf = FALSE; + inOP = FALSE; + + printf("Starting simple test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + + + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + if((ec_slavecount > 1)) + { + for(slc = 1; slc <= ec_slavecount; slc++) + { + // beckhoff EL7031, using ec_slave[].name is not very reliable + if((ec_slave[slc].eep_man == 0x00000002) && (ec_slave[slc].eep_id == 0x1b773052)) + { + printf("Found %s at position %d\n", ec_slave[slc].name, slc); + // link slave specific setup to preop->safeop hook + ec_slave[slc].PO2SOconfig = &EL7031setup; + } + // Copley Controls EAP, using ec_slave[].name is not very reliable + if((ec_slave[slc].eep_man == 0x000000ab) && (ec_slave[slc].eep_id == 0x00000380)) + { + printf("Found %s at position %d\n", ec_slave[slc].name, slc); + // link slave specific setup to preop->safeop hook + ec_slave[slc].PO2SOconfig = &AEPsetup; + } + } + } + + + ec_config_map(&IOmap); + + ec_configdc(); + + printf("Slaves mapped, state to SAFE_OP.\n"); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 4); + + oloop = ec_slave[0].Obytes; + if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1; + if (oloop > 8) oloop = 8; + iloop = ec_slave[0].Ibytes; + if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1; + if (iloop > 8) iloop = 8; + + printf("segments : %d : %d %d %d %d\n",ec_group[0].nsegments ,ec_group[0].IOsegment[0],ec_group[0].IOsegment[1],ec_group[0].IOsegment[2],ec_group[0].IOsegment[3]); + + printf("Request operational state for all slaves\n"); + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* send one valid process data to make outputs in slaves happy*/ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + + /* start RT thread as periodic MM timer */ + mmResult = timeSetEvent(1, 0, RTthread, 0, TIME_PERIODIC); + + /* request OP state for all slaves */ + ec_writestate(0); + chk = 40; + /* wait for all slaves to reach OP state */ + do + { + ec_statecheck(0, EC_STATE_OPERATIONAL, 50000); + } + while (chk-- && (ec_slave[0].state != EC_STATE_OPERATIONAL)); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + wkc_count = 0; + inOP = TRUE; + + + /* cyclic loop, reads data from RT thread */ + for(i = 1; i <= 500; i++) + { + if(wkc >= expectedWKC) + { + printf("Processdata cycle %4d, WKC %d , O:", rtcnt, wkc); + + for(j = 0 ; j < oloop; j++) + { + printf(" %2.2x", *(ec_slave[0].outputs + j)); + } + + printf(" I:"); + for(j = 0 ; j < iloop; j++) + { + printf(" %2.2x", *(ec_slave[0].inputs + j)); + } + printf(" T:%lld\r",ec_DCtime); + needlf = TRUE; + } + osal_usleep(50000); + + } + inOP = FALSE; + } + else + { + printf("Not all slaves reached operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_OPERATIONAL) + { + printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + + /* stop RT thread */ + timeKillEvent(mmResult); + + printf("\nRequest init state for all slaves\n"); + ec_slave[0].state = EC_STATE_INIT; + /* request INIT state for all slaves */ + ec_writestate(0); + } + else + { + printf("No slaves found!\n"); + } + printf("End simple test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +//DWORD WINAPI ecatcheck( LPVOID lpParam ) +OSAL_THREAD_FUNC ecatcheck(void *lpParam) +{ + int slave; + + while(1) + { + if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)) + { + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > 0) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (!ec_slave[slave].state) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(!ec_slave[slave].state) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); + } + osal_usleep(10000); + } + + return 0; +} + +char ifbuf[1024]; + +int main(int argc, char *argv[]) +{ + ec_adaptert * adapter = NULL; + printf("SOEM (Simple Open EtherCAT Master)\nSimple test\n"); + + if (argc > 1) + { + /* create thread to handle slave error handling in OP */ + osal_thread_create(&thread1, 128000, &ecatcheck, (void*) &ctime); + strcpy(ifbuf, argv[1]); + /* start cyclic part */ + simpletest(ifbuf); + } + else + { + printf("Usage: simple_test ifname1\n"); + /* Print the list */ + printf ("Available adapters\n"); + adapter = ec_find_adapters (); + while (adapter != NULL) + { + printf ("Description : %s, Device to use for wpcap: %s\n", adapter->desc,adapter->name); + adapter = adapter->next; + } + } + + printf("End program\n"); + return (0); +} diff --git a/test/win32/slaveinfo/Makefile b/test/win32/slaveinfo/Makefile new file mode 100644 index 0000000..f009ffc --- /dev/null +++ b/test/win32/slaveinfo/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = slaveinfo + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/slaveinfo/slaveinfo.c b/test/win32/slaveinfo/slaveinfo.c new file mode 100644 index 0000000..3da6cbd --- /dev/null +++ b/test/win32/slaveinfo/slaveinfo.c @@ -0,0 +1,652 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : slaveinfo [ifname] [-sdo] [-map] + * Ifname is NIC interface, f.e. eth0. + * Optional -sdo to display CoE object dictionary. + * Optional -map to display slave PDO mapping + * + * This shows the configured slave data. + * + * (c)Arthur Ketels 2010 - 2011 + */ + +#include +#include + +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatconfig.h" +#include "ethercatcoe.h" +#include "ethercatdc.h" +#include "ethercatprint.h" + +char IOmap[4096]; +ec_ODlistt ODlist; +ec_OElistt OElist; +boolean printSDO = FALSE; +boolean printMAP = FALSE; +char usdo[128]; +char hstr[1024]; + +char* dtype2string(uint16 dtype) +{ + switch(dtype) + { + case ECT_BOOLEAN: + sprintf(hstr, "BOOLEAN"); + break; + case ECT_INTEGER8: + sprintf(hstr, "INTEGER8"); + break; + case ECT_INTEGER16: + sprintf(hstr, "INTEGER16"); + break; + case ECT_INTEGER32: + sprintf(hstr, "INTEGER32"); + break; + case ECT_INTEGER24: + sprintf(hstr, "INTEGER24"); + break; + case ECT_INTEGER64: + sprintf(hstr, "INTEGER64"); + break; + case ECT_UNSIGNED8: + sprintf(hstr, "UNSIGNED8"); + break; + case ECT_UNSIGNED16: + sprintf(hstr, "UNSIGNED16"); + break; + case ECT_UNSIGNED32: + sprintf(hstr, "UNSIGNED32"); + break; + case ECT_UNSIGNED24: + sprintf(hstr, "UNSIGNED24"); + break; + case ECT_UNSIGNED64: + sprintf(hstr, "UNSIGNED64"); + break; + case ECT_REAL32: + sprintf(hstr, "REAL32"); + break; + case ECT_REAL64: + sprintf(hstr, "REAL64"); + break; + case ECT_BIT1: + sprintf(hstr, "BIT1"); + break; + case ECT_BIT2: + sprintf(hstr, "BIT2"); + break; + case ECT_BIT3: + sprintf(hstr, "BIT3"); + break; + case ECT_BIT4: + sprintf(hstr, "BIT4"); + break; + case ECT_BIT5: + sprintf(hstr, "BIT5"); + break; + case ECT_BIT6: + sprintf(hstr, "BIT6"); + break; + case ECT_BIT7: + sprintf(hstr, "BIT7"); + break; + case ECT_BIT8: + sprintf(hstr, "BIT8"); + break; + case ECT_VISIBLE_STRING: + sprintf(hstr, "VISIBLE_STRING"); + break; + case ECT_OCTET_STRING: + sprintf(hstr, "OCTET_STRING"); + break; + default: + sprintf(hstr, "Type 0x%4.4X", dtype); + } + return hstr; +} + +char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype) +{ + int l = sizeof(usdo) - 1, i; + uint8 *u8; + int8 *i8; + uint16 *u16; + int16 *i16; + uint32 *u32; + int32 *i32; + uint64 *u64; + int64 *i64; + float *sr; + double *dr; + char es[32]; + + memset(&usdo, 0, 128); + ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM); + if (EcatError) + { + return ec_elist2string(); + } + else + { + switch(dtype) + { + case ECT_BOOLEAN: + u8 = (uint8*) &usdo[0]; + if (*u8) sprintf(hstr, "TRUE"); + else sprintf(hstr, "FALSE"); + break; + case ECT_INTEGER8: + i8 = (int8*) &usdo[0]; + sprintf(hstr, "0x%2.2x %d", *i8, *i8); + break; + case ECT_INTEGER16: + i16 = (int16*) &usdo[0]; + sprintf(hstr, "0x%4.4x %d", *i16, *i16); + break; + case ECT_INTEGER32: + case ECT_INTEGER24: + i32 = (int32*) &usdo[0]; + sprintf(hstr, "0x%8.8x %d", *i32, *i32); + break; + case ECT_INTEGER64: + i64 = (int64*) &usdo[0]; + sprintf(hstr, "0x%16.16llx %lld", *i64, *i64); + break; + case ECT_UNSIGNED8: + u8 = (uint8*) &usdo[0]; + sprintf(hstr, "0x%2.2x %u", *u8, *u8); + break; + case ECT_UNSIGNED16: + u16 = (uint16*) &usdo[0]; + sprintf(hstr, "0x%4.4x %u", *u16, *u16); + break; + case ECT_UNSIGNED32: + case ECT_UNSIGNED24: + u32 = (uint32*) &usdo[0]; + sprintf(hstr, "0x%8.8x %u", *u32, *u32); + break; + case ECT_UNSIGNED64: + u64 = (uint64*) &usdo[0]; + sprintf(hstr, "0x%16.16llx %llu", *u64, *u64); + break; + case ECT_REAL32: + sr = (float*) &usdo[0]; + sprintf(hstr, "%f", *sr); + break; + case ECT_REAL64: + dr = (double*) &usdo[0]; + sprintf(hstr, "%f", *dr); + break; + case ECT_BIT1: + case ECT_BIT2: + case ECT_BIT3: + case ECT_BIT4: + case ECT_BIT5: + case ECT_BIT6: + case ECT_BIT7: + case ECT_BIT8: + u8 = (uint8*) &usdo[0]; + sprintf(hstr, "0x%x", *u8); + break; + case ECT_VISIBLE_STRING: + strcpy(hstr, usdo); + break; + case ECT_OCTET_STRING: + hstr[0] = 0x00; + for (i = 0 ; i < l ; i++) + { + sprintf(es, "0x%2.2x ", usdo[i]); + strcat( hstr, es); + } + break; + default: + sprintf(hstr, "Unknown type"); + } + return hstr; + } +} + +/** Read PDO assign structure */ +int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset) +{ + uint16 idxloop, nidx, subidxloop, rdat, idx, subidx; + uint8 subcnt; + int wkc, bsize = 0, rdl; + int32 rdat2; + uint8 bitlen, obj_subidx; + uint16 obj_idx; + int abs_offset, abs_bit; + + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign subindex 0 ( = number of PDO's) */ + wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + rdat = etohs(rdat); + /* positive result from slave ? */ + if ((wkc > 0) && (rdat > 0)) + { + /* number of available sub indexes */ + nidx = rdat; + bsize = 0; + /* read all PDO's */ + for (idxloop = 1; idxloop <= nidx; idxloop++) + { + rdl = sizeof(rdat); rdat = 0; + /* read PDO assign */ + wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM); + /* result is index of PDO */ + idx = etohl(rdat); + if (idx > 0) + { + rdl = sizeof(subcnt); subcnt = 0; + /* read number of subindexes of PDO */ + wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM); + subidx = subcnt; + /* for each subindex */ + for (subidxloop = 1; subidxloop <= subidx; subidxloop++) + { + rdl = sizeof(rdat2); rdat2 = 0; + /* read SDO that is mapped in PDO */ + wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM); + rdat2 = etohl(rdat2); + /* extract bitlength of SDO */ + bitlen = LO_BYTE(rdat2); + bsize += bitlen; + obj_idx = (uint16)(rdat2 >> 16); + obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff); + abs_offset = mapoffset + (bitoffset / 8); + abs_bit = bitoffset % 8; + ODlist.Slave = slave; + ODlist.Index[0] = obj_idx; + OElist.Entries = 0; + wkc = 0; + /* read object entry from dictionary if not a filler (0x0000:0x00) */ + if(obj_idx || obj_subidx) + wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist); + printf(" [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen); + if((wkc > 0) && OElist.Entries) + { + printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]); + } + else + printf("\n"); + bitoffset += bitlen; + }; + }; + }; + }; + /* return total found bitlength (PDO) */ + return bsize; +} + +int si_map_sdo(int slave) +{ + int wkc, rdl; + int retVal = 0; + uint8 nSM, iSM, tSM; + int Tsize, outputs_bo, inputs_bo; + uint8 SMt_bug_add; + + printf("PDO mapping according to CoE :\n"); + SMt_bug_add = 0; + outputs_bo = 0; + inputs_bo = 0; + rdl = sizeof(nSM); nSM = 0; + /* read SyncManager Communication Type object count */ + wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM); + /* positive result from slave ? */ + if ((wkc > 0) && (nSM > 2)) + { + /* make nSM equal to number of defined SM */ + nSM--; + /* limit to maximum number of SM defined, if true the slave can't be configured */ + if (nSM > EC_MAXSM) + nSM = EC_MAXSM; + /* iterate for every SM type defined */ + for (iSM = 2 ; iSM <= nSM ; iSM++) + { + rdl = sizeof(tSM); tSM = 0; + /* read SyncManager Communication Type */ + wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM); + if (wkc > 0) + { + if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave! + { + SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4 + printf("Activated SM type workaround, possible incorrect mapping.\n"); + } + if(tSM) + tSM += SMt_bug_add; // only add if SMt > 0 + + if (tSM == 3) // outputs + { + /* read the assign RXPDO */ + printf(" SM%1d outputs\n addr b index: sub bitl data_type name\n", iSM); + Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo ); + outputs_bo += Tsize; + } + if (tSM == 4) // inputs + { + /* read the assign TXPDO */ + printf(" SM%1d inputs\n addr b index: sub bitl data_type name\n", iSM); + Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo ); + inputs_bo += Tsize; + } + } + } + } + + /* found some I/O bits ? */ + if ((outputs_bo > 0) || (inputs_bo > 0)) + retVal = 1; + return retVal; +} + +int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset) +{ + uint16 a , w, c, e, er, Size; + uint8 eectl; + uint16 obj_idx; + uint8 obj_subidx; + uint8 obj_name; + uint8 obj_datatype; + uint8 bitlen; + int totalsize; + ec_eepromPDOt eepPDO; + ec_eepromPDOt *PDO; + int abs_offset, abs_bit; + char str_name[EC_MAXNAME + 1]; + + eectl = ec_slave[slave].eep_pdi; + Size = 0; + totalsize = 0; + PDO = &eepPDO; + PDO->nPDO = 0; + PDO->Length = 0; + PDO->Index[1] = 0; + for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0; + if (t > 1) + t = 1; + PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t); + if (PDO->Startpos > 0) + { + a = PDO->Startpos; + w = ec_siigetbyte(slave, a++); + w += (ec_siigetbyte(slave, a++) << 8); + PDO->Length = w; + c = 1; + /* traverse through all PDOs */ + do + { + PDO->nPDO++; + PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++); + PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8); + PDO->BitSize[PDO->nPDO] = 0; + c++; + /* number of entries in PDO */ + e = ec_siigetbyte(slave, a++); + PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++); + a++; + obj_name = ec_siigetbyte(slave, a++); + a += 2; + c += 2; + if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */ + { + str_name[0] = 0; + if(obj_name) + ec_siistring(str_name, slave, obj_name); + if (t) + printf(" SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name); + else + printf(" SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name); + printf(" addr b index: sub bitl data_type name\n"); + /* read all entries defined in PDO */ + for (er = 1; er <= e; er++) + { + c += 4; + obj_idx = ec_siigetbyte(slave, a++); + obj_idx += (ec_siigetbyte(slave, a++) << 8); + obj_subidx = ec_siigetbyte(slave, a++); + obj_name = ec_siigetbyte(slave, a++); + obj_datatype = ec_siigetbyte(slave, a++); + bitlen = ec_siigetbyte(slave, a++); + abs_offset = mapoffset + (bitoffset / 8); + abs_bit = bitoffset % 8; + + PDO->BitSize[PDO->nPDO] += bitlen; + a += 2; + + str_name[0] = 0; + if(obj_name) + ec_siistring(str_name, slave, obj_name); + + printf(" [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen); + printf(" %-12s %s\n", dtype2string(obj_datatype), str_name); + bitoffset += bitlen; + totalsize += bitlen; + } + PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO]; + Size += PDO->BitSize[PDO->nPDO]; + c++; + } + else /* PDO deactivated because SM is 0xff or > EC_MAXSM */ + { + c += 4 * e; + a += 8 * e; + c++; + } + if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */ + } + while (c < PDO->Length); + } + if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */ + return totalsize; +} + + +int si_map_sii(int slave) +{ + int retVal = 0; + int Tsize, outputs_bo, inputs_bo; + + printf("PDO mapping according to SII :\n"); + + outputs_bo = 0; + inputs_bo = 0; + /* read the assign RXPDOs */ + Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo ); + outputs_bo += Tsize; + /* read the assign TXPDOs */ + Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo ); + inputs_bo += Tsize; + /* found some I/O bits ? */ + if ((outputs_bo > 0) || (inputs_bo > 0)) + retVal = 1; + return retVal; +} + +void si_sdo(int cnt) +{ + int i, j; + + ODlist.Entries = 0; + memset(&ODlist, 0, sizeof(ODlist)); + if( ec_readODlist(cnt, &ODlist)) + { + printf(" CoE Object Description found, %d entries.\n",ODlist.Entries); + for( i = 0 ; i < ODlist.Entries ; i++) + { + ec_readODdescription(i, &ODlist); + while(EcatError) printf("%s", ec_elist2string()); + printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n", + ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]); + memset(&OElist, 0, sizeof(OElist)); + ec_readOE(i, &ODlist, &OElist); + while(EcatError) printf("%s", ec_elist2string()); + for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++) + { + if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0)) + { + printf(" Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n", + j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]); + if ((OElist.ObjAccess[j] & 0x0007)) + { + printf(" Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j])); + } + } + } + } + } + else + { + while(EcatError) printf("%s", ec_elist2string()); + } +} + +void slaveinfo(char *ifname) +{ + int cnt, i, j, nSM; + uint16 ssigen; + int expectedWKC; + + printf("Starting slaveinfo\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config(FALSE, &IOmap) > 0 ) + { + ec_configdc(); + while(EcatError) printf("%s", ec_elist2string()); + printf("%d slaves found and configured.\n",ec_slavecount); + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 3); + if (ec_slave[0].state != EC_STATE_SAFE_OP ) + { + printf("Not all slaves reached safe operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_SAFE_OP) + { + printf("Slave %d State=%2x StatusCode=%4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + + + ec_readstate(); + for( cnt = 1 ; cnt <= ec_slavecount ; cnt++) + { + printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n", + cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits, + ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc); + if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport); + printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 , + (ec_slave[cnt].activeports & 0x02) > 0 , + (ec_slave[cnt].activeports & 0x04) > 0 , + (ec_slave[cnt].activeports & 0x08) > 0 ); + printf(" Configured address: %4.4x\n", ec_slave[cnt].configadr); + printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev); + for(nSM = 0 ; nSM < EC_MAXSM ; nSM++) + { + if(ec_slave[cnt].SM[nSM].StartAddr > 0) + printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, ec_slave[cnt].SM[nSM].StartAddr, ec_slave[cnt].SM[nSM].SMlength, + (int)ec_slave[cnt].SM[nSM].SMflags, ec_slave[cnt].SMtype[nSM]); + } + for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++) + { + printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j, + (int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit, + ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit, + ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive); + } + printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n", + ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func); + printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto); + ssigen = ec_siifind(cnt, ECT_SII_GENERAL); + /* SII general section */ + if (ssigen) + { + ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07); + ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08); + ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09); + ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a); + if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0) + { + ec_slave[cnt].blockLRW = 1; + ec_slave[0].blockLRW++; + } + ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e); + ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8; + ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent; + } + printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n", + ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails); + printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n", + ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW); + if ((ec_slave[cnt].mbx_proto & 0x04) && printSDO) + si_sdo(cnt); + if(printMAP) + { + if (ec_slave[cnt].mbx_proto & 0x04) + si_map_sdo(cnt); + else + si_map_sii(cnt); + } + } + } + else + { + printf("No slaves found!\n"); + } + printf("End slaveinfo, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +char ifbuf[1024]; + +int main(int argc, char *argv[]) +{ + ec_adaptert * adapter = NULL; + printf("SOEM (Simple Open EtherCAT Master)\nSlaveinfo\n"); + + if (argc > 1) + { + if ((argc > 2) && (strncmp(argv[2], "-sdo", sizeof("-sdo")) == 0)) printSDO = TRUE; + if ((argc > 2) && (strncmp(argv[2], "-map", sizeof("-map")) == 0)) printMAP = TRUE; + /* start slaveinfo */ + strcpy(ifbuf, argv[1]); + slaveinfo(ifbuf); + } + else + { + printf("Usage: slaveinfo ifname [options]\nifname = eth0 for example\nOptions :\n -sdo : print SDO info\n -map : print mapping\n"); + /* Print the list */ + printf ("Available adapters\n"); + adapter = ec_find_adapters (); + while (adapter != NULL) + { + printf ("Description : %s, Device to use for wpcap: %s\n", adapter->desc,adapter->name); + adapter = adapter->next; + } + } + + printf("End program\n"); + return (0); +} diff --git a/test/win32/status_test/Makefile b/test/win32/status_test/Makefile new file mode 100644 index 0000000..1d1ad5f --- /dev/null +++ b/test/win32/status_test/Makefile @@ -0,0 +1,24 @@ +#****************************************************************************** +# * *** *** +# *** *** *** +# *** **** ********** *** ***** *** **** ***** +# ********* ********** *** ********* ************ ********* +# **** *** *** *** *** **** *** +# *** *** ****** *** *********** *** **** ***** +# *** *** ****** *** ************* *** **** ***** +# *** **** **** *** *** *** **** *** +# *** ******* ***** ************** ************* ********* +# *** ***** *** ******* ** ** ****** ***** +# t h e r e a l t i m e t a r g e t e x p e r t s +# +# http://www.rt-labs.com +# Copyright (C) 2006. rt-labs AB, Sweden. All rights reserved. +#------------------------------------------------------------------------------ +# $Id: Makefile 262 2012-08-14 06:14:07Z rtlaka $ +#------------------------------------------------------------------------------ + +APPNAME = simple_test + +all: $(APPNAME) + +include $(PRJ_ROOT)/make/app.mk diff --git a/test/win32/status_test/status_test.c b/test/win32/status_test/status_test.c new file mode 100644 index 0000000..af9692d --- /dev/null +++ b/test/win32/status_test/status_test.c @@ -0,0 +1,219 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master + * + * Usage : status_test [ifname1] + * ifname is NIC interface, f.e. eth0 + * + * This is a test to read out status information from a slave. + * + * (c)Daniel Udd 2014 + */ + +#include +#include +//#include + +#include "osal.h" +#include "ethercattype.h" +#include "nicdrv.h" +#include "ethercatbase.h" +#include "ethercatmain.h" +#include "ethercatdc.h" +#include "ethercatcoe.h" +#include "ethercatfoe.h" +#include "ethercatconfig.h" +#include "ethercatprint.h" +#include "ecat.h" + +#define EC_TIMEOUTMON 500 + +char IOmap[4096]; +OSAL_THREAD_HANDLE thread1; +int expectedWKC; +boolean needlf; +volatile int wkc; +boolean inOP; +uint8 currentgroup = 0; + +static void print_dc_status(ecat_slave_dc_status_t * status) +{ + printf("Slave dc status:\n"); + printf(" - DC System time:\n"); + printf(" System time: %llu\n", status->time); + printf(" System time offset: %llu\n", status->offset); + printf(" System time delay: %u\n", status->delay); + printf(" System time difference: %d\n", status->difference); +} +static void print_status(ecat_slave_status_t * status) +{ + printf("Slave status:\n"); + printf(" - port 0:\n"); + printf(" Link detected: %u\n", status->port[0].link_detected); + printf(" Loop port: %u\n", status->port[0].loop_port); + printf(" Stable communication: %u\n", status->port[0].stable_com); + printf(" Lost link counter: %u\n", status->port[0].lost_link_counter); + printf(" Invalid frame counter: %u\n", status->port[0].invalid_frame_counter); + printf(" RX error counter: %u\n", status->port[0].rx_error_counter); + printf(" Forwarded RX error counter: %u\n", status->port[0].forwarded_rx_error_counter); + printf(" - port 1:\n"); + printf(" Link detected: %u\n", status->port[1].link_detected); + printf(" Loop port: %u\n", status->port[1].loop_port); + printf(" Stable communication: %u\n", status->port[1].stable_com); + printf(" Lost link counter: %u\n", status->port[1].lost_link_counter); + printf(" Invalid frame counter: %u\n", status->port[1].invalid_frame_counter); + printf(" RX error counter: %u\n", status->port[1].rx_error_counter); + printf(" Forwarded RX error counter: %u\n", status->port[1].forwarded_rx_error_counter); + printf(" - port 2:\n"); + printf(" Link detected: %u\n", status->port[2].link_detected); + printf(" Loop port: %u\n", status->port[2].loop_port); + printf(" Stable communication: %u\n", status->port[2].stable_com); + printf(" Lost link counter: %u\n", status->port[2].lost_link_counter); + printf(" Invalid frame counter: %u\n", status->port[2].invalid_frame_counter); + printf(" RX error counter: %u\n", status->port[2].rx_error_counter); + printf(" Forwarded RX error counter: %u\n", status->port[2].forwarded_rx_error_counter); + printf(" - port 3:\n"); + printf(" Link detected: %u\n", status->port[3].link_detected); + printf(" Loop port: %u\n", status->port[3].loop_port); + printf(" Stable communication: %u\n", status->port[3].stable_com); + printf(" Lost link counter: %u\n", status->port[3].lost_link_counter); + printf(" Invalid frame counter: %u\n", status->port[3].invalid_frame_counter); + printf(" RX error counter: %u\n", status->port[3].rx_error_counter); + printf(" Forwarded RX error counter: %u\n", status->port[3].forwarded_rx_error_counter); + printf(" - Watchdog Counters:\n"); + printf(" Watchdog counter process data: %u\n", status->wd_cnt.watchdog_counter_process_data); + printf(" Watchdog counter pdi: %u\n", status->wd_cnt.watchdog_counter_pdi); + printf(" - ECAT Processing Unit Error Counter: %u\n", status->ecat_processing_unit_error_counter); + printf(" - PDI Error Counter: %u\n", status->pdi_error_counter); + printf(" - PDI Error Code: %u\n", status->pdi_error_code); +} + +void slave_status_test(char * ibuf) +{ + ecat_slave_status_t slave_status; + ecat_slave_dc_status_t slave_dc_status; + int fault; + ecat_net_t * net; + + printf("Init...\n"); + memset(&slave_status, 0, sizeof(ecat_slave_status_t)); + memset(&slave_dc_status, 0, sizeof(ecat_slave_dc_status_t)); + net = ecat_net_init (ibuf); + if (!ecat_net_scan (net)) { + fault = ecat_slave_get_status(net, 1, &slave_status); + printf("Get status result: %d\n", fault); + fault = ecat_slave_get_dc_status(net, 1, &slave_dc_status); + printf("Get dc status result: %d\n", fault); + print_status(&slave_status); + print_dc_status(&slave_dc_status); + } +} + +OSAL_THREAD_FUNC ecatcheck(void *lpParam) +{ + int slave; + + while(1) + { + if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)) + { + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > 0) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (!ec_slave[slave].state) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(!ec_slave[slave].state) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); + } + osal_usleep(10000); + } + + return 0; +} + +char ifbuf[1024]; + +int main(int argc, char *argv[]) +{ + ec_adaptert * adapter = NULL; + printf("SOEM (Simple Open EtherCAT Master)\nStatus test\n"); + + if (argc > 1) + { + /* create thread to handle slave error handling in OP */ + osal_thread_create(&thread1, 128000, &ecatcheck, (void*) &ctime); + strcpy(ifbuf, argv[1]); + /* start test */ + slave_status_test(ifbuf); + } + else + { + printf("Usage: status_test ifname1\n"); + /* Print the list */ + printf ("Available adapters\n"); + adapter = ec_find_adapters (); + while (adapter != NULL) + { + printf ("Description : %s, Device to use for wpcap: %s\n", adapter->desc,adapter->name); + adapter = adapter->next; + } + } + + printf("End program\n"); + return (0); +}