mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-06 11:51:45 +08:00
Merge
This commit is contained in:
92
.hgignore
Normal file
92
.hgignore
Normal file
@@ -0,0 +1,92 @@
|
||||
syntax: glob
|
||||
|
||||
**.ko
|
||||
**.ko.cmd
|
||||
**.lo
|
||||
**.mod.c
|
||||
**.o
|
||||
**.o.cmd
|
||||
**.swp
|
||||
.tmp_versions
|
||||
ChangeLog
|
||||
Doxyfile
|
||||
Kbuild
|
||||
Makefile
|
||||
Makefile.in
|
||||
Module.markers
|
||||
Module.symvers
|
||||
TAGS
|
||||
aclocal.m4
|
||||
autoconf
|
||||
autom4te.cache
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
devices/Kbuild
|
||||
devices/Makefile
|
||||
devices/Makefile.in
|
||||
devices/TAGS
|
||||
devices/e1000/Kbuild
|
||||
devices/e1000/Makefile
|
||||
devices/e1000/Makefile.in
|
||||
devices/modules.order
|
||||
examples/Kbuild
|
||||
examples/Makefile
|
||||
examples/Makefile.in
|
||||
examples/TAGS
|
||||
examples/dc_rtai/Kbuild
|
||||
examples/dc_rtai/Makefile
|
||||
examples/dc_rtai/Makefile.in
|
||||
examples/dc_user/.deps
|
||||
examples/dc_user/.libs
|
||||
examples/dc_user/Makefile
|
||||
examples/dc_user/Makefile.in
|
||||
examples/dc_user/TAGS
|
||||
examples/dc_user/ec_dc_user_example
|
||||
examples/mini/Kbuild
|
||||
examples/mini/Makefile
|
||||
examples/mini/Makefile.in
|
||||
examples/mini/modules.order
|
||||
examples/modules.order
|
||||
examples/rtai/Kbuild
|
||||
examples/rtai/Makefile
|
||||
examples/rtai/Makefile.in
|
||||
examples/user/.deps
|
||||
examples/user/.libs
|
||||
examples/user/Makefile
|
||||
examples/user/Makefile.in
|
||||
examples/user/TAGS
|
||||
examples/user/ec_user_example
|
||||
include/Makefile
|
||||
include/Makefile.in
|
||||
include/TAGS
|
||||
lib/.deps
|
||||
lib/.libs
|
||||
lib/Makefile
|
||||
lib/Makefile.in
|
||||
lib/TAGS
|
||||
lib/libethercat.la
|
||||
libtool
|
||||
m4/Makefile
|
||||
m4/Makefile.in
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
m4/lt~obsolete.m4
|
||||
modules.order
|
||||
script/Makefile
|
||||
script/Makefile.in
|
||||
script/init.d/Makefile
|
||||
script/init.d/Makefile.in
|
||||
script/init.d/ethercat
|
||||
script/sysconfig/Makefile
|
||||
script/sysconfig/Makefile.in
|
||||
stamp-h1
|
||||
tool/.deps
|
||||
tool/Makefile
|
||||
tool/Makefile.in
|
||||
tool/TAGS
|
||||
tool/ethercat
|
||||
11
Makefile.am
11
Makefile.am
@@ -81,14 +81,13 @@ clean-local:
|
||||
@rm -f Modules.symvers
|
||||
|
||||
mydist:
|
||||
svn2cl $(srcdir)
|
||||
@SVNREV=`svnversion $(srcdir)` && \
|
||||
$(MAKE) dist-bzip2 \
|
||||
distdir=$(PACKAGE)-$(VERSION)-r$${SVNREV}
|
||||
hg log --style=changelog $(srcdir) > ChangeLog
|
||||
@REV=`hg id -i $(srcdir)` && \
|
||||
$(MAKE) dist-bzip2 distdir=$(PACKAGE)-$(VERSION)-$${REV}
|
||||
|
||||
dist-hook:
|
||||
if which svnversion >/dev/null 2>&1; then \
|
||||
svnversion $(srcdir) 2>/dev/null >$(distdir)/svnrevision; \
|
||||
if which hg >/dev/null 2>&1; then \
|
||||
hg id -i $(srcdir) 2>/dev/null >$(distdir)/revision; \
|
||||
fi
|
||||
|
||||
mrproper: clean cleandoc
|
||||
|
||||
7
NEWS
7
NEWS
@@ -26,7 +26,7 @@ Changes since 1.4.0:
|
||||
* Added 8139too driver for kernels 2.6.25 (F. Pose), 2.6.26 (M. Luescher),
|
||||
2.6.27, 2.6.28 and 2.6.29 (M. Goetze).
|
||||
* Added e1000 driver for 2.6.26 (M. Luescher).
|
||||
* Added r8169 driver for 2.6.24 and 2.6.28.
|
||||
* Added r8169 driver for 2.6.24, 2.6.28 and 2.6.29.
|
||||
* Debug interfaces are created with the Ethernet addresses of the attached
|
||||
physical device.
|
||||
* Improved error case return codes of many functions.
|
||||
@@ -45,6 +45,8 @@ Changes since 1.4.0:
|
||||
methods to let an application transfer SDOs before activating the master
|
||||
(thanks to Stefan Weiser).
|
||||
* Fixed SDO upload segment response (thanks to Christoph Peter).
|
||||
* Fixed SDO upload segment response for 10 bytes mailbox length (thanks to
|
||||
Joerg Mohre).
|
||||
* SDO entry access rights are shown in 'ethercat sdos'.
|
||||
* Added 64-bit data access macros to application header.
|
||||
* Added debug level for all masters as a module parameter. Thanks to Erwin
|
||||
@@ -59,7 +61,10 @@ Changes since 1.4.0:
|
||||
* Module symbol versions file for ec_master.ko is installed to
|
||||
prefix/modules/ec_master.symvers.
|
||||
* Added 'ethercat eoe' command to display Ethernet over EtherCAT statistics.
|
||||
* Added 'ethercat cstruct' command to output PDO information in C language.
|
||||
* Significantly improved EoE bandwidth by running EoE processing in a kthread.
|
||||
* Switched version control from Subversion to Mercurial.
|
||||
* Implemented CompleteAccess for SDO downloads.
|
||||
|
||||
Changes in 1.4.0:
|
||||
|
||||
|
||||
9
TODO
9
TODO
@@ -20,7 +20,6 @@ Version 1.5.0:
|
||||
"System Time" register instead of using the application time.
|
||||
- Check if register 0x0980 is working, to avoid clearing it when
|
||||
configuring.
|
||||
- Create an interface to query the System Time Difference registers.
|
||||
* Remove byte-swapping functions from user space.
|
||||
* EoE:
|
||||
- Only execute one EoE handler per cycle.
|
||||
@@ -47,6 +46,14 @@ Version 1.5.0:
|
||||
* Document ec_fsm_foe members.
|
||||
* Test KBUILD_EXTRA_SYMBOLS.
|
||||
* Remove default buffer size in SDO upload.
|
||||
* Check for Enable SDO Complete Access flag.
|
||||
* Implement CompleteAccess for command-line tool.
|
||||
* Implement CompleteAccess for SDO uploads.
|
||||
* Implement identifier parameter for cstruct command.
|
||||
* Implement sync delimiter for cstruct command.
|
||||
* Change SDO index at runtime for SDO request.
|
||||
* Implement ecrt_slave_config_request_state().
|
||||
* Output skipped datagrams again.
|
||||
|
||||
Future issues:
|
||||
|
||||
|
||||
@@ -31,24 +31,24 @@
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
REV := $(shell if test -s $(src)/../svnrevision; then \
|
||||
cat $(src)/../svnrevision; \
|
||||
REV := $(shell if test -s $(src)/../revision; then \
|
||||
cat $(src)/../revision; \
|
||||
else \
|
||||
svnversion $(src)/.. 2>/dev/null || echo "unknown"; \
|
||||
hg id -i $(src)/.. 2>/dev/null || echo "unknown"; \
|
||||
fi)
|
||||
|
||||
ifeq (@ENABLE_8139TOO@,1)
|
||||
EC_8139TOO_OBJ := 8139too-@KERNEL_8139TOO@-ethercat.o
|
||||
obj-m += ec_8139too.o
|
||||
ec_8139too-objs := $(EC_8139TOO_OBJ)
|
||||
CFLAGS_$(EC_8139TOO_OBJ) = -DSVNREV=$(REV)
|
||||
CFLAGS_$(EC_8139TOO_OBJ) = -DREV=$(REV)
|
||||
endif
|
||||
|
||||
ifeq (@ENABLE_E100@,1)
|
||||
EC_E100_OBJ := e100-@KERNEL_E100@-ethercat.o
|
||||
obj-m += ec_e100.o
|
||||
ec_e100-objs := $(EC_E100_OBJ)
|
||||
CFLAGS_$(EC_E100_OBJ) = -DSVNREV=$(REV)
|
||||
CFLAGS_$(EC_E100_OBJ) = -DREV=$(REV)
|
||||
endif
|
||||
|
||||
ifeq (@ENABLE_E1000@,1)
|
||||
@@ -59,7 +59,7 @@ ifeq (@ENABLE_R8169@,1)
|
||||
EC_R8169_OBJ := r8169-@KERNEL_R8169@-ethercat.o
|
||||
obj-m += ec_r8169.o
|
||||
ec_r8169-objs := $(EC_R8169_OBJ)
|
||||
CFLAGS_$(EC_R8169_OBJ) = -DSVNREV=$(REV)
|
||||
CFLAGS_$(EC_R8169_OBJ) = -DREV=$(REV)
|
||||
endif
|
||||
|
||||
KBUILD_EXTRA_SYMBOLS := \
|
||||
|
||||
@@ -71,7 +71,9 @@ noinst_HEADERS = \
|
||||
r8169-2.6.24-ethercat.c \
|
||||
r8169-2.6.24-orig.c \
|
||||
r8169-2.6.28-ethercat.c \
|
||||
r8169-2.6.28-orig.c
|
||||
r8169-2.6.28-orig.c \
|
||||
r8169-2.6.29-ethercat.c \
|
||||
r8169-2.6.29-orig.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
Kbuild.in
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
|
||||
TOPDIR := $(src)/../..
|
||||
|
||||
REV := $(shell if test -s $(TOPDIR)/svnrevision; then \
|
||||
cat $(TOPDIR)/svnrevision; \
|
||||
REV := $(shell if test -s $(TOPDIR)/revision; then \
|
||||
cat $(TOPDIR)/revision; \
|
||||
else \
|
||||
svnversion $(TOPDIR) 2>/dev/null || echo "unknown"; \
|
||||
hg id -i $(TOPDIR) 2>/dev/null || echo "unknown"; \
|
||||
fi)
|
||||
|
||||
ifeq (@ENABLE_E1000@,1)
|
||||
@@ -47,7 +47,7 @@ ifeq (@ENABLE_E1000@,1)
|
||||
e1000_param-@KERNEL_E1000@-ethercat.o
|
||||
obj-m += ec_e1000.o
|
||||
ec_e1000-objs := $(EC_E1000_OBJ)
|
||||
CFLAGS_e1000_main-@KERNEL_E1000@-ethercat.o = -DSVNREV=$(REV)
|
||||
CFLAGS_e1000_main-@KERNEL_E1000@-ethercat.o = -DREV=$(REV)
|
||||
endif
|
||||
|
||||
KBUILD_EXTRA_SYMBOLS := \
|
||||
|
||||
3970
devices/r8169-2.6.29-ethercat.c
Normal file
3970
devices/r8169-2.6.29-ethercat.c
Normal file
File diff suppressed because it is too large
Load Diff
3873
devices/r8169-2.6.29-orig.c
Normal file
3873
devices/r8169-2.6.29-orig.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ LATEX_OPTIONS := -file-line-error-style
|
||||
COMMANDS := \
|
||||
alias \
|
||||
config \
|
||||
cstruct \
|
||||
data \
|
||||
debug \
|
||||
domains \
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
\usepackage{listings}
|
||||
\usepackage{svn}
|
||||
\usepackage{SIunits}
|
||||
\usepackage{amsmath} % for \text{}
|
||||
\usepackage{hyperref}
|
||||
|
||||
\hypersetup{pdfpagelabels,plainpages=false}
|
||||
@@ -227,6 +228,20 @@ EtherCAT functionality (see chap.~\ref{chap:api}).
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\item Distributed Clocks support (see sec.~\ref{sec:dc}).
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\item Configuration of the slave's DC parameters through the application
|
||||
interface.
|
||||
|
||||
\item Synchronization (offset and drift compensation) of the distributed
|
||||
slave clocks to the reference clock.
|
||||
|
||||
\item Optional synchronization of the reference clock to the master clock.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\item CANopen over EtherCAT (CoE)
|
||||
|
||||
\begin{itemize}
|
||||
@@ -268,7 +283,7 @@ EtherCAT functionality (see chap.~\ref{chap:api}).
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\item Userspace command-line-tool ``ethercat`` (see sec.~\ref{sec:tool})
|
||||
\item Userspace command-line-tool ``ethercat'' (see sec.~\ref{sec:tool})
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
@@ -283,7 +298,7 @@ EtherCAT functionality (see chap.~\ref{chap:api}).
|
||||
\item Access to slave registers.
|
||||
\item Slave SII (EEPROM) access.
|
||||
\item Controlling application-layer states.
|
||||
\item Generation of slave description XML from existing slaves.
|
||||
\item Generation of slave description XML and C-code from existing slaves.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
@@ -773,10 +788,10 @@ kernelspace and uses RTAI functionality, ordinary kernel semaphores would not
|
||||
be sufficient. For that, an important design decision was made: The
|
||||
application that reserved a master must have the total control, therefore it
|
||||
has to take responsibility for providing the appropriate locking mechanisms.
|
||||
If another instance wants to access the master, it has to request the master
|
||||
lock by callbacks, that have to be set by the application. Moreover the
|
||||
application can deny access to the master if it considers it to be awkward at
|
||||
the moment.
|
||||
If another instance wants to access the master, it has to request the bus
|
||||
access via callbacks, that have to be provided by the application. Moreover
|
||||
the application can deny access to the master if it considers it to be awkward
|
||||
at the moment.
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
@@ -788,10 +803,126 @@ the moment.
|
||||
Figure~\ref{fig:locks} exemplary shows, how two processes share one master:
|
||||
The application's cyclic task uses the master for process data exchange, while
|
||||
the master-internal EoE process uses it to communicate with EoE-capable
|
||||
slaves. Both have to acquire the master lock before access: The application
|
||||
task can access the lock natively, while the EoE process has to use the
|
||||
callbacks. See the application interface documentation (chap.~\ref{chap:api})
|
||||
for how to use the locking callbacks.
|
||||
slaves. Both have to access the bus from time to time, but the EoE process
|
||||
does this by ``asking'' the application to do the bus access for it. In this
|
||||
way, the application can use the appropriate locking mechanism to avoid
|
||||
accessing the bus at the same time. See the application interface
|
||||
documentation (chap.~\ref{chap:api}) for how to use these callbacks.
|
||||
|
||||
%------------------------------------------------------------------------------
|
||||
|
||||
\section{Distributed Clocks}
|
||||
\label{sec:dc}
|
||||
\index{Distributed Clocks}
|
||||
|
||||
From version 1.5, the master supports EtherCAT's ``Distributed Clocks''
|
||||
feature. It is possible to synchronize the slave clocks on the bus to the
|
||||
``reference clock'' (which is the local clock of the first slave with DC
|
||||
support) and to synchronize the reference clock to the ``master clock'' (which
|
||||
is the local clock of the master). All other clocks on the bus (after the
|
||||
reference clock) are considered as ``slave clocks'' (see fig.~\ref{fig:dc}).
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\includegraphics[width=.8\textwidth]{images/dc}
|
||||
\caption{Distributed Clocks}
|
||||
\label{fig:dc}
|
||||
\end{figure}
|
||||
|
||||
\paragraph{Local Clocks} Any EtherCAT slave that supports DC has a local clock
|
||||
register with nanosecond resolution. If the slave is powered, the clock starts
|
||||
from zero, meaning that when slaves are powered on at different times, their
|
||||
clocks will have different values. These ``offsets'' have to be compensated by
|
||||
the distributed clocks mechanism. On the other hand, the clocks do not run
|
||||
exactly with the same speed, since the used quarts units have a natural
|
||||
frequency deviation. This deviation is usually very small, but over longer
|
||||
periods, the error would accumulate and the difference between local clocks
|
||||
would grow. This clock ``drift'' has also to be compensated by the DC
|
||||
mechanism.
|
||||
|
||||
\paragraph{Application Time} The common time base for the bus has to be
|
||||
provided by the application. This application time $t_\text{app}$ is used
|
||||
|
||||
\begin{enumerate}
|
||||
\item to configure the slaves' clock offsets (see below),
|
||||
\item to program the slave's start times for sync pulse generation (see
|
||||
below).
|
||||
\item to synchronize the reference clock to the master clock (optional).
|
||||
\end{enumerate}
|
||||
|
||||
\paragraph{Offset Compensation} For the offset compensation, each slave
|
||||
provides a ``System Time Offset'' register $t_\text{off}$, that is added to
|
||||
the internal clock value $t_\text{int}$ to get the ``System Time''
|
||||
$t_\text{sys}$:
|
||||
|
||||
\begin{eqnarray}
|
||||
t_\text{sys} & = & t_\text{int} + t_\text{off} \\
|
||||
\Rightarrow t_\text{int} & = & t_\text{sys} - t_\text{off} \nonumber
|
||||
\end{eqnarray}
|
||||
|
||||
The master reads the values of both registers to calculate a new system time
|
||||
offset in a way, that the resulting system time shall match the master's
|
||||
application time $t_\text{app}$:
|
||||
|
||||
\begin{eqnarray}
|
||||
t_\text{sys} & \stackrel{!}{=} & t_\text{app} \\
|
||||
\Rightarrow t_\text{int} + t_\text{off} & \stackrel{!}{=} & t_\text{app} \nonumber \\
|
||||
\Rightarrow t_\text{off} & = & t_\text{app} - t_\text{int} \nonumber \\
|
||||
\Rightarrow t_\text{off} & = & t_\text{app} - (t_\text{sys} - t_\text{off}) \nonumber \\
|
||||
\Rightarrow t_\text{off} & = & t_\text{app} - t_\text{sys} + t_\text{off}
|
||||
\end{eqnarray}
|
||||
|
||||
The small time offset error resulting from the different times of reading and
|
||||
writing the registers will be compensated by the drift compensation.
|
||||
|
||||
\paragraph{Drift Compensation} The drift compensation is possible due to a
|
||||
special mechanism in each DC-capable slave: A write operation to the ``System
|
||||
time'' register will cause the internal time control loop to compare the
|
||||
written time (minus the programmed transmission delay, see below) to the
|
||||
current system time. The calculated time error will be used as an input to the
|
||||
time controller, that will tune the local clock speed to be a little faster or
|
||||
slower\footnote{The local slave clock will be incremented either with
|
||||
\unit{9}{\nano\second}, \unit{10}{\nano\second} or \unit{11}{\nano\second}
|
||||
every \unit{10}{\nano\second}.}, according to the sign of the error.
|
||||
|
||||
\paragraph{Transmission Delays} The Ethernet frame needs a small amount of
|
||||
time to get from slave to slave. The resulting transmission delay times
|
||||
accumulate on the bus and can reach microsecond magnitude and thus have to be
|
||||
considered during the drift compensation. EtherCAT slaves supporting DC
|
||||
provide a mechanism to measure the transmission delays: For each of the four
|
||||
slave ports there is a receive time register. A write operation to the receive
|
||||
time register of port 0 starts the measuring and the current system time is
|
||||
latched and stored in a receive time register once the frame is received on
|
||||
the corresponding port. The master can read out the relative receive times,
|
||||
then calculate time delays between the slaves (using its knowledge of the bus
|
||||
topology), and finally calculate the time delays from the reference clock to
|
||||
each slave. These values are programmed into the slaves' transmission delay
|
||||
registers. In this way, the drift compensation can reach nanosecond synchrony.
|
||||
|
||||
\paragraph{Checking Synchrony} DC-capable slaves provide the 32-bit ``System
|
||||
time difference'' register at address \lstinline+0x092c+, where the system
|
||||
time difference of the last drift compensation is stored in nanosecond
|
||||
resolution and in sign-and-magnitude coding\footnote{This allows
|
||||
broadcast-reading all system time difference registers on the bus to get an
|
||||
upper approximation}. To check for bus synchrony, the system time difference
|
||||
registers can also be cyclically read via the command-line-tool (see
|
||||
sec.~\ref{sec:regaccess}):
|
||||
|
||||
\begin{lstlisting}
|
||||
$ `\textbf{watch -n0 "ethercat reg\_read -p4 -tint32 0x92c"}`
|
||||
\end{lstlisting}
|
||||
|
||||
\paragraph{Sync Signals} Synchronous clocks are only the prerequisite for
|
||||
synchronous events on the bus. Each slave with DC support provides two ``sync
|
||||
signals'', that can be programmed to create events, that will for example
|
||||
cause the slave application to latch its inputs on a certain time. A sync
|
||||
event can either be generated once or cyclically, depending on what makes
|
||||
sense for the slave application. Programming the sync signals is a matter of
|
||||
setting the so-called ``AssignActivate'' word and the sync signals' cycle- and
|
||||
shift times. The AssignActivate word is slave-specific and has to be taken
|
||||
from the XML slave description (\lstinline+Device+ $\rightarrow$
|
||||
\lstinline+Dc+), where also typical sync signal configurations ``OpModes'' can
|
||||
be found.
|
||||
|
||||
%------------------------------------------------------------------------------
|
||||
|
||||
@@ -2088,6 +2219,13 @@ sec.~\ref{sec:autonode} for how to install and configure it.
|
||||
|
||||
%------------------------------------------------------------------------------
|
||||
|
||||
\subsection{Output PDO information in C Language}
|
||||
\label{sec:ethercat-cstruct}
|
||||
|
||||
\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_cstruct}
|
||||
|
||||
%------------------------------------------------------------------------------
|
||||
|
||||
\subsection{Displaying Process Data}
|
||||
|
||||
\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_data}
|
||||
@@ -2148,6 +2286,7 @@ sec.~\ref{sec:autonode} for how to install and configure it.
|
||||
%------------------------------------------------------------------------------
|
||||
|
||||
\subsection{Register Access}
|
||||
\label{sec:regaccess}
|
||||
|
||||
\lstinputlisting[basicstyle=\ttfamily\footnotesize]{external/ethercat_reg_read}
|
||||
|
||||
@@ -2315,10 +2454,10 @@ character device (see chap.~\ref{chap:arch}, fig.~\ref{fig:arch} and
|
||||
sec.~\ref{sec:cdev}).
|
||||
|
||||
The function calls of the kernel API are mapped to the userspace via an
|
||||
\lstinline+ioctl()+ interface. Each function has its own \lstinline+ioctl()+
|
||||
call. The kernel part of the interface calls the according API functions
|
||||
directly, what results in a minimum additional delay (see
|
||||
sec.~\ref{sec:usertiming}).
|
||||
\lstinline+ioctl()+ interface. The userspace API functions share a set of
|
||||
generic \lstinline+ioctl()+ calls. The kernel part of the interface calls the
|
||||
according API functions directly, what results in a minimum additional delay
|
||||
(see sec.~\ref{sec:usertiming}).
|
||||
|
||||
For performance reasons, the actual domain process data (see
|
||||
sec.~\ref{sec:processdata}) are not copied between kernel and user memory on
|
||||
|
||||
@@ -8,6 +8,7 @@ FIGS := \
|
||||
app-config.fig \
|
||||
architecture.fig \
|
||||
attach.fig \
|
||||
dc.fig \
|
||||
fmmus.fig \
|
||||
fsm-coedown.fig \
|
||||
fsm-eoe.fig \
|
||||
|
||||
136
documentation/images/dc.fig
Normal file
136
documentation/images/dc.fig
Normal file
@@ -0,0 +1,136 @@
|
||||
#FIG 3.2
|
||||
Portrait
|
||||
Center
|
||||
Metric
|
||||
A4
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
6 1215 1035 1755 1575
|
||||
1 3 0 1 0 7 50 -1 20 0.000 1 0.0000 1485 1305 225 225 1485 1305 1710 1305
|
||||
1 3 0 1 7 7 48 -1 20 0.000 1 0.0000 1485 1305 162 162 1485 1305 1647 1305
|
||||
1 3 0 1 7 0 47 -1 20 0.000 1 0.0000 1485 1305 23 23 1485 1305 1508 1305
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1485 1080 1485 1530
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1598 1110 1372 1500
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1680 1193 1290 1417
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1710 1305 1260 1305
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1680 1418 1290 1193
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1598 1500 1373 1110
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1485 1305 1530 1125
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1485 1305 1575 1260
|
||||
-6
|
||||
6 4950 1890 5490 2430
|
||||
1 3 0 1 0 7 50 -1 20 0.000 1 0.0000 5220 2160 225 225 5220 2160 5445 2160
|
||||
1 3 0 1 7 7 48 -1 20 0.000 1 0.0000 5220 2160 162 162 5220 2160 5382 2160
|
||||
1 3 0 1 7 0 47 -1 20 0.000 1 0.0000 5220 2160 23 23 5220 2160 5243 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5220 1935 5220 2385
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5333 1965 5107 2355
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5415 2048 5025 2272
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5445 2160 4995 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5415 2273 5025 2048
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5333 2355 5108 1965
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5220 2160 5265 1980
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5220 2160 5310 2115
|
||||
-6
|
||||
6 6030 1305 7380 2475
|
||||
6 6795 1890 7335 2430
|
||||
1 3 0 1 0 7 50 -1 20 0.000 1 0.0000 7065 2160 225 225 7065 2160 7290 2160
|
||||
1 3 0 1 7 7 48 -1 20 0.000 1 0.0000 7065 2160 162 162 7065 2160 7227 2160
|
||||
1 3 0 1 7 0 47 -1 20 0.000 1 0.0000 7065 2160 23 23 7065 2160 7088 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7065 1935 7065 2385
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7178 1965 6952 2355
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7260 2048 6870 2272
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7290 2160 6840 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7260 2273 6870 2048
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7178 2355 6953 1965
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7065 2160 7110 1980
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
7065 2160 7155 2115
|
||||
-6
|
||||
2 4 0 1 0 7 51 -1 20 0.000 0 0 8 0 0 5
|
||||
7380 2475 6030 2475 6030 1305 7380 1305 7380 2475
|
||||
4 1 0 49 -1 16 16 0.0000 4 180 810 6705 1665 Slave 2\001
|
||||
-6
|
||||
6 7875 1305 9225 2475
|
||||
6 8640 1890 9180 2430
|
||||
1 3 0 1 0 7 50 -1 20 0.000 1 0.0000 8910 2160 225 225 8910 2160 9135 2160
|
||||
1 3 0 1 7 7 48 -1 20 0.000 1 0.0000 8910 2160 162 162 8910 2160 9072 2160
|
||||
1 3 0 1 7 0 47 -1 20 0.000 1 0.0000 8910 2160 23 23 8910 2160 8933 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
8910 1935 8910 2385
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9023 1965 8797 2355
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9105 2048 8715 2272
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9135 2160 8685 2160
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9105 2273 8715 2048
|
||||
2 1 0 1 0 7 49 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9023 2355 8798 1965
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
8910 2160 8955 1980
|
||||
2 1 0 1 0 7 47 -1 -1 0.000 0 0 -1 0 0 2
|
||||
8910 2160 9000 2115
|
||||
-6
|
||||
2 4 0 1 0 7 51 -1 20 0.000 0 0 8 0 0 5
|
||||
9225 2475 7875 2475 7875 1305 9225 1305 9225 2475
|
||||
4 1 0 49 -1 16 16 0.0000 4 180 810 8550 1665 Slave n\001
|
||||
-6
|
||||
2 4 0 1 0 7 51 -1 20 0.000 0 0 8 0 0 5
|
||||
1800 1620 450 1620 450 450 1800 450 1800 1620
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1800 1080 2340 1935
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3690 1935 4185 1935
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1125 1935 1350 1530
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
4860 2880 5094 2391
|
||||
2 4 0 1 0 7 51 -1 20 0.000 0 0 8 0 0 5
|
||||
5535 2475 4185 2475 4185 1305 5535 1305 5535 2475
|
||||
2 4 0 1 0 7 51 -1 20 0.000 0 0 8 0 0 5
|
||||
3690 2475 2340 2475 2340 1305 3690 1305 3690 2475
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
5535 1935 6030 1935
|
||||
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||
7380 1935 7875 1935
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
8370 2880 8730 2385
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
7470 2880 7224 2391
|
||||
4 1 0 49 -1 16 16 0.0000 4 180 735 1125 810 Master\001
|
||||
4 1 0 50 -1 16 16 0.0000 4 180 1800 4860 3105 Reference Clock\001
|
||||
4 1 0 50 -1 16 16 0.0000 4 180 1410 1125 2250 Master Clock\001
|
||||
4 1 0 49 -1 16 16 0.0000 4 180 810 4860 1665 Slave 1\001
|
||||
4 1 0 49 -1 16 16 0.0000 4 180 810 3015 1665 Slave 0\001
|
||||
4 1 0 49 -1 16 10 0.0000 4 150 615 3015 2205 (No DC)\001
|
||||
4 1 0 50 -1 16 16 0.0000 4 180 1395 7920 3105 Slave Clocks\001
|
||||
@@ -238,24 +238,28 @@ void run(long data)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void send_callback(ec_master_t *master)
|
||||
void send_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
ecrt_master_send_ext(m);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void receive_callback(ec_master_t *master)
|
||||
void receive_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_master_receive(m);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
@@ -281,7 +285,7 @@ int __init init_mod(void)
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback, master);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
||||
@@ -354,19 +354,21 @@ void cyclic_task(unsigned long data)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void send_callback(ec_master_t *master)
|
||||
void send_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
down(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
ecrt_master_send_ext(m);
|
||||
up(&master_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void receive_callback(ec_master_t *master)
|
||||
void receive_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
down(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_master_receive(m);
|
||||
up(&master_sem);
|
||||
}
|
||||
|
||||
@@ -392,8 +394,7 @@ int __init init_mini_module(void)
|
||||
}
|
||||
|
||||
sema_init(&master_sem, 1);
|
||||
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback, master);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
||||
@@ -243,24 +243,28 @@ void run(long data)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void send_callback(ec_master_t *master)
|
||||
void send_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
ecrt_master_send_ext(m);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void receive_callback(ec_master_t *master)
|
||||
void receive_callback(void *cb_data)
|
||||
{
|
||||
ec_master_t *m = (ec_master_t *) cb_data;
|
||||
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_master_receive(m);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
@@ -288,7 +292,7 @@ int __init init_mod(void)
|
||||
goto out_return;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback, master);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
/** Master version string
|
||||
*/
|
||||
#define EC_MASTER_VERSION VERSION " r" EC_STR(SVNREV)
|
||||
#define EC_MASTER_VERSION VERSION " " EC_STR(REV)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
* ecrt_slave_config_dc() to configure a slave for cyclic operation, and
|
||||
* ecrt_master_application_time(), ecrt_master_sync_reference_clock() and
|
||||
* ecrt_master_sync_slave_clocks() for offset and drift compensation. The
|
||||
* EC_TIMEVAL2NANO() macro can be used for epoch time conversion.
|
||||
* EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the
|
||||
* ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process()
|
||||
* methods can be used to monitor the synchrony.
|
||||
* - Improved the callback mechanism. ecrt_master_callbacks() now takes two
|
||||
* callback functions for sending and receiving datagrams.
|
||||
* ecrt_master_send_ext() is used to execute the sending of non-application
|
||||
@@ -53,6 +55,9 @@
|
||||
* - Added watchdog configuration (method ecrt_slave_config_watchdog(),
|
||||
* #ec_watchdog_mode_t, \a watchdog_mode parameter in ec_sync_info_t and
|
||||
* ecrt_slave_config_sync_manager()).
|
||||
* - Added ecrt_slave_config_complete_sdo() method to download an SDO during
|
||||
* configuration via CompleteAccess.
|
||||
* - Added ecrt_master_deactivate() to remove the bus configuration.
|
||||
* - Added ecrt_open_master() and ecrt_master_reserve() separation for
|
||||
* userspace.
|
||||
* - Added bus information interface (methods ecrt_master(),
|
||||
@@ -63,7 +68,7 @@
|
||||
* methods to let an application transfer SDOs before activating the master.
|
||||
* - Changed the meaning of the negative return values of
|
||||
* ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
|
||||
* - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See
|
||||
* - Implemented the Vendor-specific over EtherCAT mailbox protocol. See
|
||||
* ecrt_slave_config_create_voe_handler().
|
||||
* - Renamed ec_sdo_request_state_t to #ec_request_state_t, because it is also
|
||||
* used by VoE handlers.
|
||||
@@ -129,7 +134,7 @@
|
||||
|
||||
/** Timeval to nanoseconds conversion.
|
||||
*
|
||||
* This macro converts a unix epoch time to EtherCAT DC time.
|
||||
* This macro converts a Unix epoch time to EtherCAT DC time.
|
||||
*
|
||||
* \see void ecrt_master_application_time()
|
||||
*
|
||||
@@ -237,7 +242,7 @@ typedef struct {
|
||||
uint8_t al_state; /**< Current state of the slave. */
|
||||
uint8_t error_flag; /**< Error flag for that slave. */
|
||||
uint8_t sync_count; /**< Number of sync managers. */
|
||||
uint16_t sdo_count; /**< Number of SDO's. */
|
||||
uint16_t sdo_count; /**< Number of SDOs. */
|
||||
char name[EC_MAX_STRING_LENGTH]; /**< Name of the slave. */
|
||||
} ec_slave_info_t;
|
||||
|
||||
@@ -469,8 +474,8 @@ int ecrt_master_reserve(
|
||||
* its parameters. Asynchronous master access (like EoE processing) is only
|
||||
* possible if the callbacks have been set.
|
||||
*
|
||||
* The task of the send callback (\a request_cb) is to decide, if the bus is
|
||||
* currently accessible. In this case, it can call the ecrt_master_send_ext()
|
||||
* The task of the send callback (\a send_cb) is to decide, if the bus is
|
||||
* currently accessible and whether or not to call the ecrt_master_send_ext()
|
||||
* method.
|
||||
*
|
||||
* The task of the receive callback (\a receive_cb) is to decide, if a call to
|
||||
@@ -478,8 +483,10 @@ int ecrt_master_reserve(
|
||||
*/
|
||||
void ecrt_master_callbacks(
|
||||
ec_master_t *master, /**< EtherCAT master */
|
||||
void (*send_cb)(ec_master_t *), /**< Datagram sending callback. */
|
||||
void (*receive_cb)(ec_master_t *) /**< Receive callback. */
|
||||
void (*send_cb)(void *), /**< Datagram sending callback. */
|
||||
void (*receive_cb)(void *), /**< Receive callback. */
|
||||
void *cb_data /**< Arbitraty pointer passed to the callback functions.
|
||||
*/
|
||||
);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
@@ -644,7 +651,7 @@ int ecrt_master_sdo_download(
|
||||
* processing.
|
||||
*
|
||||
* \retval 0 Success.
|
||||
* \retval -1 Error occured.
|
||||
* \retval -1 Error occurred.
|
||||
*/
|
||||
int ecrt_master_sdo_upload(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
@@ -679,6 +686,18 @@ int ecrt_master_activate(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Deactivates the master.
|
||||
*
|
||||
* Removes the bus configuration. All objects created by
|
||||
* ecrt_master_create_domain(), ecrt_master_slave_config(), ecrt_domain_data()
|
||||
* ecrt_slave_config_create_sdo_request() and
|
||||
* ecrt_slave_config_create_voe_handler() are freed, so pointers to them
|
||||
* become invalid.
|
||||
*/
|
||||
void ecrt_master_deactivate(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Sends all datagrams in the queue.
|
||||
*
|
||||
* This method takes all datagrams, that have been queued for transmission,
|
||||
@@ -759,6 +778,28 @@ void ecrt_master_sync_slave_clocks(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Queues the DC synchonity monitoring datagram for sending.
|
||||
*
|
||||
* The datagram broadcast-reads all "System time difference" registers (\a
|
||||
* 0x092c) to get an upper estiomation of the DC synchony. The result can be
|
||||
* checked with the ecrt_master_sync_monitor_process() method.
|
||||
*/
|
||||
void ecrt_master_sync_monitor_queue(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Processes the DC synchonity monitoring datagram.
|
||||
*
|
||||
* If the sync monitoring datagram was sent before with
|
||||
* ecrt_master_sync_monitor_queue(), the result can be queried with this
|
||||
* method.
|
||||
*
|
||||
* \return Upper estination of the maximum time difference in ns.
|
||||
*/
|
||||
uint32_t ecrt_master_sync_monitor_process(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/******************************************************************************
|
||||
* Slave configuration methods
|
||||
*****************************************************************************/
|
||||
@@ -779,13 +820,17 @@ int ecrt_slave_config_sync_manager(
|
||||
);
|
||||
|
||||
/** Configure a slave's watchdog times.
|
||||
*/
|
||||
*/
|
||||
void ecrt_slave_config_watchdog(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint16_t watchdog_divider, /**< Number of 40 ns intervals. Used as a
|
||||
base unit for all slave watchdogs. */
|
||||
base unit for all slave watchdogs. If set
|
||||
to zero, the value is not written, so the
|
||||
default ist used. */
|
||||
uint16_t watchdog_intervals /**< Number of base intervals for process
|
||||
data watchdog. */
|
||||
data watchdog. If set to zero, the value
|
||||
is not written, so the default is used.
|
||||
*/
|
||||
);
|
||||
|
||||
/** Add a PDO to a sync manager's PDO assignment.
|
||||
@@ -1031,6 +1076,23 @@ int ecrt_slave_config_sdo32(
|
||||
uint32_t value /**< Value to set. */
|
||||
);
|
||||
|
||||
/** Add configuration data for a complete SDO.
|
||||
*
|
||||
* The SDO data are transferred via CompleteAccess. Data for the first
|
||||
* subindex (0) have to be included.
|
||||
*
|
||||
* \see ecrt_slave_config_sdo().
|
||||
*
|
||||
* \retval 0 Success.
|
||||
* \retval <0 Error code.
|
||||
*/
|
||||
int ecrt_slave_config_complete_sdo(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint16_t index, /**< Index of the SDO to configure. */
|
||||
const uint8_t *data, /**< Pointer to the data. */
|
||||
size_t size /**< Size of the \a data. */
|
||||
);
|
||||
|
||||
/** Create an SDO request to exchange SDOs during realtime operation.
|
||||
*
|
||||
* The created SDO request object is freed automatically when the master is
|
||||
|
||||
35
lib/master.c
35
lib/master.c
@@ -336,6 +336,16 @@ int ecrt_master_activate(ec_master_t *master)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_deactivate(ec_master_t *master)
|
||||
{
|
||||
if (ioctl(master->fd, EC_IOCTL_DEACTIVATE, NULL) == -1) {
|
||||
fprintf(stderr, "Failed to deactivate master: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_send(ec_master_t *master)
|
||||
{
|
||||
if (ioctl(master->fd, EC_IOCTL_SEND, NULL) == -1) {
|
||||
@@ -395,3 +405,28 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
||||
{
|
||||
if (ioctl(master->fd, EC_IOCTL_SYNC_MON_QUEUE, NULL) == -1) {
|
||||
fprintf(stderr, "Failed to queue sync monitor datagram: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
|
||||
{
|
||||
uint32_t time_diff;
|
||||
|
||||
if (ioctl(master->fd, EC_IOCTL_SYNC_MON_PROCESS, &time_diff) == -1) {
|
||||
time_diff = 0xffffffff;
|
||||
fprintf(stderr, "Failed to process sync monitor datagram: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return time_diff;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -294,6 +294,29 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||
data.subindex = subindex;
|
||||
data.data = sdo_data;
|
||||
data.size = size;
|
||||
data.complete_access = 0;
|
||||
|
||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
|
||||
fprintf(stderr, "Failed to configure SDO.\n");
|
||||
return -1; // FIXME
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||
const uint8_t *sdo_data, size_t size)
|
||||
{
|
||||
ec_ioctl_sc_sdo_t data;
|
||||
|
||||
data.config_index = sc->index;
|
||||
data.index = index;
|
||||
data.subindex = 0;
|
||||
data.data = sdo_data;
|
||||
data.size = size;
|
||||
data.complete_access = 1;
|
||||
|
||||
if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
|
||||
fprintf(stderr, "Failed to configure SDO.\n");
|
||||
|
||||
@@ -71,12 +71,12 @@ ifeq (@ENABLE_DEBUG_IF@,1)
|
||||
ec_master-objs += debug.o
|
||||
endif
|
||||
|
||||
REV := $(shell if test -s $(src)/../svnrevision; then \
|
||||
cat $(src)/../svnrevision; \
|
||||
REV := $(shell if test -s $(src)/../revision; then \
|
||||
cat $(src)/../revision; \
|
||||
else \
|
||||
svnversion $(src)/.. 2>/dev/null || echo "unknown"; \
|
||||
hg id -i $(src)/.. 2>/dev/null || echo "unknown"; \
|
||||
fi)
|
||||
|
||||
CFLAGS_module.o := -DSVNREV=$(REV)
|
||||
CFLAGS_module.o := -DREV=$(REV)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
@@ -171,8 +171,11 @@ int ec_cdev_ioctl_master(
|
||||
data.slave_count = master->slave_count;
|
||||
data.config_count = ec_master_config_count(master);
|
||||
data.domain_count = ec_master_domain_count(master);
|
||||
#ifdef EC_EOE
|
||||
data.eoe_handler_count = ec_master_eoe_handler_count(master);
|
||||
#endif
|
||||
data.phase = (uint8_t) master->phase;
|
||||
data.active = (uint8_t) master->active;
|
||||
data.scan_busy = master->scan_busy;
|
||||
up(&master->master_sem);
|
||||
|
||||
@@ -1256,9 +1259,12 @@ int ec_cdev_ioctl_config(
|
||||
data.product_code = sc->product_code;
|
||||
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) {
|
||||
data.syncs[i].dir = sc->sync_configs[i].dir;
|
||||
data.syncs[i].watchdog_mode = sc->sync_configs[i].watchdog_mode;
|
||||
data.syncs[i].pdo_count =
|
||||
ec_pdo_list_count(&sc->sync_configs[i].pdos);
|
||||
}
|
||||
data.watchdog_divider = sc->watchdog_divider;
|
||||
data.watchdog_intervals = sc->watchdog_intervals;
|
||||
data.sdo_count = ec_slave_config_sdo_count(sc);
|
||||
data.slave_position = sc->slave ? sc->slave->ring_position : -1;
|
||||
data.dc_assign_activate = sc->dc_assign_activate;
|
||||
@@ -1429,7 +1435,8 @@ int ec_cdev_ioctl_config_sdo(
|
||||
data.index = req->index;
|
||||
data.subindex = req->subindex;
|
||||
data.size = req->data_size;
|
||||
memcpy(&data.data, req->data, min((u32) data.size, (u32) 4));
|
||||
memcpy(&data.data, req->data,
|
||||
min((u32) data.size, (u32) EC_MAX_SDO_DATA_SIZE));
|
||||
|
||||
up(&master->master_sem);
|
||||
|
||||
@@ -1441,6 +1448,8 @@ int ec_cdev_ioctl_config_sdo(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
|
||||
/** Get EoE handler information.
|
||||
*/
|
||||
int ec_cdev_ioctl_eoe_handler(
|
||||
@@ -1486,6 +1495,8 @@ int ec_cdev_ioctl_eoe_handler(
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Request the master from userspace.
|
||||
@@ -1622,7 +1633,7 @@ int ec_cdev_ioctl_activate(
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, ec_master_internal_send_cb,
|
||||
ec_master_internal_receive_cb);
|
||||
ec_master_internal_receive_cb, master);
|
||||
|
||||
ret = ecrt_master_activate(master);
|
||||
if (ret < 0)
|
||||
@@ -1637,6 +1648,23 @@ int ec_cdev_ioctl_activate(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Deactivates the master.
|
||||
*/
|
||||
int ec_cdev_ioctl_deactivate(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
unsigned long arg, /**< ioctl() argument. */
|
||||
ec_cdev_priv_t *priv /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
if (unlikely(!priv->requested))
|
||||
return -EPERM;
|
||||
|
||||
ecrt_master_deactivate(master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Send frames.
|
||||
*/
|
||||
int ec_cdev_ioctl_send(
|
||||
@@ -1759,6 +1787,50 @@ int ec_cdev_ioctl_sync_slaves(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Queue the sync monitoring datagram.
|
||||
*/
|
||||
int ec_cdev_ioctl_sync_mon_queue(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
unsigned long arg, /**< ioctl() argument. */
|
||||
ec_cdev_priv_t *priv /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
if (unlikely(!priv->requested))
|
||||
return -EPERM;
|
||||
|
||||
down(&master->io_sem);
|
||||
ecrt_master_sync_monitor_queue(master);
|
||||
up(&master->io_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Processes the sync monitoring datagram.
|
||||
*/
|
||||
int ec_cdev_ioctl_sync_mon_process(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
unsigned long arg, /**< ioctl() argument. */
|
||||
ec_cdev_priv_t *priv /**< Private data structure of file handle. */
|
||||
)
|
||||
{
|
||||
uint32_t time_diff;
|
||||
|
||||
if (unlikely(!priv->requested))
|
||||
return -EPERM;
|
||||
|
||||
down(&master->io_sem);
|
||||
time_diff = ecrt_master_sync_monitor_process(master);
|
||||
up(&master->io_sem);
|
||||
|
||||
if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Configure a sync manager.
|
||||
*/
|
||||
int ec_cdev_ioctl_sc_sync(
|
||||
@@ -2111,8 +2183,12 @@ int ec_cdev_ioctl_sc_sdo(
|
||||
|
||||
up(&master->master_sem); // FIXME
|
||||
|
||||
ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data,
|
||||
data.size);
|
||||
if (data.complete_access) {
|
||||
ret = ecrt_slave_config_complete_sdo(sc, data.index, sdo_data, data.size);
|
||||
} else {
|
||||
ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data,
|
||||
data.size);
|
||||
}
|
||||
kfree(sdo_data);
|
||||
return ret;
|
||||
}
|
||||
@@ -3228,8 +3304,10 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
return ec_cdev_ioctl_config_pdo_entry(master, arg);
|
||||
case EC_IOCTL_CONFIG_SDO:
|
||||
return ec_cdev_ioctl_config_sdo(master, arg);
|
||||
#ifdef EC_EOE
|
||||
case EC_IOCTL_EOE_HANDLER:
|
||||
return ec_cdev_ioctl_eoe_handler(master, arg);
|
||||
#endif
|
||||
case EC_IOCTL_REQUEST:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
@@ -3246,6 +3324,10 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_activate(master, arg, priv);
|
||||
case EC_IOCTL_DEACTIVATE:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_deactivate(master, arg, priv);
|
||||
case EC_IOCTL_SEND:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
@@ -3268,6 +3350,14 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_sync_slaves(master, arg, priv);
|
||||
case EC_IOCTL_SYNC_MON_QUEUE:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_sync_mon_queue(master, arg, priv);
|
||||
case EC_IOCTL_SYNC_MON_PROCESS:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ec_cdev_ioctl_sync_mon_process(master, arg, priv);
|
||||
case EC_IOCTL_SC_SYNC:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
|
||||
@@ -506,6 +506,12 @@ void ecdev_receive(
|
||||
{
|
||||
const void *ec_data = data + ETH_HLEN;
|
||||
size_t ec_size = size - ETH_HLEN;
|
||||
|
||||
if (unlikely(!data)) {
|
||||
EC_WARN("%s() called with NULL data.\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
device->rx_count++;
|
||||
|
||||
if (unlikely(device->master->debug_level > 1)) {
|
||||
|
||||
@@ -1074,8 +1074,14 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
uint8_t size;
|
||||
|
||||
if (fsm->slave->master->debug_level) {
|
||||
EC_DBG("Downloading SDO 0x%04X:%02X to slave %u.\n",
|
||||
request->index, request->subindex, slave->ring_position);
|
||||
char subidxstr[10];
|
||||
if (request->complete_access) {
|
||||
subidxstr[0] = 0x00;
|
||||
} else {
|
||||
sprintf(subidxstr, ":%02X", request->subindex);
|
||||
}
|
||||
EC_DBG("Downloading SDO 0x%04X%s to slave %u.\n",
|
||||
request->index, subidxstr, slave->ring_position);
|
||||
ec_print_data(request->data, request->data_size);
|
||||
}
|
||||
|
||||
@@ -1097,9 +1103,11 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
EC_WRITE_U16(data, 0x2 << 12); // SDO request
|
||||
EC_WRITE_U8 (data + 2, (0x3 // size specified, expedited
|
||||
| size << 2
|
||||
| ((request->complete_access ? 1 : 0) << 4)
|
||||
| 0x1 << 5)); // Download request
|
||||
EC_WRITE_U16(data + 3, request->index);
|
||||
EC_WRITE_U8 (data + 5, request->subindex);
|
||||
EC_WRITE_U8 (data + 5,
|
||||
request->complete_access ? 0x00 : request->subindex);
|
||||
memcpy(data + 6, request->data, request->data_size);
|
||||
memset(data + 6 + request->data_size, 0x00, 4 - request->data_size);
|
||||
|
||||
@@ -1110,7 +1118,7 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
}
|
||||
else { // request->data_size > 4, use normal transfer type
|
||||
if (slave->configured_rx_mailbox_size < 6 + 10 + request->data_size) {
|
||||
EC_ERR("SDO fragmenting not supported yet!\n");
|
||||
EC_ERR("SDO fragmenting not supported yet!\n"); // FIXME
|
||||
fsm->state = ec_fsm_coe_error;
|
||||
return;
|
||||
}
|
||||
@@ -1124,9 +1132,11 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
|
||||
EC_WRITE_U16(data, 0x2 << 12); // SDO request
|
||||
EC_WRITE_U8 (data + 2, (0x1 // size indicator, normal
|
||||
| ((request->complete_access ? 1 : 0) << 4)
|
||||
| 0x1 << 5)); // Download request
|
||||
EC_WRITE_U16(data + 3, request->index);
|
||||
EC_WRITE_U8 (data + 5, request->subindex);
|
||||
EC_WRITE_U8 (data + 5,
|
||||
request->complete_access ? 0x00 : request->subindex);
|
||||
EC_WRITE_U32(data + 6, request->data_size);
|
||||
memcpy(data + 10, request->data, request->data_size);
|
||||
|
||||
@@ -1311,12 +1321,18 @@ void ec_fsm_coe_down_response(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
|
||||
EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
|
||||
char subidxstr[10];
|
||||
fsm->state = ec_fsm_coe_error;
|
||||
EC_ERR("SDO download 0x%04X:%02X (%u bytes) aborted on slave %u.\n",
|
||||
request->index, request->subindex, request->data_size,
|
||||
slave->ring_position);
|
||||
if (request->complete_access) {
|
||||
subidxstr[0] = 0x00;
|
||||
} else {
|
||||
sprintf(subidxstr, ":%02X", request->subindex);
|
||||
}
|
||||
EC_ERR("SDO download 0x%04X%s (%u bytes) aborted on slave %u.\n",
|
||||
request->index, subidxstr, request->data_size,
|
||||
slave->ring_position);
|
||||
if (rec_size < 10) {
|
||||
EC_ERR("Incomplete Abort command:\n");
|
||||
EC_ERR("Incomplete abort command:\n");
|
||||
ec_print_data(data, rec_size);
|
||||
} else {
|
||||
fsm->request->abort_code = EC_READ_U32(data + 6);
|
||||
@@ -1805,7 +1821,6 @@ void ec_fsm_coe_up_seg_response(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
uint8_t *data, mbox_prot;
|
||||
size_t rec_size, data_size;
|
||||
ec_sdo_request_t *request = fsm->request;
|
||||
uint32_t seg_size;
|
||||
unsigned int last_segment;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
@@ -1883,14 +1898,11 @@ void ec_fsm_coe_up_seg_response(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
return;
|
||||
}
|
||||
|
||||
last_segment = EC_READ_U8(data + 2) & 0x01;
|
||||
seg_size = (EC_READ_U8(data + 2) & 0xE) >> 1;
|
||||
if (rec_size > 10) {
|
||||
data_size = rec_size - 3; /* Header of segment upload is smaller than
|
||||
normal upload */
|
||||
} else { // == 10
|
||||
/* seg_size contains the number of trailing bytes to ignore. */
|
||||
data_size = rec_size - seg_size;
|
||||
data_size = rec_size - 3; /* Header of segment upload is smaller than
|
||||
normal upload */
|
||||
if (rec_size == 10) {
|
||||
uint8_t seg_size = (EC_READ_U8(data + 2) & 0xE) >> 1;
|
||||
data_size -= seg_size;
|
||||
}
|
||||
|
||||
if (request->data_size + data_size > fsm->complete_size) {
|
||||
@@ -1904,6 +1916,7 @@ void ec_fsm_coe_up_seg_response(ec_fsm_coe_t *fsm /**< finite state machine */)
|
||||
memcpy(request->data + request->data_size, data + 3, data_size);
|
||||
request->data_size += data_size;
|
||||
|
||||
last_segment = EC_READ_U8(data + 2) & 0x01;
|
||||
if (!last_segment) {
|
||||
fsm->toggle = !fsm->toggle;
|
||||
ec_fsm_coe_up_prepare_segment_request(fsm);
|
||||
|
||||
@@ -933,9 +933,9 @@ void ec_fsm_slave_config_enter_watchdog(
|
||||
|
||||
fsm->retries = EC_FSM_RETRIES;
|
||||
fsm->state = ec_fsm_slave_config_state_watchdog;
|
||||
} else {
|
||||
ec_fsm_slave_config_enter_pdo_sync(fsm);
|
||||
}
|
||||
|
||||
ec_fsm_slave_config_enter_pdo_sync(fsm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -77,47 +77,52 @@
|
||||
#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x15, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x16, ec_ioctl_config_pdo_entry_t)
|
||||
#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x17, ec_ioctl_config_sdo_t)
|
||||
#ifdef EC_EOE
|
||||
#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x18, ec_ioctl_eoe_handler_t)
|
||||
#endif
|
||||
|
||||
// Application interface
|
||||
#define EC_IOCTL_REQUEST EC_IO(0x19)
|
||||
#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1a)
|
||||
#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x1b, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_ACTIVATE EC_IOR(0x1c, size_t)
|
||||
#define EC_IOCTL_SEND EC_IO(0x1d)
|
||||
#define EC_IOCTL_RECEIVE EC_IO(0x1e)
|
||||
#define EC_IOCTL_MASTER_STATE EC_IOR(0x1f, ec_master_state_t)
|
||||
#define EC_IOCTL_APP_TIME EC_IOW(0x20, ec_ioctl_app_time_t)
|
||||
#define EC_IOCTL_SYNC_REF EC_IO(0x21)
|
||||
#define EC_IOCTL_SYNC_SLAVES EC_IO(0x22)
|
||||
#define EC_IOCTL_SC_SYNC EC_IOW(0x23, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x24, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x25, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x26, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x27, ec_ioctl_add_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x28, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x29, ec_ioctl_reg_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_DC EC_IOW(0x2a, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_SDO EC_IOW(0x2b, ec_ioctl_sc_sdo_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2c, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x2d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x2e, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x2f)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x20)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x31)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x32, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x33, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x34, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x35, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x36, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x37, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x38, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x39, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x3a, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x3d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x3e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_DEACTIVATE EC_IO(0x1d)
|
||||
#define EC_IOCTL_SEND EC_IO(0x1e)
|
||||
#define EC_IOCTL_RECEIVE EC_IO(0x1f)
|
||||
#define EC_IOCTL_MASTER_STATE EC_IOR(0x20, ec_master_state_t)
|
||||
#define EC_IOCTL_APP_TIME EC_IOW(0x21, ec_ioctl_app_time_t)
|
||||
#define EC_IOCTL_SYNC_REF EC_IO(0x22)
|
||||
#define EC_IOCTL_SYNC_SLAVES EC_IO(0x23)
|
||||
#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x24)
|
||||
#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x25, uint32_t)
|
||||
#define EC_IOCTL_SC_SYNC EC_IOW(0x26, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x27, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x28, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x29, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x2a, ec_ioctl_add_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x2b, ec_ioctl_config_pdo_t)
|
||||
#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x2c, ec_ioctl_reg_pdo_entry_t)
|
||||
#define EC_IOCTL_SC_DC EC_IOW(0x2d, ec_ioctl_config_t)
|
||||
#define EC_IOCTL_SC_SDO EC_IOW(0x2e, ec_ioctl_sc_sdo_t)
|
||||
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2f, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SC_VOE EC_IOWR(0x20, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SC_STATE EC_IOWR(0x31, ec_ioctl_sc_state_t)
|
||||
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x32)
|
||||
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x33)
|
||||
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x34)
|
||||
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x35, ec_ioctl_domain_state_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x36, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x37, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x38, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x39, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x3a, ec_ioctl_sdo_request_t)
|
||||
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x3b, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x3c, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ EC_IOW(0x3d, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3e, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3f, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x40, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x41, ec_ioctl_voe_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -129,8 +134,11 @@ typedef struct {
|
||||
uint32_t slave_count;
|
||||
uint32_t config_count;
|
||||
uint32_t domain_count;
|
||||
#ifdef EC_EOE
|
||||
uint32_t eoe_handler_count;
|
||||
#endif
|
||||
uint8_t phase;
|
||||
uint8_t active;
|
||||
uint8_t scan_busy;
|
||||
struct {
|
||||
uint8_t address[6];
|
||||
@@ -434,6 +442,11 @@ typedef struct {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Maximum size for displayed SDO data.
|
||||
* \todo Make this dynamic.
|
||||
*/
|
||||
#define EC_MAX_SDO_DATA_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
// inputs
|
||||
uint32_t config_index;
|
||||
@@ -443,11 +456,13 @@ typedef struct {
|
||||
uint16_t index;
|
||||
uint8_t subindex;
|
||||
uint32_t size;
|
||||
uint8_t data[4];
|
||||
uint8_t data[EC_MAX_SDO_DATA_SIZE];
|
||||
} ec_ioctl_config_sdo_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
|
||||
typedef struct {
|
||||
// input
|
||||
uint16_t eoe_index;
|
||||
@@ -464,6 +479,8 @@ typedef struct {
|
||||
uint32_t tx_queue_size;
|
||||
} ec_ioctl_eoe_handler_t;
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
@@ -497,6 +514,7 @@ typedef struct {
|
||||
uint8_t subindex;
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
uint8_t complete_access;
|
||||
} ec_ioctl_sc_sdo_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
217
master/master.c
217
master/master.c
@@ -122,6 +122,7 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
sema_init(&master->device_sem, 1);
|
||||
|
||||
master->phase = EC_ORPHANED;
|
||||
master->active = 0;
|
||||
master->injection_seq_fsm = 0;
|
||||
master->injection_seq_rt = 0;
|
||||
|
||||
@@ -169,8 +170,10 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
sema_init(&master->io_sem, 1);
|
||||
master->send_cb = NULL;
|
||||
master->receive_cb = NULL;
|
||||
master->cb_data = NULL;
|
||||
master->app_send_cb = NULL;
|
||||
master->app_receive_cb = NULL;
|
||||
master->app_cb_data = NULL;
|
||||
|
||||
INIT_LIST_HEAD(&master->sii_requests);
|
||||
init_waitqueue_head(&master->sii_queue);
|
||||
@@ -225,12 +228,23 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
EC_ERR("Failed to allocate synchronisation datagram.\n");
|
||||
goto out_clear_ref_sync;
|
||||
}
|
||||
|
||||
// init sync monitor datagram
|
||||
ec_datagram_init(&master->sync_mon_datagram);
|
||||
snprintf(master->sync_mon_datagram.name, EC_DATAGRAM_NAME_SIZE, "syncmon");
|
||||
ret = ec_datagram_brd(&master->sync_mon_datagram, 0x092c, 4);
|
||||
if (ret < 0) {
|
||||
ec_datagram_clear(&master->sync_mon_datagram);
|
||||
EC_ERR("Failed to allocate sync monitoring datagram.\n");
|
||||
goto out_clear_sync;
|
||||
}
|
||||
|
||||
ec_master_find_dc_ref_clock(master);
|
||||
|
||||
// init character device
|
||||
ret = ec_cdev_init(&master->cdev, master, device_number);
|
||||
if (ret)
|
||||
goto out_clear_sync;
|
||||
goto out_clear_sync_mon;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
|
||||
master->class_device = device_create(class, NULL,
|
||||
@@ -259,6 +273,8 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
||||
|
||||
out_clear_cdev:
|
||||
ec_cdev_clear(&master->cdev);
|
||||
out_clear_sync_mon:
|
||||
ec_datagram_clear(&master->sync_mon_datagram);
|
||||
out_clear_sync:
|
||||
ec_datagram_clear(&master->sync_datagram);
|
||||
out_clear_ref_sync:
|
||||
@@ -297,6 +313,7 @@ void ec_master_clear(
|
||||
ec_master_clear_slave_configs(master);
|
||||
ec_master_clear_slaves(master);
|
||||
|
||||
ec_datagram_clear(&master->sync_mon_datagram);
|
||||
ec_datagram_clear(&master->sync_datagram);
|
||||
ec_datagram_clear(&master->ref_sync_datagram);
|
||||
ec_fsm_master_clear(&master->fsm);
|
||||
@@ -349,22 +366,25 @@ void ec_master_clear_slaves(ec_master_t *master)
|
||||
|
||||
master->dc_ref_clock = NULL;
|
||||
|
||||
// external requests are obsolete, so we wake pending waiters and remove them from the list
|
||||
// SII
|
||||
// external requests are obsolete, so we wake pending waiters and remove
|
||||
// them from the list
|
||||
//
|
||||
// SII requests
|
||||
while (1) {
|
||||
ec_sii_write_request_t *request;
|
||||
if (list_empty(&master->sii_requests))
|
||||
break;
|
||||
// get first request
|
||||
request = list_entry(master->sii_requests.next, ec_sii_write_request_t,
|
||||
list);
|
||||
request = list_entry(master->sii_requests.next,
|
||||
ec_sii_write_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
EC_INFO("Discarding SII request, slave %u does not exist anymore.\n",
|
||||
request->slave->ring_position);
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->sii_queue);
|
||||
}
|
||||
// Reg
|
||||
|
||||
// Register requests
|
||||
while (1) {
|
||||
ec_reg_request_t *request;
|
||||
if (list_empty(&master->reg_requests))
|
||||
@@ -378,7 +398,8 @@ void ec_master_clear_slaves(ec_master_t *master)
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->reg_queue);
|
||||
}
|
||||
// SDO
|
||||
|
||||
// SDO requests
|
||||
while (1) {
|
||||
ec_master_sdo_request_t *request;
|
||||
if (list_empty(&master->slave_sdo_requests))
|
||||
@@ -392,7 +413,8 @@ void ec_master_clear_slaves(ec_master_t *master)
|
||||
request->req.state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->sdo_queue);
|
||||
}
|
||||
// FOE
|
||||
|
||||
// FoE requests
|
||||
while (1) {
|
||||
ec_master_foe_request_t *request;
|
||||
if (list_empty(&master->foe_requests))
|
||||
@@ -441,9 +463,10 @@ void ec_master_clear_domains(ec_master_t *master)
|
||||
/** Internal sending callback.
|
||||
*/
|
||||
void ec_master_internal_send_cb(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
void *cb_data /**< Callback data. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = (ec_master_t *) cb_data;
|
||||
down(&master->io_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
up(&master->io_sem);
|
||||
@@ -454,9 +477,10 @@ void ec_master_internal_send_cb(
|
||||
/** Internal receiving callback.
|
||||
*/
|
||||
void ec_master_internal_receive_cb(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
void *cb_data /**< Callback data. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = (ec_master_t *) cb_data;
|
||||
down(&master->io_sem);
|
||||
ecrt_master_receive(master);
|
||||
up(&master->io_sem);
|
||||
@@ -532,6 +556,7 @@ int ec_master_enter_idle_phase(
|
||||
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
master->cb_data = master;
|
||||
|
||||
master->phase = EC_IDLE;
|
||||
ret = ec_master_thread_start(master, ec_master_idle_thread,
|
||||
@@ -633,6 +658,7 @@ int ec_master_enter_operation_phase(ec_master_t *master /**< EtherCAT master */)
|
||||
master->phase = EC_OPERATION;
|
||||
master->app_send_cb = NULL;
|
||||
master->app_receive_cb = NULL;
|
||||
master->app_cb_data = NULL;
|
||||
return ret;
|
||||
|
||||
out_allow:
|
||||
@@ -645,66 +671,17 @@ out_allow:
|
||||
|
||||
/** Transition function from OPERATION to IDLE phase.
|
||||
*/
|
||||
void ec_master_leave_operation_phase(ec_master_t *master
|
||||
/**< EtherCAT master */)
|
||||
void ec_master_leave_operation_phase(
|
||||
ec_master_t *master /**< EtherCAT master */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
#ifdef EC_EOE
|
||||
ec_eoe_t *eoe;
|
||||
#endif
|
||||
if (master->active)
|
||||
ecrt_master_deactivate(master);
|
||||
|
||||
if (master->debug_level)
|
||||
EC_DBG("OPERATION -> IDLE.\n");
|
||||
|
||||
master->phase = EC_IDLE;
|
||||
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_stop(master);
|
||||
#endif
|
||||
ec_master_thread_stop(master);
|
||||
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
|
||||
down(&master->master_sem);
|
||||
ec_master_clear_domains(master);
|
||||
ec_master_clear_slave_configs(master);
|
||||
up(&master->master_sem);
|
||||
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
|
||||
// set states for all slaves
|
||||
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
|
||||
|
||||
// mark for reconfiguration, because the master could have no
|
||||
// possibility for a reconfiguration between two sequential operation
|
||||
// phases.
|
||||
slave->force_config = 1;
|
||||
}
|
||||
|
||||
#ifdef EC_EOE
|
||||
// ... but leave EoE slaves in OP
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list) {
|
||||
if (ec_eoe_is_open(eoe))
|
||||
ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
|
||||
}
|
||||
#endif
|
||||
|
||||
master->app_time = 0ULL;
|
||||
master->app_start_time = 0ULL;
|
||||
master->has_start_time = 0;
|
||||
|
||||
if (ec_master_thread_start(master, ec_master_idle_thread,
|
||||
"EtherCAT-IDLE"))
|
||||
EC_WARN("Failed to restart master thread!\n");
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_start(master);
|
||||
#endif
|
||||
|
||||
master->allow_scan = 1;
|
||||
master->allow_config = 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1189,7 +1166,7 @@ static int ec_master_eoe_thread(void *priv_data)
|
||||
goto schedule;
|
||||
|
||||
// receive datagrams
|
||||
master->receive_cb(master);
|
||||
master->receive_cb(master->cb_data);
|
||||
|
||||
// actual EoE processing
|
||||
sth_to_send = 0;
|
||||
@@ -1209,7 +1186,7 @@ static int ec_master_eoe_thread(void *priv_data)
|
||||
}
|
||||
// (try to) send datagrams
|
||||
down(&master->ext_queue_sem);
|
||||
master->send_cb(master);
|
||||
master->send_cb(master->cb_data);
|
||||
up(&master->ext_queue_sem);
|
||||
}
|
||||
|
||||
@@ -1438,6 +1415,8 @@ const ec_domain_t *ec_master_find_domain_const(
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
|
||||
/** Get the number of EoE handlers.
|
||||
*
|
||||
* \return Number of EoE handlers.
|
||||
@@ -1480,6 +1459,8 @@ const ec_eoe_t *ec_master_get_eoe_handler_const(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Set the debug level.
|
||||
@@ -1683,6 +1664,11 @@ int ecrt_master_activate(ec_master_t *master)
|
||||
if (master->debug_level)
|
||||
EC_DBG("ecrt_master_activate(master = 0x%x)\n", (u32) master);
|
||||
|
||||
if (master->active) {
|
||||
EC_WARN("%s: Master already active!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
down(&master->master_sem);
|
||||
|
||||
// finish all domains
|
||||
@@ -1718,6 +1704,7 @@ int ecrt_master_activate(ec_master_t *master)
|
||||
|
||||
master->send_cb = master->app_send_cb;
|
||||
master->receive_cb = master->app_receive_cb;
|
||||
master->cb_data = master->app_cb_data;
|
||||
|
||||
ret = ec_master_thread_start(master, ec_master_operation_thread,
|
||||
"EtherCAT-OP");
|
||||
@@ -1731,11 +1718,80 @@ int ecrt_master_activate(ec_master_t *master)
|
||||
|
||||
master->allow_config = 1; // request the current configuration
|
||||
master->allow_scan = 1; // allow re-scanning on topology change
|
||||
master->active = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_deactivate(ec_master_t *master)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
#ifdef EC_EOE
|
||||
ec_eoe_t *eoe;
|
||||
#endif
|
||||
|
||||
if (master->debug_level)
|
||||
EC_DBG("ecrt_master_deactivate(master = 0x%x)\n", (u32) master);
|
||||
|
||||
if (!master->active) {
|
||||
EC_WARN("%s: Master not active.\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_stop(master);
|
||||
#endif
|
||||
ec_master_thread_stop(master);
|
||||
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
master->cb_data = master;
|
||||
|
||||
down(&master->master_sem);
|
||||
ec_master_clear_domains(master);
|
||||
ec_master_clear_slave_configs(master);
|
||||
up(&master->master_sem);
|
||||
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
|
||||
// set states for all slaves
|
||||
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
|
||||
|
||||
// mark for reconfiguration, because the master could have no
|
||||
// possibility for a reconfiguration between two sequential operation
|
||||
// phases.
|
||||
slave->force_config = 1;
|
||||
}
|
||||
|
||||
#ifdef EC_EOE
|
||||
// ... but leave EoE slaves in OP
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list) {
|
||||
if (ec_eoe_is_open(eoe))
|
||||
ec_slave_request_state(eoe->slave, EC_SLAVE_STATE_OP);
|
||||
}
|
||||
#endif
|
||||
|
||||
master->app_time = 0ULL;
|
||||
master->app_start_time = 0ULL;
|
||||
master->has_start_time = 0;
|
||||
|
||||
if (ec_master_thread_start(master, ec_master_idle_thread,
|
||||
"EtherCAT-IDLE"))
|
||||
EC_WARN("Failed to restart master thread!\n");
|
||||
#ifdef EC_EOE
|
||||
ec_master_eoe_start(master);
|
||||
#endif
|
||||
|
||||
master->allow_scan = 1;
|
||||
master->allow_config = 1;
|
||||
master->active = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_send(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_t *datagram, *n;
|
||||
@@ -1895,15 +1951,16 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_callbacks(ec_master_t *master,
|
||||
void (*send_cb)(ec_master_t *), void (*receive_cb)(ec_master_t *))
|
||||
void (*send_cb)(void *), void (*receive_cb)(void *), void *cb_data)
|
||||
{
|
||||
if (master->debug_level)
|
||||
EC_DBG("ecrt_master_callbacks(master = 0x%x, send_cb = 0x%x, "
|
||||
" receive_cb = 0x%x)\n", (u32) master, (u32) send_cb,
|
||||
(u32) receive_cb);
|
||||
" receive_cb = 0x%x, cb_data = 0x%x)\n", (u32) master,
|
||||
(u32) send_cb, (u32) receive_cb, (u32) cb_data);
|
||||
|
||||
master->app_send_cb = send_cb;
|
||||
master->app_receive_cb = receive_cb;
|
||||
master->app_cb_data = cb_data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1945,10 +2002,30 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_sync_monitor_queue(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_zero(&master->sync_mon_datagram);
|
||||
ec_master_queue_datagram(master, &master->sync_mon_datagram);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
|
||||
{
|
||||
if (master->sync_mon_datagram.state == EC_DATAGRAM_RECEIVED) {
|
||||
return EC_READ_U32(master->sync_mon_datagram.data) & 0x7fffffff;
|
||||
} else {
|
||||
return 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_master_create_domain);
|
||||
EXPORT_SYMBOL(ecrt_master_activate);
|
||||
EXPORT_SYMBOL(ecrt_master_deactivate);
|
||||
EXPORT_SYMBOL(ecrt_master_send);
|
||||
EXPORT_SYMBOL(ecrt_master_send_ext);
|
||||
EXPORT_SYMBOL(ecrt_master_receive);
|
||||
@@ -1958,6 +2035,8 @@ EXPORT_SYMBOL(ecrt_master_state);
|
||||
EXPORT_SYMBOL(ecrt_master_application_time);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_reference_clock);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_slave_clocks);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_monitor_queue);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_monitor_process);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ struct ec_master {
|
||||
ec_fsm_master_t fsm; /**< Master state machine. */
|
||||
ec_datagram_t fsm_datagram; /**< Datagram used for state machines. */
|
||||
ec_master_phase_t phase; /**< Master phase. */
|
||||
unsigned int active; /**< Master has been activated. */
|
||||
unsigned int injection_seq_fsm; /**< Datagram injection sequence number
|
||||
for the FSM side. */
|
||||
unsigned int injection_seq_rt; /**< Datagram injection sequence number
|
||||
@@ -125,6 +126,8 @@ struct ec_master {
|
||||
reference clock to the master clock. */
|
||||
ec_datagram_t sync_datagram; /**< Datagram used for DC drift
|
||||
compensation. */
|
||||
ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation
|
||||
monitoring. */
|
||||
ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */
|
||||
|
||||
unsigned int scan_busy; /**< Current scan state. */
|
||||
@@ -166,12 +169,14 @@ struct ec_master {
|
||||
|
||||
struct semaphore io_sem; /**< Semaphore used in \a IDLE phase. */
|
||||
|
||||
void (*send_cb)(ec_master_t *); /**< Current send datagrams callback. */
|
||||
void (*receive_cb)(ec_master_t *); /**< Current receive datagrams callback. */
|
||||
void (*app_send_cb)(ec_master_t *); /**< Application's send datagrams
|
||||
void (*send_cb)(void *); /**< Current send datagrams callback. */
|
||||
void (*receive_cb)(void *); /**< Current receive datagrams callback. */
|
||||
void *cb_data; /**< Current callback data. */
|
||||
void (*app_send_cb)(void *); /**< Application's send datagrams
|
||||
callback. */
|
||||
void (*app_receive_cb)(ec_master_t *); /**< Application's receive datagrams
|
||||
void (*app_receive_cb)(void *); /**< Application's receive datagrams
|
||||
callback. */
|
||||
void *app_cb_data; /**< Application callback data. */
|
||||
|
||||
struct list_head sii_requests; /**< SII write requests. */
|
||||
wait_queue_head_t sii_queue; /**< Wait queue for SII
|
||||
@@ -236,8 +241,10 @@ unsigned int ec_master_domain_count(const ec_master_t *);
|
||||
ec_domain_t *ec_master_find_domain(ec_master_t *, unsigned int);
|
||||
const ec_domain_t *ec_master_find_domain_const(const ec_master_t *,
|
||||
unsigned int);
|
||||
#ifdef EC_EOE
|
||||
uint16_t ec_master_eoe_handler_count(const ec_master_t *);
|
||||
const ec_eoe_t *ec_master_get_eoe_handler_const(const ec_master_t *, uint16_t);
|
||||
#endif
|
||||
|
||||
int ec_master_debug_level(ec_master_t *, unsigned int);
|
||||
|
||||
@@ -247,8 +254,8 @@ ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *, uint16_t,
|
||||
|
||||
void ec_master_calc_dc(ec_master_t *);
|
||||
|
||||
void ec_master_internal_send_cb(ec_master_t *);
|
||||
void ec_master_internal_receive_cb(ec_master_t *);
|
||||
void ec_master_internal_send_cb(void *);
|
||||
void ec_master_internal_receive_cb(void *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ void ec_sdo_request_init(
|
||||
ec_sdo_request_t *req /**< SDO request. */
|
||||
)
|
||||
{
|
||||
req->complete_access = 0;
|
||||
req->data = NULL;
|
||||
req->mem_size = 0;
|
||||
req->data_size = 0;
|
||||
@@ -88,6 +89,7 @@ int ec_sdo_request_copy(
|
||||
const ec_sdo_request_t *other /**< Other SDO request to copy from. */
|
||||
)
|
||||
{
|
||||
req->complete_access = other->complete_access;
|
||||
req->index = other->index;
|
||||
req->subindex = other->subindex;
|
||||
return ec_sdo_request_copy_data(req, other->data, other->data_size);
|
||||
|
||||
@@ -52,6 +52,7 @@ struct ec_sdo_request {
|
||||
uint8_t *data; /**< Pointer to SDO data. */
|
||||
size_t mem_size; /**< Size of SDO data memory. */
|
||||
size_t data_size; /**< Size of SDO data. */
|
||||
uint8_t complete_access; /**< SDO shall be transferred completely. */
|
||||
uint32_t issue_timeout; /**< Maximum time in ms, the processing of the
|
||||
request may take. */
|
||||
uint32_t response_timeout; /**< Maximum time in ms, the transfer is
|
||||
|
||||
@@ -794,6 +794,48 @@ int ecrt_slave_config_sdo32(ec_slave_config_t *sc, uint16_t index,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index,
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
ec_slave_t *slave = sc->slave;
|
||||
ec_sdo_request_t *req;
|
||||
int ret;
|
||||
|
||||
if (sc->master->debug_level)
|
||||
EC_DBG("ecrt_slave_config_complete_sdo(sc = 0x%x, index = 0x%04X, "
|
||||
"data = 0x%x, size = %u)\n", (u32) sc,
|
||||
index, (u32) data, size);
|
||||
|
||||
if (slave && !(slave->sii.mailbox_protocols & EC_MBOX_COE)) {
|
||||
EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
|
||||
return -EPROTONOSUPPORT; // protocol not supported
|
||||
}
|
||||
|
||||
if (!(req = (ec_sdo_request_t *)
|
||||
kmalloc(sizeof(ec_sdo_request_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for SDO configuration!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ec_sdo_request_init(req);
|
||||
ec_sdo_request_address(req, index, 0);
|
||||
req->complete_access = 1;
|
||||
|
||||
ret = ec_sdo_request_copy_data(req, data, size);
|
||||
if (ret < 0) {
|
||||
ec_sdo_request_clear(req);
|
||||
kfree(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
list_add_tail(&req->list, &sc->sdo_configs);
|
||||
up(&sc->master->master_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_slave_config_create_sdo_request(), but with ERR_PTR() return
|
||||
* value.
|
||||
*/
|
||||
@@ -923,6 +965,7 @@ EXPORT_SYMBOL(ecrt_slave_config_sdo);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sdo8);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sdo16);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sdo32);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_complete_sdo);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_state);
|
||||
|
||||
198
tool/CommandCStruct.cpp
Normal file
198
tool/CommandCStruct.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master 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.
|
||||
*
|
||||
* The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* The license mentioned above concerns the source code only. Using the
|
||||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
using namespace std;
|
||||
|
||||
#include "CommandCStruct.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
CommandCStruct::CommandCStruct():
|
||||
Command("cstruct", "Generate slave PDO information in C language.")
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
string CommandCStruct::helpString() const
|
||||
{
|
||||
stringstream str;
|
||||
|
||||
str << getName() << " [OPTIONS]" << endl
|
||||
<< endl
|
||||
<< getBriefDescription() << endl
|
||||
<< endl
|
||||
<< "The output C code can be used directly with the" << endl
|
||||
<< "ecrt_slave_config_pdos() function of the application" << endl
|
||||
<< "interface." << endl
|
||||
<< endl
|
||||
<< "Command-specific options:" << endl
|
||||
<< " --alias -a <alias>" << endl
|
||||
<< " --position -p <pos> Slave selection. See the help of" << endl
|
||||
<< " the 'slaves' command." << endl
|
||||
<< endl
|
||||
<< numericInfo();
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void CommandCStruct::execute(MasterDevice &m, const StringVector &args)
|
||||
{
|
||||
SlaveList slaves;
|
||||
SlaveList::const_iterator si;
|
||||
|
||||
if (args.size()) {
|
||||
stringstream err;
|
||||
err << "'" << getName() << "' takes no arguments!";
|
||||
throwInvalidUsageException(err);
|
||||
}
|
||||
|
||||
m.open(MasterDevice::Read);
|
||||
slaves = selectedSlaves(m);
|
||||
|
||||
for (si = slaves.begin(); si != slaves.end(); si++) {
|
||||
generateSlaveCStruct(m, *si);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void CommandCStruct::generateSlaveCStruct(
|
||||
MasterDevice &m,
|
||||
const ec_ioctl_slave_t &slave
|
||||
)
|
||||
{
|
||||
ec_ioctl_slave_sync_t sync;
|
||||
ec_ioctl_slave_sync_pdo_t pdo;
|
||||
ec_ioctl_slave_sync_pdo_entry_t entry;
|
||||
unsigned int i, j, k, pdo_pos = 0, entry_pos = 0;
|
||||
stringstream id, syncs, pdos, entries;
|
||||
|
||||
if (!slave.sync_count)
|
||||
return;
|
||||
|
||||
id << "slave_" << dec << slave.position << "_";
|
||||
|
||||
for (i = 0; i < slave.sync_count; i++) {
|
||||
m.getSync(&sync, slave.position, i);
|
||||
|
||||
syncs << " {" << dec << sync.sync_index
|
||||
<< ", " << (EC_READ_BIT(&sync.control_register, 2) ?
|
||||
"EC_DIR_OUTPUT" : "EC_DIR_INPUT")
|
||||
<< ", " << dec << (unsigned int) sync.pdo_count
|
||||
<< ", ";
|
||||
if (sync.pdo_count) {
|
||||
syncs << id.str() << "pdos + " << dec << pdo_pos;
|
||||
} else {
|
||||
syncs << "NULL";
|
||||
}
|
||||
syncs << ", " << (EC_READ_BIT(&sync.control_register, 6) ?
|
||||
"EC_WD_ENABLE" : "EC_WD_DISABLE")
|
||||
<< "},";
|
||||
syncs << endl;
|
||||
pdo_pos += sync.pdo_count;
|
||||
|
||||
for (j = 0; j < sync.pdo_count; j++) {
|
||||
m.getPdo(&pdo, slave.position, i, j);
|
||||
|
||||
pdos << " {0x" << hex << setfill('0')
|
||||
<< setw(4) << pdo.index
|
||||
<< ", " << dec << (unsigned int) pdo.entry_count
|
||||
<< ", ";
|
||||
if (pdo.entry_count) {
|
||||
pdos << id.str() << "pdo_entries + " << dec << entry_pos;
|
||||
} else {
|
||||
pdos << "NULL";
|
||||
}
|
||||
pdos << "},";
|
||||
if (strlen((const char *) pdo.name)) {
|
||||
pdos << " /* " << pdo.name << " */";
|
||||
}
|
||||
pdos << endl;
|
||||
entry_pos += pdo.entry_count;
|
||||
|
||||
for (k = 0; k < pdo.entry_count; k++) {
|
||||
m.getPdoEntry(&entry, slave.position, i, j, k);
|
||||
|
||||
entries << " {0x" << hex << setfill('0')
|
||||
<< setw(4) << entry.index
|
||||
<< ", 0x" << setw(2) << (unsigned int) entry.subindex
|
||||
<< ", " << dec << (unsigned int) entry.bit_length
|
||||
<< "},";
|
||||
if (strlen((const char *) entry.name)) {
|
||||
entries << " /* " << entry.name << " */";
|
||||
}
|
||||
entries << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cout
|
||||
<< "/* Slave " << slave.position;
|
||||
if (strlen(slave.order)) {
|
||||
cout << ", \"" << slave.order << "\"";
|
||||
}
|
||||
|
||||
cout << endl
|
||||
<< " * Vendor ID: 0x" << hex << setfill('0')
|
||||
<< setw(8) << slave.vendor_id << endl
|
||||
<< " * Product code: 0x" << hex << setfill('0')
|
||||
<< setw(8) << slave.product_code << endl
|
||||
<< " * Revision number: 0x" << hex << setfill('0')
|
||||
<< setw(8) << slave.revision_number << endl
|
||||
<< " */" << endl
|
||||
<< endl;
|
||||
|
||||
if (entry_pos) {
|
||||
cout << "ec_pdo_entry_info_t " << id.str()
|
||||
<< "pdo_entries[] = {" << endl
|
||||
<< entries.str()
|
||||
<< "};" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
if (pdo_pos) {
|
||||
cout << "ec_pdo_info_t " << id.str() << "pdos[] = {" << endl
|
||||
<< pdos.str()
|
||||
<< "};" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
cout << "ec_sync_info_t " << id.str() << "syncs[] = {" << endl
|
||||
<< syncs.str()
|
||||
<< "};" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
52
tool/CommandCStruct.h
Normal file
52
tool/CommandCStruct.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master 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.
|
||||
*
|
||||
* The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* The license mentioned above concerns the source code only. Using the
|
||||
* EtherCAT technology and brand is only permitted in compliance with the
|
||||
* industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __COMMANDCSTRUCT_H__
|
||||
#define __COMMANDCSTRUCT_H__
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
class CommandCStruct:
|
||||
public Command
|
||||
{
|
||||
public:
|
||||
CommandCStruct();
|
||||
|
||||
string helpString() const;
|
||||
void execute(MasterDevice &, const StringVector &);
|
||||
|
||||
protected:
|
||||
void generateSlaveCStruct(MasterDevice &, const ec_ioctl_slave_t &);
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#endif
|
||||
@@ -131,7 +131,7 @@ void CommandConfig::showDetailedConfigs(
|
||||
)
|
||||
{
|
||||
ConfigList::const_iterator configIter;
|
||||
unsigned int j, k, l;
|
||||
unsigned int i, j, k, l;
|
||||
ec_ioctl_slave_t slave;
|
||||
ec_ioctl_config_pdo_t pdo;
|
||||
ec_ioctl_config_pdo_entry_t entry;
|
||||
@@ -159,11 +159,34 @@ void CommandConfig::showDetailedConfigs(
|
||||
cout << "none" << endl;
|
||||
}
|
||||
|
||||
cout << "Watchdog divider: ";
|
||||
if (configIter->watchdog_divider) {
|
||||
cout << dec << configIter->watchdog_divider;
|
||||
} else {
|
||||
cout << "(Default)";
|
||||
}
|
||||
cout << endl
|
||||
<< "Watchdog intervals: ";
|
||||
if (configIter->watchdog_intervals) {
|
||||
cout << dec << configIter->watchdog_intervals;
|
||||
} else {
|
||||
cout << "(Default)";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
|
||||
if (configIter->syncs[j].pdo_count) {
|
||||
cout << "SM" << dec << j << " ("
|
||||
cout << "SM" << dec << j << ", Dir: "
|
||||
<< (configIter->syncs[j].dir == EC_DIR_INPUT
|
||||
? "Input" : "Output") << ")" << endl;
|
||||
? "Input" : "Output") << ", Watchdog: ";
|
||||
switch (configIter->syncs[j].watchdog_mode) {
|
||||
case EC_WD_DEFAULT: cout << "Default"; break;
|
||||
case EC_WD_ENABLE: cout << "Enable"; break;
|
||||
case EC_WD_DISABLE: cout << "Disable"; break;
|
||||
default: cout << "???"; break;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
for (k = 0; k < configIter->syncs[j].pdo_count; k++) {
|
||||
m.getConfigPdo(&pdo, configIter->config_index, j, k);
|
||||
|
||||
@@ -194,26 +217,23 @@ void CommandConfig::showDetailedConfigs(
|
||||
<< hex << setfill('0')
|
||||
<< setw(4) << sdo.index << ":"
|
||||
<< setw(2) << (unsigned int) sdo.subindex
|
||||
<< ", " << dec << sdo.size << " byte: " << hex;
|
||||
<< ", " << dec << sdo.size << " byte" << endl;
|
||||
|
||||
switch (sdo.size) {
|
||||
case 1:
|
||||
cout << "0x" << setw(2)
|
||||
<< (unsigned int) *(uint8_t *) &sdo.data;
|
||||
break;
|
||||
case 2:
|
||||
cout << "0x" << setw(4)
|
||||
<< le16_to_cpup(&sdo.data);
|
||||
break;
|
||||
case 4:
|
||||
cout << "0x" << setw(8)
|
||||
<< le32_to_cpup(&sdo.data);
|
||||
break;
|
||||
default:
|
||||
cout << "???";
|
||||
cout << " " << hex;
|
||||
for (i = 0; i < min((uint32_t) sdo.size,
|
||||
(uint32_t) EC_MAX_SDO_DATA_SIZE); i++) {
|
||||
cout << setw(2) << (unsigned int) sdo.data[i];
|
||||
if ((i + 1) % 16 == 0 && i < sdo.size - 1) {
|
||||
cout << endl << " ";
|
||||
} else {
|
||||
cout << " ";
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
if (sdo.size > EC_MAX_SDO_DATA_SIZE) {
|
||||
cout << " ..." << endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cout << " None." << endl;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $Id: CommandSlaves.cpp 1767 2009-05-08 13:35:06Z fp $
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $Id: CommandSlaves.h 1667 2009-02-24 12:51:39Z fp $
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
|
||||
@@ -91,6 +91,7 @@ void CommandMaster::execute(MasterDevice &m, const StringVector &args)
|
||||
}
|
||||
|
||||
cout << endl
|
||||
<< " Active: " << (data.active ? "yes" : "no") << endl
|
||||
<< " Slaves: " << data.slave_count << endl
|
||||
<< " Ethernet devices:" << endl;
|
||||
|
||||
|
||||
@@ -27,21 +27,23 @@
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# vim: syntax=make
|
||||
# vim: syntax=automake
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
bin_PROGRAMS = ethercat
|
||||
|
||||
ethercat_SOURCES = \
|
||||
Command.cpp \
|
||||
CommandAlias.cpp \
|
||||
CommandConfig.cpp \
|
||||
CommandCStruct.cpp \
|
||||
CommandData.cpp \
|
||||
CommandDebug.cpp \
|
||||
CommandDomains.cpp \
|
||||
CommandDownload.cpp \
|
||||
CommandEoe.cpp \
|
||||
CommandFoeRead.cpp \
|
||||
CommandFoeWrite.cpp \
|
||||
CommandGraph.cpp \
|
||||
@@ -64,15 +66,21 @@ ethercat_SOURCES = \
|
||||
main.cpp \
|
||||
sii_crc.cpp
|
||||
|
||||
if ENABLE_EOE
|
||||
ethercat_SOURCES += CommandEoe.cpp
|
||||
else
|
||||
EXTRA_DIST += CommandEoe.cpp
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
Command.h \
|
||||
CommandAlias.h \
|
||||
CommandConfig.h \
|
||||
CommandCStruct.h \
|
||||
CommandData.h \
|
||||
CommandDebug.h \
|
||||
CommandDomains.h \
|
||||
CommandDownload.h \
|
||||
CommandEoe.h \
|
||||
CommandFoeRead.h \
|
||||
CommandFoeWrite.h \
|
||||
CommandGraph.h \
|
||||
@@ -94,12 +102,18 @@ noinst_HEADERS = \
|
||||
SdoCommand.h \
|
||||
sii_crc.h
|
||||
|
||||
REV = `if test -s $(top_srcdir)/svnrevision; then \
|
||||
cat $(top_srcdir)/svnrevision; \
|
||||
if ENABLE_EOE
|
||||
noinst_HEADERS += CommandEoe.h
|
||||
else
|
||||
EXTRA_DIST += CommandEoe.h
|
||||
endif
|
||||
|
||||
REV = `if test -s $(top_srcdir)/revision; then \
|
||||
cat $(top_srcdir)/revision; \
|
||||
else \
|
||||
svnversion $(srcdir)/.. 2>/dev/null || echo "unknown"; \
|
||||
hg id -i $(top_srcdir) 2>/dev/null || echo "unknown"; \
|
||||
fi`
|
||||
|
||||
ethercat_CXXFLAGS = -I$(top_srcdir)/master -Wall -DSVNREV=$(REV)
|
||||
ethercat_CXXFLAGS = -I$(top_srcdir)/master -Wall -DREV=$(REV)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
@@ -485,6 +485,8 @@ void MasterDevice::requestState(
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
|
||||
void MasterDevice::getEoeHandler(
|
||||
ec_ioctl_eoe_handler_t *eoe,
|
||||
uint16_t eoeHandlerIndex
|
||||
@@ -499,4 +501,6 @@ void MasterDevice::getEoeHandler(
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -117,7 +117,9 @@ class MasterDevice
|
||||
void requestState(uint16_t, uint8_t);
|
||||
void readFoe(ec_ioctl_slave_foe_t *);
|
||||
void writeFoe(ec_ioctl_slave_foe_t *);
|
||||
#ifdef EC_EOE
|
||||
void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t);
|
||||
#endif
|
||||
|
||||
private:
|
||||
unsigned int index;
|
||||
|
||||
@@ -37,11 +37,14 @@ using namespace std;
|
||||
|
||||
#include "CommandAlias.h"
|
||||
#include "CommandConfig.h"
|
||||
#include "CommandCStruct.h"
|
||||
#include "CommandData.h"
|
||||
#include "CommandDebug.h"
|
||||
#include "CommandDomains.h"
|
||||
#include "CommandDownload.h"
|
||||
#include "CommandEoe.h"
|
||||
#ifdef EC_EOE
|
||||
# include "CommandEoe.h"
|
||||
#endif
|
||||
#include "CommandFoeRead.h"
|
||||
#include "CommandFoeWrite.h"
|
||||
#include "CommandGraph.h"
|
||||
@@ -293,11 +296,14 @@ int main(int argc, char **argv)
|
||||
|
||||
commandList.push_back(new CommandAlias());
|
||||
commandList.push_back(new CommandConfig());
|
||||
commandList.push_back(new CommandCStruct());
|
||||
commandList.push_back(new CommandData());
|
||||
commandList.push_back(new CommandDebug());
|
||||
commandList.push_back(new CommandDomains());
|
||||
commandList.push_back(new CommandDownload());
|
||||
#ifdef EC_EOE
|
||||
commandList.push_back(new CommandEoe());
|
||||
#endif
|
||||
commandList.push_back(new CommandFoeRead());
|
||||
commandList.push_back(new CommandFoeWrite());
|
||||
commandList.push_back(new CommandGraph());
|
||||
|
||||
Reference in New Issue
Block a user