Removed MSR example; adapted RTAI example; README files for examples.
authorFlorian Pose <fp@igh-essen.com>
Wed, 02 Jul 2008 12:16:48 +0000
changeset 1080 088a61306930
parent 1079 ef1266652c4d
child 1081 66c60b99c2e8
Removed MSR example; adapted RTAI example; README files for examples.
TODO
configure.ac
examples/Makefile.am
examples/mini/README
examples/mini/mini.c
examples/msr/Kbuild.in
examples/msr/Makefile.am
examples/msr/init.sh
examples/msr/libm.o_shipped
examples/msr/msr_sample.c
examples/msr/msrserv.pl
examples/rtai/README
examples/rtai/rtai_sample.c
--- a/TODO	Wed Jul 02 11:26:51 2008 +0000
+++ b/TODO	Wed Jul 02 12:16:48 2008 +0000
@@ -8,22 +8,22 @@
 
 Version 1.4.0:
 
+* Race in jiffies frame timeout.
 * Move EC_NUM_SYNCS define to ecrt.h.
-* Read Pdo mapping for unknown Pdos before configuring it.
+* Read Pdo mapping for unknown Pdos before configuring them.
 * Attach Pdo names from SII or Coe dictioary to Pdos read via CoE.
 * Make scanning and configuration run parallel (each).
-* Adapt remaining examples.
-* READMEs for examples.
 * Update documentation.
 * Add -a and -p switches for 'ethercat config' command.
-* Race in jiffies frame timeout.
+* Add a -n (numeric) switch to ethercat command.
+* Make verbose and quite flags a master property.
 * File access over EtherCAT (FoE).
 * Allow master requesting when in ORPHANED phase
 * Get original driver for r8169.
+* Distributed clocks.
 
 Future issues:
 
-* Distributed clocks.
 * Move master threads, slave handlers and state machines into a user
   space daemon.
 * Implement user space realtime interface via cdev.
@@ -35,7 +35,6 @@
 * Optimize alignment of process data.
 * Redundancy with 2 network adapters.
 * Interface/buffers for asynchronous domain IO.
-* Add a -n (numeric) switch to ethercat command.
 
 Smaller issues:
 
--- a/configure.ac	Wed Jul 02 11:26:51 2008 +0000
+++ b/configure.ac	Wed Jul 02 12:16:48 2008 +0000
@@ -384,36 +384,6 @@
 AC_SUBST(RTAI_DIR,[$rtaidir])
 
 #------------------------------------------------------------------------------
-# MSR path (optional)
-#------------------------------------------------------------------------------
-
-AC_ARG_WITH([msr-dir],
-    AC_HELP_STRING(
-        [--with-msr-dir=<DIR>],
-        [MSR path (only for MSR example)]
-    ),
-    [
-        msrdir=[$withval]
-    ],
-    [
-        msrdir=""
-    ]
-)
-
-AC_MSG_CHECKING([for MSR path])
-
-if test -z "${msrdir}"; then
-    AC_MSG_RESULT([not specified.])
-else
-    if test \! -r ${msrdir}/include/msr.h; then
-        AC_MSG_ERROR([no MSR installation found in ${msrdir}!])
-    fi
-    AC_MSG_RESULT([$msrdir])
-fi
-
-AC_SUBST(MSR_DIR,[$msrdir])
-
-#------------------------------------------------------------------------------
 # Debug interface
 #------------------------------------------------------------------------------
 
@@ -526,8 +496,6 @@
         examples/Makefile
         examples/mini/Kbuild
         examples/mini/Makefile
-        examples/msr/Kbuild
-        examples/msr/Makefile
         examples/rtai/Kbuild
         examples/rtai/Makefile
         include/Makefile
--- a/examples/Makefile.am	Wed Jul 02 11:26:51 2008 +0000
+++ b/examples/Makefile.am	Wed Jul 02 12:16:48 2008 +0000
@@ -31,6 +31,6 @@
 #
 #------------------------------------------------------------------------------
 
-DIST_SUBDIRS = mini rtai msr
+DIST_SUBDIRS = mini rtai
 
 #------------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mini/README	Wed Jul 02 12:16:48 2008 +0000
@@ -0,0 +1,28 @@
+-------------------------------------------------------------------------------
+
+$Id$
+
+-------------------------------------------------------------------------------
+
+This is a minimal example module for the use of the EtherCAT master realtime
+interface. It uses a kernel timer to generate a cyclic task.
+
+Most probably you'll have different EtherCAT slaves present. Try adjusting the
+section "process data" in mini.c to your bus configuration.
+
+There are some features that can be disabled by commenting out the respective
+defines at the head of mini.c.
+
+---
+
+To build the example module, call:
+
+make modules
+
+To run it, call:
+
+insmod ec_mini.ko
+
+...and watch the system logs for the outputs.
+
+-------------------------------------------------------------------------------
--- a/examples/mini/mini.c	Wed Jul 02 11:26:51 2008 +0000
+++ b/examples/mini/mini.c	Wed Jul 02 12:16:48 2008 +0000
@@ -43,16 +43,13 @@
 // Module parameters
 #define FREQUENCY 100
 
-// Optional features
+// Optional features (comment to disable)
 #define CONFIGURE_PDOS
 #define EXTERNAL_MEMORY
 #define SDO_ACCESS
 
 #define PFX "ec_mini: "
 
-#define AnaInPos  0, 1
-#define DigOutPos 0, 3
-
 /*****************************************************************************/
 
 // EtherCAT
@@ -66,28 +63,32 @@
 static ec_slave_config_t *sc_ana_in = NULL;
 static ec_slave_config_state_t sc_ana_in_state = {};
 
+// Timer
 static struct timer_list timer;
-static unsigned int counter = 0;
 
 /*****************************************************************************/
 
 // process data
 static uint8_t *domain1_pd; // process data memory
 
+#define AnaInSlavePos  0, 1
+#define DigOutSlavePos 0, 3
+
+#define Beckhoff_EL2004 0x00000002, 0x07D43052
+#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
+
 static unsigned int off_ana_in; // offsets for Pdo entries
 static unsigned int off_dig_out;
 
+const static ec_pdo_entry_reg_t domain1_regs[] = {
+    {AnaInSlavePos,  Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
+    {DigOutSlavePos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
+    {}
+};
+
+static unsigned int counter = 0;
 static unsigned int blink = 0;
 
-#define Beckhoff_EL2004 0x00000002, 0x07D43052
-#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
-
-const static ec_pdo_entry_reg_t domain1_regs[] = {
-    {AnaInPos,  Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
-    {DigOutPos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
-    {}
-};
-
 /*****************************************************************************/
 
 #ifdef CONFIGURE_PDOS
@@ -312,7 +313,7 @@
     }
 
     if (!(sc_ana_in = ecrt_master_slave_config(
-                    master, AnaInPos, Beckhoff_EL3162))) {
+                    master, AnaInSlavePos, Beckhoff_EL3162))) {
         printk(KERN_ERR PFX "Failed to get slave configuration.\n");
         goto out_release_master;
     }
@@ -324,7 +325,8 @@
         goto out_release_master;
     }
 
-    if (!(sc = ecrt_master_slave_config(master, DigOutPos, Beckhoff_EL2004))) {
+    if (!(sc = ecrt_master_slave_config(
+                    master, DigOutSlavePos, Beckhoff_EL2004))) {
         printk(KERN_ERR PFX "Failed to get slave configuration.\n");
         goto out_release_master;
     }
--- a/examples/msr/Kbuild.in	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-#------------------------------------------------------------------------------
-#
-#  $Id$
-#
-#  Copyright (C) 2006  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
-#  as published by the Free Software Foundation; either version 2 of the
-#  License, or (at your option) any later version.
-#
-#  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 right to use EtherCAT Technology is granted and comes free of
-#  charge under condition of compatibility of product made by
-#  Licensee. People intending to distribute/sell products based on the
-#  code, have to sign an agreement to guarantee that products using
-#  software based on IgH EtherCAT master stay compatible with the actual
-#  EtherCAT specification (which are released themselves as an open
-#  standard) as the (only) precondition to have the right to use EtherCAT
-#  Technology, IP and trade marks.
-#
-#  vi: syntax=make
-#
-#------------------------------------------------------------------------------
-
-MODULE := ec_msr_sample
-
-obj-m := $(MODULE).o
-
-$(MODULE)-objs := \
-	msr_sample.o \
-	rt_lib/msr-core/msr_lists.o \
-	rt_lib/msr-core/msr_main.o \
-	rt_lib/msr-core/msr_charbuf.o \
-	rt_lib/msr-core/msr_reg.o \
-	rt_lib/msr-core/msr_interpreter.o \
-	rt_lib/msr-core/msr_messages.o \
-	rt_lib/msr-core/msr_proc.o \
-	rt_lib/msr-core/msr_error_reg.o \
-	rt_lib/msr-utils/msr_utils.o \
-	rt_lib/msr-utils/msr_time.o \
-	rt_lib/msr-math/msr_base64.o \
-	rt_lib/msr-math/msr_hex_bin.o \
-	libm.o
-
-EXTRA_CFLAGS := \
-	-I@MSR_DIR@/include \
-	-I@RTAI_DIR@/include \
-	-D_SIMULATION -mhard-float
-
-#------------------------------------------------------------------------------
--- a/examples/msr/Makefile.am	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#------------------------------------------------------------------------------
-#
-#  $Id$
-#
-#  Copyright (C) 2006  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
-#  as published by the Free Software Foundation; either version 2 of the
-#  License, or (at your option) any later version.
-#
-#  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 right to use EtherCAT Technology is granted and comes free of
-#  charge under condition of compatibility of product made by
-#  Licensee. People intending to distribute/sell products based on the
-#  code, have to sign an agreement to guarantee that products using
-#  software based on IgH EtherCAT master stay compatible with the actual
-#  EtherCAT specification (which are released themselves as an open
-#  standard) as the (only) precondition to have the right to use EtherCAT
-#  Technology, IP and trade marks.
-#
-#------------------------------------------------------------------------------
-
-EXTRA_DIST = \
-	Kbuild.in \
-	libm.o_shipped \
-	msr_sample.c \
-	msrserv.pl \
-	init.sh
-
-BUILT_SOURCES = \
-	Kbuild
-
-modules:
-	$(MAKE) -C "$(LINUX_SOURCE_DIR)" M="@abs_srcdir@" modules
-
-modules_install:
-	mkdir -p $(DESTDIR)$(LINUX_MOD_PATH)
-	cp $(srcdir)/ec_msr_sample.ko $(DESTDIR)$(LINUX_MOD_PATH)
-
-clean-local:
-	$(MAKE) -C "$(LINUX_SOURCE_DIR)" M="@abs_srcdir@" clean
-
-#------------------------------------------------------------------------------
--- a/examples/msr/init.sh	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-#!/bin/sh
-
-#------------------------------------------------------------------------------
-#
-#  MSR Init Script
-#
-#  $Id$
-#
-#------------------------------------------------------------------------------
-
-### BEGIN INIT INFO
-# Provides:          msr
-# Required-Start:    $local_fs $syslog $network
-# Should-Start:      $time ntp ethercat
-# Required-Stop:     $local_fs $syslog $network
-# Should-Stop:       $time ntp ethercat
-# Default-Start:     3 5
-# Default-Stop:      0 1 2 6
-# Short-Description: MSR module
-# Description:
-### END INIT INFO
-
-#------------------------------------------------------------------------------
-
-# <Customizing>
-
-NAME="MSR EtherCAT sample"
-BASE=/opt/etherlab
-MSR_SERVER=$BASE/bin/msrserv.pl
-MODULE=ec_msr_sample
-RTAI_PATH=/usr/realtime
-RTAI_MODULES="hal up" # sem math
-DEVICE=msr
-DEVMASK=664
-GROUP=users
-
-# </Customizing>
-
-#------------------------------------------------------------------------------
-
-. /etc/rc.status
-rc_reset
-
-#------------------------------------------------------------------------------
-
-case "$1" in
-    start)
-	echo -n Starting $NAME" "
-
-	# Insert RTAI modules
-	for mod in $RTAI_MODULES; do
-	    if ! lsmod | grep -q "^rtai_$mod"; then
-		if ! insmod $RTAI_PATH/modules/rtai_$mod.ko; then
-		    /bin/false
-		    rc_status -v
-		    rc_exit
-		fi
-	    fi
-	done
-
-	# Insert realtime module
-	if ! modprobe $MODULE; then
-	    /bin/false
-	    rc_status -v
-	    rc_exit
-	fi
-
-	#sleep 2
-
-	# Create MSR device
-	MAJOR=`cat /proc/devices | awk "\\$2==\"$DEVICE\" {print \\$1}"`
-	rm -f /dev/${DEVICE}
-	mknod /dev/${DEVICE} c $MAJOR 0
-	chgrp $GROUP /dev/${DEVICE}
-	chmod $DEVMASK /dev/${DEVICE}
-
-	#sleep 1
-
-	# Start MSR-Server
-	startproc $MSR_SERVER 1>/dev/null 2>/dev/null
-	rc_status -v
-	;;
-
-    stop)
-	echo -n Shutting down $NAME" "
-
-	if ! killproc $MSR_SERVER; then
-	    /bin/false
-	    rc_status -v
-	    rc_exit
-	fi
-
-	if ! /sbin/rmmod $MODULE; then
-	    /bin/false
-	    rc_status -v
-	    rc_exit
-	fi
-
-	# Remove stale nodes
-	rm -f /dev/${DEVICE} /dev/${DEVICE}0
-
-	rc_status -v
-	;;
-
-    restart)
-	$0 stop || exit 1
-	sleep 1
-	$0 start
-
-	rc_status
-	;;
-
-    status)
-	echo -n "Checking for MSR module: "
-	/sbin/lsmod | grep -q "^$MODULE"
-	rc_status -v
-
-	echo -n "Checking for MSR server: "
-	checkproc $MSR_SERVER
-	rc_status -v
-	;;
-
-    *)
-	echo "Usage: $0 {start|stop|status|restart}"
-	exit 1
-	;;
-esac
-
-rc_exit
\ No newline at end of file
--- a/examples/msr/libm.o_shipped	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-/usr/lib/libm.a
\ No newline at end of file
--- a/examples/msr/msr_sample.c	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-/******************************************************************************
- *
- *  $Id$
- *
- *  Copyright (C) 2006  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
- *  as published by the Free Software Foundation; either version 2 of the
- *  License, or (at your option) any later version.
- *
- *  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 right to use EtherCAT Technology is granted and comes free of
- *  charge under condition of compatibility of product made by
- *  Licensee. People intending to distribute/sell products based on the
- *  code, have to sign an agreement to guarantee that products using
- *  software based on IgH EtherCAT master stay compatible with the actual
- *  EtherCAT specification (which are released themselves as an open
- *  standard) as the (only) precondition to have the right to use EtherCAT
- *  Technology, IP and trade marks.
- *
- *****************************************************************************/
-
-// Linux
-#include <linux/module.h>
-
-// RTAI
-#include "rtai_sched.h"
-#include "rtai_sem.h"
-
-// RT_lib
-#include <msr_main.h>
-#include <msr_reg.h>
-#include <msr_time.h>
-
-// EtherCAT
-#include "../../include/ecrt.h"
-#include "../../include/ecdb.h"
-
-#define MSR_ABTASTFREQUENZ 1000
-
-#define HZREDUCTION (MSR_ABTASTFREQUENZ / HZ)
-#define TIMERTICKS (1000000000 / MSR_ABTASTFREQUENZ)
-
-/*****************************************************************************/
-
-// RTAI
-RT_TASK task;
-SEM master_sem;
-cycles_t t_start = 0, t_critical;
-
-// EtherCAT
-ec_master_t *master = NULL;
-ec_domain_t *domain1 = NULL;
-
-// raw process data
-void *r_ana_out;
-
-// channels
-double k_ana_out;
-
-ec_pdo_reg_t domain1_pdos[] = {
-    {"3", Beckhoff_EL4132_Output1, &r_ana_out},
-    {}
-};
-
-/*****************************************************************************/
-
-void msr_controller_run(void)
-{
-    // receive
-    rt_sem_wait(&master_sem);
-    ecrt_master_receive(master);
-    ecrt_domain_process(domain1);
-    rt_sem_signal(&master_sem);
-
-    // Process data
-    EC_WRITE_S16(r_ana_out, k_ana_out / 10.0 * 0x7FFF);
-
-    // Send
-    rt_sem_wait(&master_sem);
-    ecrt_domain_queue(domain1);
-    ecrt_master_run(master);
-    ecrt_master_send(master);
-    rt_sem_signal(&master_sem);
-
-    msr_write_kanal_list();
-}
-
-/*****************************************************************************/
-
-void msr_run(long data)
-{
-    while (1) {
-        t_start = get_cycles();
-        MSR_RTAITHREAD_CODE(msr_controller_run(););
-        rt_task_wait_period();
-    }
-}
-
-/*****************************************************************************/
-
-int msr_reg(void)
-{
-    msr_reg_kanal("/ana_out", "", &k_ana_out, TDBL);
-    return 0;
-}
-
-/*****************************************************************************/
-
-int request_lock(void *data)
-{
-    // too close to the next RT cycle: deny access...
-    if (get_cycles() - t_start > t_critical) return -1;
-
-    // allow access
-    rt_sem_wait(&master_sem);
-    return 0;
-}
-
-/*****************************************************************************/
-
-void release_lock(void *data)
-{
-    rt_sem_signal(&master_sem);
-}
-
-/*****************************************************************************/
-
-int __init init_mod(void)
-{
-    RTIME ticks;
-
-    printk(KERN_INFO "=== Starting EtherCAT RTAI MSR sample module... ===\n");
-
-    rt_sem_init(&master_sem, 1);
-    t_critical = cpu_khz * 800 / MSR_ABTASTFREQUENZ; // ticks for 80%
-
-    if (msr_rtlib_init(1, MSR_ABTASTFREQUENZ, 10, &msr_reg) < 0) {
-        printk(KERN_ERR "Failed to initialize rtlib!\n");
-        goto out_return;
-    }
-
-    if (!(master = ecrt_request_master(0))) {
-        printk(KERN_ERR "Failed to request master 0!\n");
-        goto out_msr_cleanup;
-    }
-
-    ecrt_master_callbacks(master, request_lock, release_lock, NULL);
-
-    printk(KERN_INFO "Creating domains...\n");
-    if (!(domain1 = ecrt_master_create_domain(master))) {
-        printk(KERN_ERR "Failed to create domains!\n");
-        goto out_release_master;
-    }
-
-    printk(KERN_INFO "Registering Pdos...\n");
-    if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
-        printk(KERN_ERR "Failed to register Pdos.\n");
-        goto out_release_master;
-    }
-
-    printk(KERN_INFO "Activating master...\n");
-    if (ecrt_master_activate(master)) {
-        printk(KERN_ERR "Could not activate master!\n");
-        goto out_release_master;
-    }
-
-    printk("Starting cyclic sample thread...\n");
-    ticks = start_rt_timer(nano2count(TIMERTICKS));
-    if (rt_task_init(&task, msr_run, 0, 2000, 0, 1, NULL)) {
-        printk(KERN_ERR "Failed to init RTAI task!\n");
-        goto out_stop_timer;
-    }
-    if (rt_task_make_periodic(&task, rt_get_time() + ticks, ticks)) {
-        printk(KERN_ERR "Failed to run RTAI task!\n");
-        goto out_stop_task;
-    }
-
-    printk(KERN_INFO "=== EtherCAT RTAI MSR sample module started. ===\n");
-    return 0;
-
- out_stop_task:
-    rt_task_delete(&task);
- out_stop_timer:
-    stop_rt_timer();
- out_release_master:
-    ecrt_release_master(master);
- out_msr_cleanup:
-    msr_rtlib_cleanup();
- out_return:
-    rt_sem_delete(&master_sem);
-    return -1;
-}
-
-/*****************************************************************************/
-
-void __exit cleanup_mod(void)
-{
-    printk(KERN_INFO "=== Unloading EtherCAT RTAI MSR sample module... ===\n");
-
-    rt_task_delete(&task);
-    stop_rt_timer();
-    ecrt_release_master(master);
-    rt_sem_delete(&master_sem);
-    msr_rtlib_cleanup();
-
-    printk(KERN_INFO "=== EtherCAT RTAI MSR sample module unloaded. ===\n");
-}
-
-/*****************************************************************************/
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Florian Pose <fp@igh-essen.com>");
-MODULE_DESCRIPTION("EtherCAT RTAI MSR sample module");
-
-module_init(init_mod);
-module_exit(cleanup_mod);
-
-/*****************************************************************************/
--- a/examples/msr/msrserv.pl	Wed Jul 02 11:26:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,267 +0,0 @@
-#!/usr/bin/perl -w
-
-#------------------------------------------------------------------------------
-#
-#  Copyright (C) 2006  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
-#  as published by the Free Software Foundation; either version 2 of the
-#  License, or (at your option) any later version.
-#
-#  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 right to use EtherCAT Technology is granted and comes free of
-#  charge under condition of compatibility of product made by
-#  Licensee. People intending to distribute/sell products based on the
-#  code, have to sign an agreement to guarantee that products using
-#  software based on IgH EtherCAT master stay compatible with the actual
-#  EtherCAT specification (which are released themselves as an open
-#  standard) as the (only) precondition to have the right to use EtherCAT
-#  Technology, IP and trade marks.
-#
-#------------------------------------------------------------------------------
-#
-#  Multithreaded Server
-#  according to the example from "Programming Perl"
-#  this code is improved according to the example from
-#  perldoc perlipc, so now safely being usable under Perl 5.8
-#  (see note (*))
-#
-#  works with read/write on a device-file
-#
-#------------------------------------------------------------------------------
-
-require 5.002;
-use strict;
-BEGIN { $ENV{PATH} = '/opt/msr/bin:/usr/bin:/bin' }
-use Socket;
-use Carp;
-use FileHandle;
-use Getopt::Std;
-
-use Sys::Syslog qw(:DEFAULT setlogsock);
-
-use vars qw (
-	     $self $pid $dolog $port $dev %opts $selfbase
-	     $len $offset $stream $written $read $log $blksize
-	     $instdir
-	     $authfile %authhosts
-	     );
-
-
-# Do logging to local syslogd by unix-domain socket instead of inetd
-setlogsock("unix");
-
-# Prototypes and some little Tools
-sub spawn;
-sub logmsg {
-  my ($level, $debug, @text) = @_;
-  syslog("daemon|$level", @text) if $debug > $dolog;
-#  print STDERR "daemon|$level", @text, "\n" if $dolog;
-}
-sub out {
-  my $waitpid = wait;
-  logmsg("notice", 2, "$waitpid exited");
-  unlink "$selfbase.pid";
-  exit 0;
-}
-
-sub help {
-  print "\n  usage: $0 [-l og] [-h elp] [-p port] [-d device]\n";
-  exit;
-}
-
-# Process Options
-%opts = (
-	 "l" => 1,
-	 "h" => 0,
-	 "p" => 2345,
-	 "d" => "/dev/msr"
-	 );
-
-getopts("lhp:d:", \%opts);
-
-help if $opts{"h"};
-
-( $self =  $0 ) =~ s+.*/++ ;
-( $selfbase = $self ) =~ s/\..*//;
-$log = "$selfbase.log";
-$dolog = $opts{"l"};
-$port = $opts{"p"};
-$dev = $opts{"d"};
-$blksize = 1024; # try to write as much bytes
-$instdir = "/opt/msr";
-$authfile = "$instdir/etc/hosts.auth";
-
-# Start logging
-openlog($self, 'pid');
-
-# Flush Output, dont buffer
-$| = 1;
-
-# first fork and run in background
-if ($pid = fork) {
-#  open LOG, ">$log" if $dolog;
-#  close LOG;
-  logmsg("notice", 2, "forked process: $pid\n");
-  exit 0;
-}
-
-# Server tells about startup success
-open (PID, ">/$instdir/var/run/$selfbase.pid");
-print PID "$$\n";
-close PID;
-
-# Cleanup on exit (due to kill -TERM signal)
-$SIG{TERM} = \&out;
-
-# We use streams
-my $proto = getprotobyname('tcp');
-
-# Open Server socket
-socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
-setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
-  or die "setsocketopt: $!";
-bind (Server, sockaddr_in($port, INADDR_ANY))
-  or die "bind: $!";
-listen (Server, SOMAXCONN)
-  or die "listen: $!";
-
-%authhosts = ();
-# get authorized hosts
-open (AUTH, $authfile)
-  or logmsg ("notice", 2, "Could not read allowed hosts file: $authfile");
-while (<AUTH>) {
-    chomp;
-    my $host = lc $_;
-     if ($host =~ /^[\d\w]/) {
-	 $authhosts{$_} = 1;
-	 logmsg ("notice", 2, "Authorized host: >$host<");
-     }
-}
-close (AUTH);
-
-# tell about open server socket
-logmsg ("notice", 2, "Server started at port $port");
-
-my $waitedpid = 0;
-my $paddr;
-
-# wait for children to return, thus avoiding zombies
-# improvement (*)
-use POSIX ":sys_wait_h";
-sub REAPER {
-  my $child;
-  while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
-    logmsg ("notice", 2, "reaped $waitedpid", ($? ? " with exit $?" : ""));
-  }
-  $SIG{CHLD} = \&REAPER;  # loathe sysV
-}
-
-# also all sub-processes should wait for their children
-$SIG{CHLD} = \&REAPER;
-
-# start a new server for every incoming request
-# improvement (*) -- loop forever
-
-while ( 1 ) {
-  for ( $waitedpid = 0;
-	($paddr = accept(Client,Server)) || $waitedpid;
-	$waitedpid = 0, close Client ) {
-    next if $waitedpid and not $paddr;
-    my ($port, $iaddr) = sockaddr_in($paddr);
-    my $name = lc gethostbyaddr($iaddr, AF_INET);
-    my $ipaddr = inet_ntoa($iaddr);
-    my $n = 0;
-
-# tell about the requesting client
-    logmsg ("info", 2, "Connection from >$ipaddr< ($name) at port $port");
-
-    spawn sub {
-      my ($head, $hlen, $pos, $pegel, $typ, $siz, $nch, $nrec, $dat, $i, $j, $n, $llen); 
-      my ($watchpegel, $shmpegel);
-      my ($rin, $rout, $in, $line, $data_requested, $oversample);
-      my (@channels);
-
-#   to use stdio on writing to Client
-      Client->autoflush();
-
-#   Open Device
-      sysopen (DEV, "$dev", O_RDWR | O_NONBLOCK, 0666) or die("can't open $dev");
-
-#   Bitmask to check for input on stdin
-      $rin = "";
-      vec($rin, fileno(Client), 1) = 1;
-
-#   check for authorized hosts
-      my $access = 'deny';
-      $access = 'allow' if $authhosts{$ipaddr};
-      $line = "<remote_host host=\"$ipaddr\" access=\"$access\">\n";
-      logmsg ("info", 2, $line);
-      $len = length $line;
-      $offset = 0;
-      while ($len) {
-	$written = syswrite (DEV, $line, $len, $offset);
-	$len -= $written;
-	$offset += $written;
-      }
-
-      while ( 1 ) {
-	$in = select ($rout=$rin, undef, undef, 0.0); # poll client
-#     look for any Input from Client
-	if ($in) {
-#       exit on EOF
-	  $len = sysread (Client, $line, $blksize) or exit;
-	  logmsg("info", 0, "got $len bytes: \"$line\"");
-	  $offset = 0;
-#       copy request to device
-	  while ($len) {
-	    $written = syswrite (DEV, $line, $len, $offset);
-	    $len -= $written;
-	    $offset += $written;
-	  }
-	}
-#     look for some output from device
-	if ($len = sysread DEV, $stream, $blksize) {
-	  print Client $stream;
-	} else {
-	  select undef, undef, undef, 0.1; # calm down if nothing on device
-	}
-      }
-    };
-    logmsg("info", 2, "spawned\n");
-  }
-  logmsg("info", 2, "server loop\n");
-}
-
-sub spawn {
-  my $coderef = shift;
-
-  unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
-    confess "usage: spawn CODEREF";
-  }
-  my $pid;
-  if (!defined($pid = fork)) {
-    logmsg ("notice", 2, "fork failed: $!");
-    return;
-  } elsif ($pid) {
-    logmsg ("notice", 2, "Request $pid");
-    return; # Parent
-  }
-
-# do not use fdup as in the original example
-# open (STDIN, "<&Client") or die "Can't dup client to stdin";
-# open (STDOUT, ">&Client") or die "Can't dup client to stdout";
-# STDOUT->autoflush();
-  exit &$coderef();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/rtai/README	Wed Jul 02 12:16:48 2008 +0000
@@ -0,0 +1,31 @@
+-------------------------------------------------------------------------------
+
+$Id$
+
+-------------------------------------------------------------------------------
+
+This is a minimal example module for the use of the EtherCAT master realtime
+interface with an RTAI thread.
+
+The module expects an RTAI installation. Configure the master sources
+specifying --with-rtai-dir to have the right include paths.
+
+Most probably you'll have different EtherCAT slaves present. Try adjusting the
+section "process data" in rtai_sample.c to your bus configuration.
+
+There are some features that can be disabled by commenting out the respective
+defines at the head of rtai_sample.c.
+
+---
+
+To build the example module, call:
+
+make modules
+
+To run it, load the appropriate RTAI modules and call:
+
+insmod ec_rtai_sample.ko
+
+...and watch the system logs for the outputs.
+
+-------------------------------------------------------------------------------
--- a/examples/rtai/rtai_sample.c	Wed Jul 02 11:26:51 2008 +0000
+++ b/examples/rtai/rtai_sample.c	Wed Jul 02 12:16:48 2008 +0000
@@ -37,100 +37,210 @@
 #include <linux/module.h>
 
 // RTAI
-#include "rtai_sched.h"
-#include "rtai_sem.h"
+#include <rtai_sched.h>
+#include <rtai_sem.h>
 
 // EtherCAT
 #include "../../include/ecrt.h"
-#include "../../include/ecdb.h"
-
-/*****************************************************************************/
-
-// RTAI task frequency in Hz
-#define FREQUENCY 2000
+
+/*****************************************************************************/
+
+// Module parameters
+
+#define FREQUENCY 2000 // task frequency in Hz
 #define INHIBIT_TIME 20
 
 #define TIMERTICKS (1000000000 / FREQUENCY)
 
+// Optional features (comment to disable)
+#define CONFIGURE_PDOS
+
 #define PFX "ec_rtai_sample: "
 
 /*****************************************************************************/
 
+// EtherCAT
+static ec_master_t *master = NULL;
+static ec_master_state_t master_state = {};
+spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
+
+static ec_domain_t *domain1 = NULL;
+static ec_domain_state_t domain1_state = {};
+
+static ec_slave_config_t *sc_ana_in = NULL;
+static ec_slave_config_state_t sc_ana_in_state = {};
+
 // RTAI
 static RT_TASK task;
 static SEM master_sem;
 static cycles_t t_last_cycle = 0, t_critical;
 
-// EtherCAT
-static ec_master_t *master = NULL;
-static ec_domain_t *domain1 = NULL;
-static ec_master_status_t master_status, old_status = {};
-
-// data fields
-static void *r_dig_out;
-static void *r_ana_out;
-static void *r_count;
-//static void *r_freq;
-
-const static ec_pdo_reg_t domain1_pdo_regs[] = {
-    {"2",      Beckhoff_EL2004_Outputs,   &r_dig_out},
-    {"3",      Beckhoff_EL4132_Output1,   &r_ana_out},
-    {"#888:1", Beckhoff_EL5101_Value,     &r_count},
-    //{"4",      Beckhoff_EL5101_Frequency, &r_freq},
+/*****************************************************************************/
+
+// process data
+static uint8_t *domain1_pd; // process data memory
+
+#define AnaInSlavePos  0, 1
+#define DigOutSlavePos 0, 3
+
+#define Beckhoff_EL2004 0x00000002, 0x07D43052
+#define Beckhoff_EL3162 0x00000002, 0x0C5A3052
+
+static unsigned int off_ana_in; // offsets for Pdo entries
+static unsigned int off_dig_out;
+
+const static ec_pdo_entry_reg_t domain1_regs[] = {
+    {AnaInSlavePos,  Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
+    {DigOutSlavePos, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
     {}
 };
 
+static unsigned int counter = 0;
+static unsigned int blink = 0;
+
+/*****************************************************************************/
+
+#ifdef CONFIGURE_PDOS
+static ec_pdo_entry_info_t el3162_channel1[] = {
+    {0x3101, 1,  8}, // status
+    {0x3101, 2, 16}  // value
+};
+
+static ec_pdo_entry_info_t el3162_channel2[] = {
+    {0x3102, 1,  8}, // status
+    {0x3102, 2, 16}  // value
+};
+
+static ec_pdo_info_t el3162_pdos[] = {
+    {0x1A00, 2, el3162_channel1},
+    {0x1A01, 2, el3162_channel2}
+};
+
+static ec_sync_info_t el3162_syncs[] = {
+    {2, EC_DIR_OUTPUT},
+    {3, EC_DIR_INPUT, 2, el3162_pdos},
+    {0xff}
+};
+
+static ec_pdo_entry_info_t el2004_channels[] = {
+    {0x3001, 1, 1}, // Value 1
+    {0x3001, 2, 1}, // Value 2
+    {0x3001, 3, 1}, // Value 3
+    {0x3001, 4, 1}  // Value 4
+};
+
+static ec_pdo_info_t el2004_pdos[] = {
+    {0x1600, 1, &el2004_channels[0]},
+    {0x1601, 1, &el2004_channels[1]},
+    {0x1602, 1, &el2004_channels[2]},
+    {0x1603, 1, &el2004_channels[3]}
+};
+
+static ec_sync_info_t el2004_syncs[] = {
+    {0, EC_DIR_OUTPUT, 4, el2004_pdos},
+    {1, EC_DIR_INPUT},
+    {0xff}
+};
+#endif
+
+/*****************************************************************************/
+
+void check_domain1_state(void)
+{
+    ec_domain_state_t ds;
+
+    spin_lock(&master_lock);
+    ecrt_domain_state(domain1, &ds);
+    spin_unlock(&master_lock);
+
+    if (ds.working_counter != domain1_state.working_counter)
+        printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
+    if (ds.wc_state != domain1_state.wc_state)
+        printk(KERN_INFO PFX "Domain1: State %u.\n", ds.wc_state);
+
+    domain1_state = ds;
+}
+
+/*****************************************************************************/
+
+void check_master_state(void)
+{
+    ec_master_state_t ms;
+
+    spin_lock(&master_lock);
+    ecrt_master_state(master, &ms);
+    spin_unlock(&master_lock);
+
+    if (ms.slaves_responding != master_state.slaves_responding)
+        printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
+    if (ms.al_states != master_state.al_states)
+        printk(KERN_INFO PFX "AL states: 0x%02X.\n", ms.al_states);
+    if (ms.link_up != master_state.link_up)
+        printk(KERN_INFO PFX "Link is %s.\n", ms.link_up ? "up" : "down");
+
+    master_state = ms;
+}
+
+/*****************************************************************************/
+
+void check_slave_config_states(void)
+{
+    ec_slave_config_state_t s;
+
+    spin_lock(&master_lock);
+    ecrt_slave_config_state(sc_ana_in, &s);
+    spin_unlock(&master_lock);
+
+    if (s.al_state != sc_ana_in_state.al_state)
+        printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
+    if (s.online != sc_ana_in_state.online)
+        printk(KERN_INFO PFX "AnaIn: %s.\n", s.online ? "online" : "offline");
+    if (s.operational != sc_ana_in_state.operational)
+        printk(KERN_INFO PFX "AnaIn: %soperational.\n",
+                s.operational ? "" : "Not ");
+
+    sc_ana_in_state = s;
+}
+
 /*****************************************************************************/
 
 void run(long data)
 {
-    static unsigned int blink = 0;
-    static unsigned int counter = 0;
-
     while (1) {
         t_last_cycle = get_cycles();
 
+        // receive process data
         rt_sem_wait(&master_sem);
         ecrt_master_receive(master);
         ecrt_domain_process(domain1);
         rt_sem_signal(&master_sem);
 
-        // process data
-        EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
+        // check process data state (optional)
+        check_domain1_state();
+
+        if (counter) {
+            counter--;
+        } else { // do this at 1 Hz
+            counter = FREQUENCY;
+
+            // calculate new process data
+            blink = !blink;
+
+            // check for master state (optional)
+            check_master_state();
+
+            // check for islave configuration state(s) (optional)
+            check_slave_config_states();
+        }
+
+        // write process data
+        EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
 
         rt_sem_wait(&master_sem);
         ecrt_domain_queue(domain1);
         ecrt_master_send(master);
         rt_sem_signal(&master_sem);
 		
-        if (counter) {
-            counter--;
-        }
-        else {
-            counter = FREQUENCY;
-            blink = !blink;
-
-            rt_sem_wait(&master_sem);
-            ecrt_master_get_status(master, &master_status);
-            rt_sem_signal(&master_sem);
-
-            if (master_status.bus_status != old_status.bus_status) {
-                printk(KERN_INFO PFX "bus status changed to %i.\n",
-                        master_status.bus_status);
-            }
-            if (master_status.bus_tainted != old_status.bus_tainted) {
-                printk(KERN_INFO PFX "tainted flag changed to %u.\n",
-                        master_status.bus_tainted);
-            }
-            if (master_status.slaves_responding !=
-                    old_status.slaves_responding) {
-                printk(KERN_INFO PFX "slaves_responding changed to %u.\n",
-                        master_status.slaves_responding);
-            }
-
-            old_status = master_status;
-        }
-
         rt_task_wait_period();
     }
 }
@@ -159,6 +269,9 @@
 int __init init_mod(void)
 {
     RTIME tick_period, requested_ticks, now;
+#ifdef CONFIGURE_PDOS
+    ec_slave_config_t *sc;
+#endif
 
     printk(KERN_INFO PFX "Starting...\n");
 
@@ -173,15 +286,39 @@
 
     ecrt_master_callbacks(master, request_lock, release_lock, NULL);
 
-    printk(KERN_INFO PFX "Creating domain...\n");
+    printk(KERN_INFO PFX "Registering domain...\n");
     if (!(domain1 = ecrt_master_create_domain(master))) {
         printk(KERN_ERR PFX "Domain creation failed!\n");
         goto out_release_master;
     }
 
-    printk(KERN_INFO PFX "Registering Pdos...\n");
-    if (ecrt_domain_register_pdo_list(domain1, domain1_pdo_regs)) {
-        printk(KERN_ERR PFX "Pdo registration failed!\n");
+    if (!(sc_ana_in = ecrt_master_slave_config(
+                    master, AnaInSlavePos, Beckhoff_EL3162))) {
+        printk(KERN_ERR PFX "Failed to get slave configuration.\n");
+        goto out_release_master;
+    }
+
+#ifdef CONFIGURE_PDOS
+    printk(KERN_INFO PFX "Configuring Pdos...\n");
+    if (ecrt_slave_config_sync_managers(sc_ana_in, EC_END, el3162_syncs)) {
+        printk(KERN_ERR PFX "Failed to configure Pdos.\n");
+        goto out_release_master;
+    }
+
+    if (!(sc = ecrt_master_slave_config(master, DigOutSlavePos, Beckhoff_EL2004))) {
+        printk(KERN_ERR PFX "Failed to get slave configuration.\n");
+        goto out_release_master;
+    }
+
+    if (ecrt_slave_config_sync_managers(sc, EC_END, el2004_syncs)) {
+        printk(KERN_ERR PFX "Failed to configure Pdos.\n");
+        goto out_release_master;
+    }
+#endif
+
+    printk(KERN_INFO PFX "Registering Pdo entries...\n");
+    if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
+        printk(KERN_ERR PFX "Pdo entry registration failed!\n");
         goto out_release_master;
     }
 
@@ -191,6 +328,9 @@
         goto out_release_master;
     }
 
+    // Get internal process data for domain
+    domain1_pd = ecrt_domain_data(domain1);
+
     printk(KERN_INFO PFX "Starting cyclic sample thread...\n");
     requested_ticks = nano2count(TIMERTICKS);
     tick_period = start_rt_timer(requested_ticks);