Removed MSR example; adapted RTAI example; README files for examples.
--- 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);