VERSION 1.1: New realtime interface, only state machines.
This commit is contained in:
parent
fe60abcfc7
commit
258b4d998d
6
TODO
6
TODO
|
|
@ -8,12 +8,6 @@ $Id$
|
|||
|
||||
Important things to do:
|
||||
|
||||
* New SDO-Configuration interface
|
||||
|
||||
* Remove slave type information from master / New RT Interface
|
||||
|
||||
* Always use state machines / remove simple IO code
|
||||
|
||||
* SysFS interface
|
||||
- Add secondary slave address
|
||||
- Add SDO dictionary
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../../include/ecrt.h" // EtherCAT realtime interface
|
||||
#include "../../include/ecdb.h" // EtherCAT slave database
|
||||
|
||||
#define ASYNC
|
||||
#define FREQUENCY 100
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -56,16 +56,14 @@ ec_domain_t *domain1 = NULL;
|
|||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
// data fields
|
||||
//void *r_ssi_input, *r_ssi_status, *r_4102[3];
|
||||
void *r_kbus_in, *r_kbus_out;
|
||||
void *r_ana_out;
|
||||
|
||||
// channels
|
||||
uint32_t k_pos;
|
||||
uint8_t k_stat;
|
||||
|
||||
ec_field_init_t domain1_fields[] = {
|
||||
//{&r_kbus_out, "0", "Beckhoff", "BK1120", "Outputs", 0},
|
||||
//{&r_kbus_in, "0", "Beckhoff", "BK1120", "Inputs", 0},
|
||||
ec_pdo_reg_t domain1_pdos[] = {
|
||||
{"1", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -74,31 +72,19 @@ ec_field_init_t domain1_fields[] = {
|
|||
void run(unsigned long data)
|
||||
{
|
||||
static unsigned int counter = 0;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
|
||||
#ifdef ASYNC
|
||||
// receive
|
||||
ecrt_master_async_receive(master);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#else
|
||||
// send and receive
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_sync_io(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#endif
|
||||
|
||||
// process data
|
||||
//k_pos = EC_READ_U32(r_ssi);
|
||||
|
||||
#ifdef ASYNC
|
||||
// send
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_async_send(master);
|
||||
#endif
|
||||
ecrt_master_send(master);
|
||||
|
||||
spin_unlock(&master_lock);
|
||||
|
||||
|
|
@ -107,9 +93,10 @@ void run(unsigned long data)
|
|||
}
|
||||
else {
|
||||
counter = FREQUENCY;
|
||||
printk(KERN_INFO "input = ");
|
||||
for (i = 0; i < 22; i++) printk("%02X ", *((uint8_t *) r_kbus_in + i));
|
||||
printk("\n");
|
||||
//printk(KERN_INFO "input = ");
|
||||
//for (i = 0; i < 22; i++)
|
||||
// printk("%02X ", *((uint8_t *) r_kbus_in + i));
|
||||
//printk("\n");
|
||||
}
|
||||
|
||||
// restart timer
|
||||
|
|
@ -136,8 +123,6 @@ void release_lock(void *data)
|
|||
|
||||
int __init init_mini_module(void)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
|
||||
printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
|
||||
|
||||
if ((master = ecrt_request_master(0)) == NULL) {
|
||||
|
|
@ -154,69 +139,19 @@ int __init init_mini_module(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Registering domain fields...\n");
|
||||
if (ecrt_domain_register_field_list(domain1, domain1_fields)) {
|
||||
printk(KERN_ERR "Field registration failed!\n");
|
||||
printk(KERN_INFO "Registering PDOs...\n");
|
||||
if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
|
||||
printk(KERN_ERR "PDO registration failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 1
|
||||
printk(KERN_INFO "Setting variable data field sizes...\n");
|
||||
if (!(slave = ecrt_master_get_slave(master, "0"))) {
|
||||
printk(KERN_ERR "Failed to get slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_slave_field_size(slave, "Outputs", 0, 0x16);
|
||||
ecrt_slave_field_size(slave, "Inputs", 0, 0x16);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Activating master...\n");
|
||||
if (ecrt_master_activate(master)) {
|
||||
printk(KERN_ERR "Failed to activate master!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (ecrt_master_fetch_sdo_lists(master)) {
|
||||
printk(KERN_ERR "Failed to fetch SDO lists!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_master_print(master, 2);
|
||||
#else
|
||||
ecrt_master_print(master, 0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!(slave = ecrt_master_get_slave(master, "5"))) {
|
||||
printk(KERN_ERR "Failed to get slave 5!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
|
||||
if (ecrt_slave_sdo_write_exp8(slave, 0x4061, 1, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 2, 1) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 3, 1) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4066, 0, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4067, 0, 4) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4068, 0, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4069, 0, 25) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x406A, 0, 25) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x406B, 0, 50)) {
|
||||
printk(KERN_ERR "Failed to configure SSI slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASYNC
|
||||
// send once and wait...
|
||||
ecrt_master_prepare_async_io(master);
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
if (ecrt_master_start_eoe(master)) {
|
||||
printk(KERN_ERR "Failed to start EoE processing!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
ecrt_master_prepare(master);
|
||||
|
||||
printk("Starting cyclic sample thread.\n");
|
||||
init_timer(&timer);
|
||||
|
|
@ -227,10 +162,6 @@ int __init init_mini_module(void)
|
|||
printk(KERN_INFO "=== Minimal EtherCAT environment started. ===\n");
|
||||
return 0;
|
||||
|
||||
#if 1
|
||||
out_deactivate:
|
||||
ecrt_master_deactivate(master);
|
||||
#endif
|
||||
out_release_master:
|
||||
ecrt_release_master(master);
|
||||
out_return:
|
||||
|
|
|
|||
|
|
@ -48,8 +48,7 @@
|
|||
|
||||
// EtherCAT
|
||||
#include "../../include/ecrt.h"
|
||||
|
||||
#define ASYNC
|
||||
#include "../../include/ecdb.h"
|
||||
|
||||
#define HZREDUCTION (MSR_ABTASTFREQUENZ / HZ)
|
||||
#define TIMERTICKS (1000000000 / MSR_ABTASTFREQUENZ)
|
||||
|
|
@ -66,16 +65,13 @@ ec_master_t *master = NULL;
|
|||
ec_domain_t *domain1 = NULL;
|
||||
|
||||
// raw process data
|
||||
void *r_ssi;
|
||||
void *r_ssi_st;
|
||||
void *r_ana_out;
|
||||
|
||||
// Channels
|
||||
uint32_t k_ssi;
|
||||
uint32_t k_ssi_st;
|
||||
double k_ana_out;
|
||||
|
||||
ec_field_init_t domain1_fields[] = {
|
||||
{&r_ssi, "0:3", "Beckhoff", "EL5001", "InputValue", 0},
|
||||
{&r_ssi_st, "0:3", "Beckhoff", "EL5001", "Status", 0},
|
||||
ec_pdo_reg_t domain1_pdos[] = {
|
||||
{"3", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -85,28 +81,16 @@ void msr_controller_run(void)
|
|||
{
|
||||
rt_sem_wait(&master_sem);
|
||||
|
||||
#ifdef ASYNC
|
||||
// Empfangen
|
||||
ecrt_master_async_receive(master);
|
||||
// receive
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#else
|
||||
// Senden und empfangen
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_sync_io(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#endif
|
||||
|
||||
// Prozessdaten verarbeiten
|
||||
k_ssi = EC_READ_U32(r_ssi);
|
||||
k_ssi_st = EC_READ_U8 (r_ssi_st);
|
||||
// Process data
|
||||
EC_WRITE_S16(r_ana_out, k_ana_out / 10.0 * 0x7FFF);
|
||||
|
||||
#ifdef ASYNC
|
||||
// Senden
|
||||
ecrt_domain_queue(domain1);
|
||||
// Send
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_async_send(master);
|
||||
#endif
|
||||
ecrt_master_send(master);
|
||||
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
|
|
@ -128,8 +112,7 @@ void msr_run(long data)
|
|||
|
||||
int msr_reg(void)
|
||||
{
|
||||
msr_reg_kanal("/ssi_position", "", &k_ssi, TUINT);
|
||||
msr_reg_kanal("/ssi_status", "", &k_ssi_st, TUINT);
|
||||
msr_reg_kanal("/ana_out", "", &k_ana_out, TDBL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -157,9 +140,6 @@ void release_lock(void *data)
|
|||
int __init init_mod(void)
|
||||
{
|
||||
RTIME ticks;
|
||||
#if 0
|
||||
ec_slave_t *slave;
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "=== Starting EtherCAT RTAI MSR sample module... ===\n");
|
||||
|
||||
|
|
@ -171,7 +151,7 @@ int __init init_mod(void)
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
if ((master = ecrt_request_master(0)) == NULL) {
|
||||
if (!(master = ecrt_request_master(0))) {
|
||||
printk(KERN_ERR "Failed to request master 0!\n");
|
||||
goto out_msr_cleanup;
|
||||
}
|
||||
|
|
@ -184,9 +164,9 @@ int __init init_mod(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Registering domain fields...\n");
|
||||
if (ecrt_domain_register_field_list(domain1, domain1_fields)) {
|
||||
printk(KERN_ERR "Failed to register domain fields.\n");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -196,59 +176,7 @@ int __init init_mod(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (ecrt_master_fetch_sdo_lists(master)) {
|
||||
printk(KERN_ERR "Failed to fetch SDO lists!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_master_print(master, 2);
|
||||
#else
|
||||
ecrt_master_print(master, 0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!(slave = ecrt_master_get_slave(master, "0:3"))) {
|
||||
printk(KERN_ERR "Failed to get slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
|
||||
if (
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 1, 1) || // disable frame error bit
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 2, 0) || // power failure bit
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 3, 1) || // inhibit time
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 4, 0) || // test mode
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4066, 0, 0) || // graycode
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4067, 0, 5) || // 125kbaud
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4068, 0, 0) || // single-turn
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4069, 0, 25) || // frame size
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x406A, 0, 25) || // data length
|
||||
ecrt_slave_sdo_write_exp16(slave, 0x406B, 0, 50) // inhibit time in us
|
||||
) {
|
||||
printk(KERN_ERR "Failed to configure SSI slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!(slave = ecrt_master_get_slave(master, "1:0"))) {
|
||||
printk(KERN_ERR "Failed to get slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
if (ecrt_slave_write_alias(slave, 0x5678)) {
|
||||
printk(KERN_ERR "Failed to write alias!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASYNC
|
||||
// Einmal senden und warten...
|
||||
ecrt_master_prepare_async_io(master);
|
||||
#endif
|
||||
|
||||
if (ecrt_master_start_eoe(master)) {
|
||||
printk(KERN_ERR "Failed to start EoE processing!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_master_prepare(master);
|
||||
|
||||
printk("Starting cyclic sample thread...\n");
|
||||
ticks = start_rt_timer(nano2count(TIMERTICKS));
|
||||
|
|
@ -268,7 +196,6 @@ int __init init_mod(void)
|
|||
rt_task_delete(&task);
|
||||
out_stop_timer:
|
||||
stop_rt_timer();
|
||||
out_deactivate:
|
||||
ecrt_master_deactivate(master);
|
||||
out_release_master:
|
||||
ecrt_release_master(master);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
// EtherCAT
|
||||
#include "../../include/ecrt.h"
|
||||
#include "../../include/ecdb.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -51,12 +52,8 @@ MODULE_DESCRIPTION("EtherCAT RTAI sample module");
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
// comment this for synchronous IO
|
||||
#define ASYNC
|
||||
|
||||
// RTAI task frequency in Hz
|
||||
#define FREQUENCY 10000
|
||||
|
||||
#define TIMERTICKS (1000000000 / FREQUENCY)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -64,22 +61,20 @@ MODULE_DESCRIPTION("EtherCAT RTAI sample module");
|
|||
// RTAI
|
||||
RT_TASK task;
|
||||
SEM master_sem;
|
||||
cycles_t t_last_start = 0;
|
||||
cycles_t t_critical;
|
||||
cycles_t t_last_start = 0, t_critical;
|
||||
|
||||
// EtherCAT
|
||||
ec_master_t *master = NULL;
|
||||
ec_domain_t *domain1 = NULL;
|
||||
|
||||
// data fields
|
||||
void *r_ssi_input;
|
||||
void *r_ana_out;
|
||||
|
||||
// channels
|
||||
uint32_t k_pos;
|
||||
|
||||
ec_field_init_t domain1_fields[] = {
|
||||
{&r_ssi_input, "3", "Beckhoff", "EL5001", "InputValue", 0},
|
||||
{NULL, "2", "Beckhoff", "EL4132", "OutputValue", 0},
|
||||
ec_pdo_reg_t domain1_pdos[] = {
|
||||
{"2", Beckhoff_EL4132_Output1, &r_ana_out},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -92,27 +87,14 @@ void run(long data)
|
|||
t_last_start = get_cycles();
|
||||
rt_sem_wait(&master_sem);
|
||||
|
||||
#ifdef ASYNC
|
||||
// receive
|
||||
ecrt_master_async_receive(master);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#else
|
||||
// send and receive
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_sync_io(master);
|
||||
ecrt_domain_process(domain1);
|
||||
#endif
|
||||
|
||||
// process data
|
||||
k_pos = EC_READ_U32(r_ssi_input);
|
||||
//k_pos = EC_READ_U32(r_ssi_input);
|
||||
|
||||
#ifdef ASYNC
|
||||
// send
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_run(master);
|
||||
ecrt_master_async_send(master);
|
||||
#endif
|
||||
ecrt_master_send(master);
|
||||
|
||||
rt_sem_signal(&master_sem);
|
||||
rt_task_wait_period();
|
||||
|
|
@ -158,15 +140,14 @@ int __init init_mod(void)
|
|||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
|
||||
printk(KERN_INFO "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master)))
|
||||
{
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
printk(KERN_ERR "Domain creation failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Registering domain fields...\n");
|
||||
if (ecrt_domain_register_field_list(domain1, domain1_fields)) {
|
||||
printk(KERN_ERR "Field registration failed!\n");
|
||||
printk(KERN_INFO "Registering PDOs...\n");
|
||||
if (ecrt_domain_register_pdo_list(domain1, domain1_pdos)) {
|
||||
printk(KERN_ERR "PDO registration failed!\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
|
|
@ -176,53 +157,7 @@ int __init init_mod(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (ecrt_master_fetch_sdo_lists(master)) {
|
||||
printk(KERN_ERR "Failed to fetch SDO lists!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_master_print(master, 2);
|
||||
#else
|
||||
ecrt_master_print(master, 0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!(slave = ecrt_master_get_slave(master, "5"))) {
|
||||
printk(KERN_ERR "Failed to get slave 5!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
|
||||
if (ecrt_slave_sdo_write_exp8(slave, 0x4061, 1, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 2, 1) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4061, 3, 1) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4066, 0, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4067, 0, 4) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4068, 0, 0) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x4069, 0, 25) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x406A, 0, 25) ||
|
||||
ecrt_slave_sdo_write_exp8(slave, 0x406B, 0, 50)) {
|
||||
printk(KERN_ERR "Failed to configure SSI slave!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printk(KERN_INFO "Writing alias...\n");
|
||||
if (ecrt_slave_sdo_write_exp16(slave, 0xBEEF)) {
|
||||
printk(KERN_ERR "Failed to write alias!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASYNC
|
||||
// send once and wait...
|
||||
ecrt_master_prepare_async_io(master);
|
||||
#endif
|
||||
|
||||
if (ecrt_master_start_eoe(master)) {
|
||||
printk(KERN_ERR "Failed to start EoE processing!\n");
|
||||
goto out_deactivate;
|
||||
}
|
||||
ecrt_master_prepare(master);
|
||||
|
||||
printk("Starting cyclic sample thread...\n");
|
||||
requested_ticks = nano2count(TIMERTICKS);
|
||||
|
|
@ -248,7 +183,6 @@ int __init init_mod(void)
|
|||
rt_task_delete(&task);
|
||||
out_stop_timer:
|
||||
stop_rt_timer();
|
||||
out_deactivate:
|
||||
ecrt_master_deactivate(master);
|
||||
out_release_master:
|
||||
ecrt_release_master(master);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT Slave Database.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __ECDB_H__
|
||||
#define __ECDB_H__
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define Beckhoff_EL4132_Output1 0x00000002, 0x10243052, 0x6411, 1
|
||||
#define Beckhoff_EL4132_Output2 0x00000002, 0x10243052, 0x6411, 2
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -69,23 +69,22 @@ struct ec_slave;
|
|||
typedef struct ec_slave ec_slave_t; /**< \see ec_slave */
|
||||
|
||||
/**
|
||||
Initialization type for field registrations.
|
||||
This type is used as a parameter for the ec_domain_register_field_list()
|
||||
Initialization type for PDO registrations.
|
||||
This type is used as a parameter for the ec_domain_register_pdo_list()
|
||||
function.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void **data_ptr; /**< address of the process data pointer */
|
||||
const char *slave_address; /**< slave address string (see
|
||||
ecrt_master_get_slave()) */
|
||||
const char *vendor_name; /**< vendor name */
|
||||
const char *product_name; /**< product name */
|
||||
const char *field_name; /**< data field name */
|
||||
unsigned int field_index; /**< index in data fields with same name */
|
||||
unsigned int field_count; /**< number of data fields with same name */
|
||||
uint32_t vendor_id; /**< vendor ID */
|
||||
uint32_t product_code; /**< product code */
|
||||
uint16_t pdo_index; /**< PDO index */
|
||||
uint8_t pdo_subindex; /**< PDO subindex */
|
||||
void **data_ptr; /**< address of the process data pointer */
|
||||
}
|
||||
ec_field_init_t;
|
||||
ec_pdo_reg_t;
|
||||
|
||||
/******************************************************************************
|
||||
* Master request functions
|
||||
|
|
@ -106,66 +105,47 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master);
|
|||
int ecrt_master_activate(ec_master_t *master);
|
||||
void ecrt_master_deactivate(ec_master_t *master);
|
||||
|
||||
int ecrt_master_fetch_sdo_lists(ec_master_t *master);
|
||||
void ecrt_master_prepare(ec_master_t *master);
|
||||
|
||||
void ecrt_master_sync_io(ec_master_t *master);
|
||||
void ecrt_master_async_send(ec_master_t *master);
|
||||
void ecrt_master_async_receive(ec_master_t *master);
|
||||
void ecrt_master_prepare_async_io(ec_master_t *master);
|
||||
void ecrt_master_send(ec_master_t *master);
|
||||
void ecrt_master_receive(ec_master_t *master);
|
||||
|
||||
void ecrt_master_run(ec_master_t *master);
|
||||
|
||||
int ecrt_master_start_eoe(ec_master_t *master);
|
||||
|
||||
void ecrt_master_debug(ec_master_t *master, int level);
|
||||
void ecrt_master_print(const ec_master_t *master, unsigned int verbosity);
|
||||
|
||||
ec_slave_t *ecrt_master_get_slave(const ec_master_t *, const char *);
|
||||
|
||||
int ecrt_master_state(const ec_master_t *master);
|
||||
|
||||
/******************************************************************************
|
||||
* Domain Methods
|
||||
*****************************************************************************/
|
||||
|
||||
ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain,
|
||||
const char *address,
|
||||
const char *vendor_name,
|
||||
const char *product_name,
|
||||
void **data_ptr, const char *field_name,
|
||||
unsigned int field_index,
|
||||
unsigned int field_count);
|
||||
int ecrt_domain_register_field_list(ec_domain_t *domain,
|
||||
const ec_field_init_t *fields);
|
||||
ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
|
||||
const char *address,
|
||||
uint32_t vendor_id,
|
||||
uint32_t product_code,
|
||||
uint16_t pdo_index,
|
||||
uint8_t pdo_subindex,
|
||||
void **data_ptr);
|
||||
int ecrt_domain_register_pdo_list(ec_domain_t *domain,
|
||||
const ec_pdo_reg_t *pdos);
|
||||
|
||||
void ecrt_domain_queue(ec_domain_t *domain);
|
||||
void ecrt_domain_process(ec_domain_t *domain);
|
||||
|
||||
int ecrt_domain_state(ec_domain_t *domain);
|
||||
int ecrt_domain_state(const ec_domain_t *domain);
|
||||
|
||||
/******************************************************************************
|
||||
* Slave Methods
|
||||
*****************************************************************************/
|
||||
|
||||
/* there SDO functions are deprecated! */
|
||||
int ecrt_slave_conf_sdo8(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint8_t value);
|
||||
int ecrt_slave_conf_sdo16(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint16_t value);
|
||||
int ecrt_slave_conf_sdo32(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint32_t value);
|
||||
|
||||
int ecrt_slave_sdo_read_exp8(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint8_t *value);
|
||||
int ecrt_slave_sdo_read_exp16(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint16_t *value);
|
||||
int ecrt_slave_sdo_read_exp32(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint32_t *value);
|
||||
int ecrt_slave_sdo_write_exp8(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint8_t value);
|
||||
int ecrt_slave_sdo_write_exp16(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint16_t value);
|
||||
int ecrt_slave_sdo_write_exp32(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint32_t value);
|
||||
int ecrt_slave_sdo_read(ec_slave_t *slave, uint16_t sdo_index,
|
||||
uint8_t sdo_subindex, uint8_t *data, size_t *size);
|
||||
|
||||
int ecrt_slave_write_alias(ec_slave_t *slave, uint16_t alias); // deprecated!
|
||||
|
||||
int ecrt_slave_field_size(ec_slave_t *slave, const char *field_name,
|
||||
unsigned int field_index, size_t size);
|
||||
int ecrt_slave_pdo_size(ec_slave_t *slave, uint16_t pdo_index,
|
||||
uint8_t pdo_subindex, size_t size);
|
||||
|
||||
/******************************************************************************
|
||||
* Bitwise read/write macros
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ ifneq ($(KERNELRELEASE),)
|
|||
|
||||
obj-m := ec_master.o
|
||||
|
||||
ec_master-objs := module.o master.o device.o slave.o datagram.o types.o \
|
||||
domain.o mailbox.o canopen.o ethernet.o debug.o fsm.o
|
||||
ec_master-objs := module.o master.o device.o slave.o datagram.o \
|
||||
domain.o mailbox.o ethernet.o debug.o fsm.o
|
||||
|
||||
REV := $(shell svnversion $(src) 2>/dev/null || echo "unknown")
|
||||
|
||||
|
|
|
|||
726
master/canopen.c
726
master/canopen.c
|
|
@ -1,726 +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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
Canopen-over-EtherCAT functions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "master.h"
|
||||
#include "mailbox.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_canopen_abort_msg(uint32_t);
|
||||
int ec_slave_fetch_sdo_descriptions(ec_slave_t *, ec_datagram_t *);
|
||||
int ec_slave_fetch_sdo_entries(ec_slave_t *, ec_datagram_t *,
|
||||
ec_sdo_t *, uint8_t);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reads 32 bit of a CANopen SDO in expedited mode.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_slave_sdo_read_exp(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint8_t *target /**< 4-byte memory */
|
||||
)
|
||||
{
|
||||
ec_datagram_t datagram;
|
||||
size_t rec_size;
|
||||
uint8_t *data;
|
||||
|
||||
ec_datagram_init(&datagram);
|
||||
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, &datagram, 0x03, 6)))
|
||||
goto err;
|
||||
|
||||
EC_WRITE_U16(data, 0x2 << 12); // SDO request
|
||||
EC_WRITE_U8 (data + 2, (0x1 << 1 // expedited transfer
|
||||
| 0x2 << 5)); // initiate upload request
|
||||
EC_WRITE_U16(data + 3, sdo_index);
|
||||
EC_WRITE_U8 (data + 5, sdo_subindex);
|
||||
|
||||
if (!(data = ec_slave_mbox_simple_io(slave, &datagram, &rec_size)))
|
||||
goto err;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
|
||||
EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
|
||||
EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n",
|
||||
sdo_index, sdo_subindex, slave->ring_position);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response
|
||||
EC_READ_U8 (data + 2) >> 5 != 0x2 || // upload response
|
||||
EC_READ_U16(data + 3) != sdo_index || // index
|
||||
EC_READ_U8 (data + 5) != sdo_subindex) { // subindex
|
||||
EC_ERR("SDO upload 0x%04X:%X failed:\n", sdo_index, sdo_subindex);
|
||||
EC_ERR("Invalid SDO upload response at slave %i!\n",
|
||||
slave->ring_position);
|
||||
ec_print_data(data, rec_size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(target, data + 6, 4);
|
||||
|
||||
ec_datagram_clear(&datagram);
|
||||
return 0;
|
||||
err:
|
||||
ec_datagram_clear(&datagram);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Writes a CANopen SDO using expedited mode.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_slave_sdo_write_exp(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
const uint8_t *sdo_data, /**< new value */
|
||||
size_t size /**< Data size in bytes (1 - 4) */
|
||||
)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t rec_size;
|
||||
ec_datagram_t datagram;
|
||||
|
||||
ec_datagram_init(&datagram);
|
||||
|
||||
if (size == 0 || size > 4) {
|
||||
EC_ERR("Invalid data size!\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, &datagram, 0x03, 0x0A)))
|
||||
goto err;
|
||||
|
||||
EC_WRITE_U16(data, 0x2 << 12); // SDO request
|
||||
EC_WRITE_U8 (data + 2, (0x1 // size specified
|
||||
| 0x1 << 1 // expedited transfer
|
||||
| (4 - size) << 2 // data set size
|
||||
| 0x1 << 5)); // initiate download request
|
||||
EC_WRITE_U16(data + 3, sdo_index);
|
||||
EC_WRITE_U8 (data + 5, sdo_subindex);
|
||||
memcpy(data + 6, sdo_data, size);
|
||||
if (size < 4) memset(data + 6 + size, 0x00, 4 - size);
|
||||
|
||||
if (!(data = ec_slave_mbox_simple_io(slave, &datagram, &rec_size)))
|
||||
goto err;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
|
||||
EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
|
||||
EC_ERR("SDO download 0x%04X:%X (%i bytes) aborted on slave %i.\n",
|
||||
sdo_index, sdo_subindex, size, slave->ring_position);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response
|
||||
EC_READ_U8 (data + 2) >> 5 != 0x3 || // download response
|
||||
EC_READ_U16(data + 3) != sdo_index || // index
|
||||
EC_READ_U8 (data + 5) != sdo_subindex) { // subindex
|
||||
EC_ERR("SDO download 0x%04X:%X (%i bytes) failed:\n",
|
||||
sdo_index, sdo_subindex, size);
|
||||
EC_ERR("Invalid SDO download response at slave %i!\n",
|
||||
slave->ring_position);
|
||||
ec_print_data(data, rec_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_datagram_clear(&datagram);
|
||||
return 0;
|
||||
err:
|
||||
ec_datagram_clear(&datagram);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reads a CANopen SDO in normal mode.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
\todo Make size non-pointer.
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_read(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint8_t *target, /**< memory for value */
|
||||
size_t *size /**< target memory size */
|
||||
)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t rec_size, data_size;
|
||||
uint32_t complete_size;
|
||||
ec_datagram_t datagram;
|
||||
|
||||
ec_datagram_init(&datagram);
|
||||
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, &datagram, 0x03, 6)))
|
||||
goto err;
|
||||
|
||||
EC_WRITE_U16(data, 0x2 << 12); // SDO request
|
||||
EC_WRITE_U8 (data + 2, 0x2 << 5); // initiate upload request
|
||||
EC_WRITE_U16(data + 3, sdo_index);
|
||||
EC_WRITE_U8 (data + 5, sdo_subindex);
|
||||
|
||||
if (!(data = ec_slave_mbox_simple_io(slave, &datagram, &rec_size)))
|
||||
goto err;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request
|
||||
EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request
|
||||
EC_ERR("SDO upload 0x%04X:%X aborted on slave %i.\n",
|
||||
sdo_index, sdo_subindex, slave->ring_position);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x3 || // SDO response
|
||||
EC_READ_U8 (data + 2) >> 5 != 0x2 || // initiate upload response
|
||||
EC_READ_U16(data + 3) != sdo_index || // index
|
||||
EC_READ_U8 (data + 5) != sdo_subindex) { // subindex
|
||||
EC_ERR("SDO upload 0x%04X:%X failed:\n", sdo_index, sdo_subindex);
|
||||
EC_ERR("Invalid SDO upload response at slave %i!\n",
|
||||
slave->ring_position);
|
||||
ec_print_data(data, rec_size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (rec_size < 10) {
|
||||
EC_ERR("Received currupted SDO upload response!\n");
|
||||
ec_print_data(data, rec_size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((complete_size = EC_READ_U32(data + 6)) > *size) {
|
||||
EC_ERR("SDO data does not fit into buffer (%i / %i)!\n",
|
||||
complete_size, *size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
data_size = rec_size - 10;
|
||||
|
||||
if (data_size != complete_size) {
|
||||
EC_ERR("SDO data incomplete - Fragmenting not implemented.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(target, data + 10, data_size);
|
||||
|
||||
ec_datagram_clear(&datagram);
|
||||
return 0;
|
||||
err:
|
||||
ec_datagram_clear(&datagram);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Fetches the SDO dictionary of a slave.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_slave_fetch_sdo_list(ec_slave_t *slave /**< EtherCAT slave */)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t rec_size;
|
||||
unsigned int i, sdo_count;
|
||||
ec_sdo_t *sdo;
|
||||
uint16_t sdo_index;
|
||||
ec_datagram_t datagram;
|
||||
|
||||
ec_datagram_init(&datagram);
|
||||
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, &datagram, 0x03, 8)))
|
||||
goto err;
|
||||
|
||||
EC_WRITE_U16(data, 0x8 << 12); // SDO information
|
||||
EC_WRITE_U8 (data + 2, 0x01); // Get OD List Request
|
||||
EC_WRITE_U8 (data + 3, 0x00);
|
||||
EC_WRITE_U16(data + 4, 0x0000);
|
||||
EC_WRITE_U16(data + 6, 0x0001); // deliver all SDOs!
|
||||
|
||||
if (unlikely(ec_master_simple_io(slave->master, &datagram))) {
|
||||
EC_ERR("Mailbox checking failed on slave %i!\n", slave->ring_position);
|
||||
goto err;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(data = ec_slave_mbox_simple_receive(slave, &datagram,
|
||||
0x03, &rec_size)))
|
||||
goto err;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
|
||||
(EC_READ_U8(data + 2) & 0x7F) == 0x07) { // error response
|
||||
EC_ERR("SDO information error response at slave %i!\n",
|
||||
slave->ring_position);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x8 || // SDO information
|
||||
(EC_READ_U8 (data + 2) & 0x7F) != 0x02) { // Get OD List response
|
||||
EC_ERR("Invalid SDO list response at slave %i!\n",
|
||||
slave->ring_position);
|
||||
ec_print_data(data, rec_size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (rec_size < 8) {
|
||||
EC_ERR("Invalid data size!\n");
|
||||
ec_print_data(data, rec_size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
sdo_count = (rec_size - 8) / 2;
|
||||
for (i = 0; i < sdo_count; i++) {
|
||||
sdo_index = EC_READ_U16(data + 8 + i * 2);
|
||||
if (!sdo_index) continue; // sometimes index is 0... ???
|
||||
|
||||
if (!(sdo = (ec_sdo_t *) kmalloc(sizeof(ec_sdo_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate memory for SDO!\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Initialize SDO object
|
||||
sdo->index = sdo_index;
|
||||
//sdo->unkown = 0x0000;
|
||||
sdo->object_code = 0x00;
|
||||
sdo->name = NULL;
|
||||
INIT_LIST_HEAD(&sdo->entries);
|
||||
|
||||
list_add_tail(&sdo->list, &slave->sdo_dictionary);
|
||||
}
|
||||
}
|
||||
while (EC_READ_U8(data + 2) & 0x80);
|
||||
|
||||
// Fetch all SDO descriptions
|
||||
if (ec_slave_fetch_sdo_descriptions(slave, &datagram)) goto err;
|
||||
|
||||
ec_datagram_clear(&datagram);
|
||||
return 0;
|
||||
err:
|
||||
ec_datagram_clear(&datagram);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Fetches the SDO descriptions for the known SDOs.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_slave_fetch_sdo_descriptions(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t rec_size, name_size;
|
||||
ec_sdo_t *sdo;
|
||||
|
||||
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 8)))
|
||||
return -1;
|
||||
EC_WRITE_U16(data, 0x8 << 12); // SDO information
|
||||
EC_WRITE_U8 (data + 2, 0x03); // Get object description request
|
||||
EC_WRITE_U8 (data + 3, 0x00);
|
||||
EC_WRITE_U16(data + 4, 0x0000);
|
||||
EC_WRITE_U16(data + 6, sdo->index); // SDO index
|
||||
|
||||
if (!(data = ec_slave_mbox_simple_io(slave, datagram, &rec_size)))
|
||||
return -1;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
|
||||
(EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response
|
||||
EC_ERR("SDO information error response at slave %i while"
|
||||
" fetching SDO 0x%04X!\n", slave->ring_position,
|
||||
sdo->index);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x8 || // SDO information
|
||||
(EC_READ_U8 (data + 2) & 0x7F) != 0x04 || // Object desc. response
|
||||
EC_READ_U16(data + 6) != sdo->index) { // SDO index
|
||||
EC_ERR("Invalid object description response at slave %i while"
|
||||
" fetching SDO 0x%04X!\n", slave->ring_position,
|
||||
sdo->index);
|
||||
ec_print_data(data, rec_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rec_size < 12) {
|
||||
EC_ERR("Invalid data size!\n");
|
||||
ec_print_data(data, rec_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
EC_DBG("object desc response:\n");
|
||||
ec_print_data(data, rec_size);
|
||||
#endif
|
||||
|
||||
//sdo->unknown = EC_READ_U16(data + 8);
|
||||
sdo->object_code = EC_READ_U8(data + 11);
|
||||
|
||||
name_size = rec_size - 12;
|
||||
if (name_size) {
|
||||
if (!(sdo->name = kmalloc(name_size + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate SDO name!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(sdo->name, data + 12, name_size);
|
||||
sdo->name[name_size] = 0;
|
||||
}
|
||||
|
||||
if (EC_READ_U8(data + 2) & 0x80) {
|
||||
EC_ERR("Fragment follows (not implemented)!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fetch all entries (subindices)
|
||||
if (ec_slave_fetch_sdo_entries(slave, datagram, sdo,
|
||||
EC_READ_U8(data + 10)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Fetches all entries (subindices) to an SDO.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_slave_fetch_sdo_entries(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
ec_datagram_t *datagram, /**< datagram */
|
||||
ec_sdo_t *sdo, /**< SDO */
|
||||
uint8_t subindices /**< number of subindices */
|
||||
)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t rec_size, data_size;
|
||||
uint8_t i;
|
||||
ec_sdo_entry_t *entry;
|
||||
|
||||
for (i = 1; i <= subindices; i++) {
|
||||
if (!(data = ec_slave_mbox_prepare_send(slave, datagram, 0x03, 10)))
|
||||
return -1;
|
||||
|
||||
EC_WRITE_U16(data, 0x8 << 12); // SDO information
|
||||
EC_WRITE_U8 (data + 2, 0x05); // Get entry description request
|
||||
EC_WRITE_U8 (data + 3, 0x00);
|
||||
EC_WRITE_U16(data + 4, 0x0000);
|
||||
EC_WRITE_U16(data + 6, sdo->index); // SDO index
|
||||
EC_WRITE_U8 (data + 8, i); // SDO subindex
|
||||
EC_WRITE_U8 (data + 9, 0x00); // value info (no values)
|
||||
|
||||
if (!(data = ec_slave_mbox_simple_io(slave, datagram, &rec_size)))
|
||||
return -1;
|
||||
|
||||
if (EC_READ_U16(data) >> 12 == 0x8 && // SDO information
|
||||
(EC_READ_U8 (data + 2) & 0x7F) == 0x07) { // error response
|
||||
EC_ERR("SDO information error response at slave %i while"
|
||||
" fetching SDO entry 0x%04X:%i!\n", slave->ring_position,
|
||||
sdo->index, i);
|
||||
ec_canopen_abort_msg(EC_READ_U32(data + 6));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EC_READ_U16(data) >> 12 != 0x8 || // SDO information
|
||||
(EC_READ_U8(data + 2) & 0x7F) != 0x06 || // Entry desc. response
|
||||
EC_READ_U16(data + 6) != sdo->index || // SDO index
|
||||
EC_READ_U8(data + 8) != i) { // SDO subindex
|
||||
EC_ERR("Invalid entry description response at slave %i while"
|
||||
" fetching SDO entry 0x%04X:%i!\n", slave->ring_position,
|
||||
sdo->index, i);
|
||||
ec_print_data(data, rec_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rec_size < 16) {
|
||||
EC_ERR("Invalid data size!\n");
|
||||
ec_print_data(data, rec_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EC_READ_U16(data + 12)) // bit length = 0
|
||||
continue;
|
||||
|
||||
data_size = rec_size - 16;
|
||||
|
||||
if (!(entry = (ec_sdo_entry_t *)
|
||||
kmalloc(sizeof(ec_sdo_entry_t) + data_size + 1, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate entry!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->subindex = i;
|
||||
entry->data_type = EC_READ_U16(data + 10);
|
||||
entry->bit_length = EC_READ_U16(data + 12);
|
||||
|
||||
// memory for name string appended to entry
|
||||
entry->name = (uint8_t *) entry + sizeof(ec_sdo_entry_t);
|
||||
|
||||
memcpy(entry->name, data + 16, data_size);
|
||||
entry->name[data_size] = 0;
|
||||
|
||||
list_add_tail(&entry->list, &sdo->entries);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
SDO abort messages.
|
||||
The "abort SDO transfer request" supplies an abort code,
|
||||
which can be translated to clear text. This table does
|
||||
the mapping of the codes and messages.
|
||||
*/
|
||||
|
||||
const ec_code_msg_t sdo_abort_messages[] = {
|
||||
{0x05030000, "Toggle bit not changed"},
|
||||
{0x05040000, "SDO protocol timeout"},
|
||||
{0x05040001, "Client/Server command specifier not valid or unknown"},
|
||||
{0x05040005, "Out of memory"},
|
||||
{0x06010000, "Unsupported access to an object"},
|
||||
{0x06010001, "Attempt to read a write-only object"},
|
||||
{0x06010002, "Attempt to write a read-only object"},
|
||||
{0x06020000, "This object does not exist in the object directory"},
|
||||
{0x06040041, "The object cannot be mapped into the PDO"},
|
||||
{0x06040042, "The number and length of the objects to be mapped would"
|
||||
" exceed the PDO length"},
|
||||
{0x06040043, "General parameter incompatibility reason"},
|
||||
{0x06040047, "Gerneral internal incompatibility in device"},
|
||||
{0x06060000, "Access failure due to a hardware error"},
|
||||
{0x06070010, "Data type does not match, length of service parameter does"
|
||||
" not match"},
|
||||
{0x06070012, "Data type does not match, length of service parameter too"
|
||||
" high"},
|
||||
{0x06070013, "Data type does not match, length of service parameter too"
|
||||
" low"},
|
||||
{0x06090011, "Subindex does not exist"},
|
||||
{0x06090030, "Value range of parameter exceeded"},
|
||||
{0x06090031, "Value of parameter written too high"},
|
||||
{0x06090032, "Value of parameter written too low"},
|
||||
{0x06090036, "Maximum value is less than minimum value"},
|
||||
{0x08000000, "General error"},
|
||||
{0x08000020, "Data cannot be transferred or stored to the application"},
|
||||
{0x08000021, "Data cannot be transferred or stored to the application"
|
||||
" because of local control"},
|
||||
{0x08000022, "Data cannot be transferred or stored to the application"
|
||||
" because of the present device state"},
|
||||
{0x08000023, "Object dictionary dynamic generation fails or no object"
|
||||
" dictionary is present"},
|
||||
{}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Outputs an SDO abort message.
|
||||
*/
|
||||
|
||||
void ec_canopen_abort_msg(uint32_t abort_code)
|
||||
{
|
||||
const ec_code_msg_t *abort_msg;
|
||||
|
||||
for (abort_msg = sdo_abort_messages; abort_msg->code; abort_msg++) {
|
||||
if (abort_msg->code == abort_code) {
|
||||
EC_ERR("SDO abort message 0x%08X: \"%s\".\n",
|
||||
abort_msg->code, abort_msg->message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EC_ERR("Unknown SDO abort code 0x%08X.\n", abort_code);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Realtime interface
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reads an 8-bit SDO in expedited mode.
|
||||
See ec_slave_sdo_read_exp()
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_read_exp8(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint8_t *target /**< memory for read value */
|
||||
)
|
||||
{
|
||||
uint8_t data[4];
|
||||
if (ec_slave_sdo_read_exp(slave, sdo_index, sdo_subindex, data)) return -1;
|
||||
*target = EC_READ_U8(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reads a 16-bit SDO in expedited mode.
|
||||
See ec_slave_sdo_read_exp()
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_read_exp16(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint16_t *target /**< memory for read value */
|
||||
)
|
||||
{
|
||||
uint8_t data[4];
|
||||
if (ec_slave_sdo_read_exp(slave, sdo_index, sdo_subindex, data)) return -1;
|
||||
*target = EC_READ_U16(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Reads a 32-bit SDO in expedited mode.
|
||||
See ec_slave_sdo_read_exp()
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_read_exp32(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint32_t *target /**< memory for read value */
|
||||
)
|
||||
{
|
||||
uint8_t data[4];
|
||||
if (ec_slave_sdo_read_exp(slave, sdo_index, sdo_subindex, data)) return -1;
|
||||
*target = EC_READ_U32(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Writes an 8-bit SDO in expedited mode.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_write_exp8(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint8_t value /**< new value */
|
||||
)
|
||||
{
|
||||
return ec_slave_sdo_write_exp(slave, sdo_index, sdo_subindex, &value, 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Writes a 16-bit SDO in expedited mode.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_write_exp16(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint16_t value /**< new value */
|
||||
)
|
||||
{
|
||||
uint8_t data[2];
|
||||
EC_WRITE_U16(data, value);
|
||||
return ec_slave_sdo_write_exp(slave, sdo_index, sdo_subindex, data, 2);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Writes a 32-bit SDO in expedited mode.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_slave_sdo_write_exp32(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t sdo_index, /**< SDO index */
|
||||
uint8_t sdo_subindex, /**< SDO subindex */
|
||||
uint32_t value /**< new value */
|
||||
)
|
||||
{
|
||||
uint8_t data[4];
|
||||
EC_WRITE_U32(data, value);
|
||||
return ec_slave_sdo_write_exp(slave, sdo_index, sdo_subindex, data, 4);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_read_exp8);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_read_exp16);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_read_exp32);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_write_exp8);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_write_exp16);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_write_exp32);
|
||||
EXPORT_SYMBOL(ecrt_slave_sdo_read);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
return -1; \
|
||||
datagram->index = 0; \
|
||||
datagram->working_counter = 0; \
|
||||
datagram->state = EC_CMD_INIT;
|
||||
datagram->state = EC_DATAGRAM_INIT;
|
||||
|
||||
#define EC_FUNC_FOOTER \
|
||||
datagram->data_size = data_size; \
|
||||
|
|
@ -69,14 +69,14 @@
|
|||
|
||||
void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
|
||||
{
|
||||
datagram->type = EC_CMD_NONE;
|
||||
datagram->type = EC_DATAGRAM_NONE;
|
||||
datagram->address.logical = 0x00000000;
|
||||
datagram->data = NULL;
|
||||
datagram->mem_size = 0;
|
||||
datagram->data_size = 0;
|
||||
datagram->index = 0x00;
|
||||
datagram->working_counter = 0x00;
|
||||
datagram->state = EC_CMD_INIT;
|
||||
datagram->state = EC_DATAGRAM_INIT;
|
||||
datagram->t_sent = 0;
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ int ec_datagram_nprd(ec_datagram_t *datagram,
|
|||
EC_WARN("Using node address 0x0000!\n");
|
||||
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_NPRD;
|
||||
datagram->type = EC_DATAGRAM_NPRD;
|
||||
datagram->address.physical.slave = node_address;
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -170,7 +170,7 @@ int ec_datagram_npwr(ec_datagram_t *datagram,
|
|||
EC_WARN("Using node address 0x0000!\n");
|
||||
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_NPWR;
|
||||
datagram->type = EC_DATAGRAM_NPWR;
|
||||
datagram->address.physical.slave = node_address;
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -195,7 +195,7 @@ int ec_datagram_aprd(ec_datagram_t *datagram,
|
|||
)
|
||||
{
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_APRD;
|
||||
datagram->type = EC_DATAGRAM_APRD;
|
||||
datagram->address.physical.slave = (int16_t) ring_position * (-1);
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -220,7 +220,7 @@ int ec_datagram_apwr(ec_datagram_t *datagram,
|
|||
)
|
||||
{
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_APWR;
|
||||
datagram->type = EC_DATAGRAM_APWR;
|
||||
datagram->address.physical.slave = (int16_t) ring_position * (-1);
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -243,7 +243,7 @@ int ec_datagram_brd(ec_datagram_t *datagram,
|
|||
)
|
||||
{
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_BRD;
|
||||
datagram->type = EC_DATAGRAM_BRD;
|
||||
datagram->address.physical.slave = 0x0000;
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -266,7 +266,7 @@ int ec_datagram_bwr(ec_datagram_t *datagram,
|
|||
)
|
||||
{
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_BWR;
|
||||
datagram->type = EC_DATAGRAM_BWR;
|
||||
datagram->address.physical.slave = 0x0000;
|
||||
datagram->address.physical.mem = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
|
|
@ -289,7 +289,7 @@ int ec_datagram_lrw(ec_datagram_t *datagram,
|
|||
)
|
||||
{
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_CMD_LRW;
|
||||
datagram->type = EC_DATAGRAM_LRW;
|
||||
datagram->address.logical = offset;
|
||||
EC_FUNC_FOOTER;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,14 +55,14 @@
|
|||
|
||||
typedef enum
|
||||
{
|
||||
EC_CMD_NONE = 0x00, /**< Dummy */
|
||||
EC_CMD_APRD = 0x01, /**< Auto-increment physical read */
|
||||
EC_CMD_APWR = 0x02, /**< Auto-increment physical write */
|
||||
EC_CMD_NPRD = 0x04, /**< Node-addressed physical read */
|
||||
EC_CMD_NPWR = 0x05, /**< Node-addressed physical write */
|
||||
EC_CMD_BRD = 0x07, /**< Broadcast read */
|
||||
EC_CMD_BWR = 0x08, /**< Broadcast write */
|
||||
EC_CMD_LRW = 0x0C /**< Logical read/write */
|
||||
EC_DATAGRAM_NONE = 0x00, /**< Dummy */
|
||||
EC_DATAGRAM_APRD = 0x01, /**< Auto-increment physical read */
|
||||
EC_DATAGRAM_APWR = 0x02, /**< Auto-increment physical write */
|
||||
EC_DATAGRAM_NPRD = 0x04, /**< Node-addressed physical read */
|
||||
EC_DATAGRAM_NPWR = 0x05, /**< Node-addressed physical write */
|
||||
EC_DATAGRAM_BRD = 0x07, /**< Broadcast read */
|
||||
EC_DATAGRAM_BWR = 0x08, /**< Broadcast write */
|
||||
EC_DATAGRAM_LRW = 0x0C /**< Logical read/write */
|
||||
}
|
||||
ec_datagram_type_t;
|
||||
|
||||
|
|
@ -72,12 +72,12 @@ ec_datagram_type_t;
|
|||
|
||||
typedef enum
|
||||
{
|
||||
EC_CMD_INIT, /**< new datagram */
|
||||
EC_CMD_QUEUED, /**< datagram queued by master */
|
||||
EC_CMD_SENT, /**< datagram has been sent */
|
||||
EC_CMD_RECEIVED, /**< datagram has been received */
|
||||
EC_CMD_TIMEOUT, /**< datagram timed out */
|
||||
EC_CMD_ERROR /**< error while sending/receiving */
|
||||
EC_DATAGRAM_INIT, /**< new datagram */
|
||||
EC_DATAGRAM_QUEUED, /**< datagram queued by master */
|
||||
EC_DATAGRAM_SENT, /**< datagram has been sent */
|
||||
EC_DATAGRAM_RECEIVED, /**< datagram has been received */
|
||||
EC_DATAGRAM_TIMED_OUT, /**< datagram timed out */
|
||||
EC_DATAGRAM_ERROR /**< error while sending/receiving */
|
||||
}
|
||||
ec_datagram_state_t;
|
||||
|
||||
|
|
|
|||
354
master/domain.c
354
master/domain.c
|
|
@ -46,7 +46,23 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_domain_clear_field_regs(ec_domain_t *);
|
||||
/**
|
||||
Data registration type.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
ec_slave_t *slave; /**< slave */
|
||||
const ec_sii_sync_t *sync; /**< sync manager */
|
||||
off_t sync_offset; /**< pdo offset */
|
||||
void **data_ptr; /**< pointer to process data pointer(s) */
|
||||
}
|
||||
ec_data_reg_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_domain_clear_data_regs(ec_domain_t *);
|
||||
ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -91,7 +107,7 @@ int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
domain->base_address = 0;
|
||||
domain->response_count = 0xFFFFFFFF;
|
||||
|
||||
INIT_LIST_HEAD(&domain->field_regs);
|
||||
INIT_LIST_HEAD(&domain->data_regs);
|
||||
INIT_LIST_HEAD(&domain->datagrams);
|
||||
|
||||
// init kobject and add it to the hierarchy
|
||||
|
|
@ -127,7 +143,7 @@ void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
|
|||
kfree(datagram);
|
||||
}
|
||||
|
||||
ec_domain_clear_field_regs(domain);
|
||||
ec_domain_clear_data_regs(domain);
|
||||
|
||||
kfree(domain);
|
||||
}
|
||||
|
|
@ -139,34 +155,70 @@ void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
|
|||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_domain_reg_field(ec_domain_t *domain, /**< EtherCAT domain */
|
||||
ec_slave_t *slave, /**< slave */
|
||||
const ec_sync_t *sync, /**< sync manager */
|
||||
uint32_t field_offset, /**< data field offset */
|
||||
void **data_ptr /**< pointer to the process data
|
||||
pointer */
|
||||
)
|
||||
int ec_domain_reg_pdo_entry(ec_domain_t *domain, /**< EtherCAT domain */
|
||||
ec_slave_t *slave, /**< slave */
|
||||
const ec_sii_pdo_t *pdo,
|
||||
const ec_sii_pdo_entry_t *entry,
|
||||
/**< PDO registration entry */
|
||||
void **data_ptr /**< pointer to the process data
|
||||
pointer */
|
||||
)
|
||||
{
|
||||
ec_field_reg_t *field_reg;
|
||||
ec_data_reg_t *data_reg;
|
||||
const ec_sii_sync_t *sync;
|
||||
const ec_sii_pdo_t *other_pdo;
|
||||
const ec_sii_pdo_entry_t *other_entry;
|
||||
unsigned int bit_offset, byte_offset, sync_found;
|
||||
|
||||
if (!(field_reg =
|
||||
(ec_field_reg_t *) kmalloc(sizeof(ec_field_reg_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate field registration.\n");
|
||||
// Find sync manager for PDO
|
||||
sync_found = 0;
|
||||
list_for_each_entry(sync, &slave->sii_syncs, list) {
|
||||
if (sync->index == pdo->sync_index) {
|
||||
sync_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sync_found) {
|
||||
EC_ERR("No sync manager for PDO 0x%04X:%i.",
|
||||
pdo->index, entry->subindex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calculate offset for process data pointer
|
||||
bit_offset = 0;
|
||||
byte_offset = 0;
|
||||
list_for_each_entry(other_pdo, &slave->sii_pdos, list) {
|
||||
if (other_pdo->sync_index != sync->index) continue;
|
||||
|
||||
list_for_each_entry(other_entry, &pdo->entries, list) {
|
||||
if (other_entry == entry) {
|
||||
byte_offset = bit_offset / 8;
|
||||
break;
|
||||
}
|
||||
bit_offset += other_entry->bit_length;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for data registration object
|
||||
if (!(data_reg =
|
||||
(ec_data_reg_t *) kmalloc(sizeof(ec_data_reg_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate data registration.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ec_slave_prepare_fmmu(slave, domain, sync)) {
|
||||
EC_ERR("FMMU configuration failed.\n");
|
||||
kfree(field_reg);
|
||||
kfree(data_reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
field_reg->slave = slave;
|
||||
field_reg->sync = sync;
|
||||
field_reg->field_offset = field_offset;
|
||||
field_reg->data_ptr = data_ptr;
|
||||
data_reg->slave = slave;
|
||||
data_reg->sync = sync;
|
||||
data_reg->sync_offset = byte_offset;
|
||||
data_reg->data_ptr = data_ptr;
|
||||
|
||||
list_add_tail(&field_reg->list, &domain->field_regs);
|
||||
list_add_tail(&data_reg->list, &domain->data_regs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -176,13 +228,13 @@ int ec_domain_reg_field(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
Clears the list of the registered data fields.
|
||||
*/
|
||||
|
||||
void ec_domain_clear_field_regs(ec_domain_t *domain /**< EtherCAT domain */)
|
||||
void ec_domain_clear_data_regs(ec_domain_t *domain /**< EtherCAT domain */)
|
||||
{
|
||||
ec_field_reg_t *field_reg, *next;
|
||||
ec_data_reg_t *data_reg, *next;
|
||||
|
||||
list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
|
||||
list_del(&field_reg->list);
|
||||
kfree(field_reg);
|
||||
list_for_each_entry_safe(data_reg, next, &domain->data_regs, list) {
|
||||
list_del(&data_reg->list);
|
||||
kfree(data_reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +274,7 @@ int ec_domain_add_datagram(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
Creates a domain.
|
||||
Reserves domain memory, calculates the logical addresses of the
|
||||
corresponding FMMUs and sets the process data pointer of the registered
|
||||
data fields.
|
||||
process data.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
|
|
@ -230,22 +282,22 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
uint32_t base_address /**< logical base address */
|
||||
)
|
||||
{
|
||||
ec_field_reg_t *field_reg;
|
||||
ec_data_reg_t *data_reg;
|
||||
ec_slave_t *slave;
|
||||
ec_fmmu_t *fmmu;
|
||||
unsigned int i, j, cmd_count;
|
||||
uint32_t field_off, field_off_cmd;
|
||||
uint32_t cmd_offset;
|
||||
size_t cmd_data_size, sync_size;
|
||||
unsigned int i, j, datagram_count;
|
||||
uint32_t pdo_off, pdo_off_datagram;
|
||||
uint32_t datagram_offset;
|
||||
size_t datagram_data_size, sync_size;
|
||||
ec_datagram_t *datagram;
|
||||
|
||||
domain->base_address = base_address;
|
||||
|
||||
// calculate size of process data and allocate memory
|
||||
domain->data_size = 0;
|
||||
cmd_offset = base_address;
|
||||
cmd_data_size = 0;
|
||||
cmd_count = 0;
|
||||
datagram_offset = base_address;
|
||||
datagram_data_size = 0;
|
||||
datagram_count = 0;
|
||||
list_for_each_entry(slave, &domain->master->slaves, list) {
|
||||
for (j = 0; j < slave->fmmu_count; j++) {
|
||||
fmmu = &slave->fmmus[j];
|
||||
|
|
@ -253,47 +305,48 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
fmmu->logical_start_address = base_address + domain->data_size;
|
||||
sync_size = ec_slave_calc_sync_size(slave, fmmu->sync);
|
||||
domain->data_size += sync_size;
|
||||
if (cmd_data_size + sync_size > EC_MAX_DATA_SIZE) {
|
||||
if (ec_domain_add_datagram(domain, cmd_offset,
|
||||
cmd_data_size)) return -1;
|
||||
cmd_offset += cmd_data_size;
|
||||
cmd_data_size = 0;
|
||||
cmd_count++;
|
||||
if (datagram_data_size + sync_size > EC_MAX_DATA_SIZE) {
|
||||
if (ec_domain_add_datagram(domain, datagram_offset,
|
||||
datagram_data_size)) return -1;
|
||||
datagram_offset += datagram_data_size;
|
||||
datagram_data_size = 0;
|
||||
datagram_count++;
|
||||
}
|
||||
cmd_data_size += sync_size;
|
||||
datagram_data_size += sync_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate last datagram
|
||||
if (cmd_data_size) {
|
||||
if (ec_domain_add_datagram(domain, cmd_offset, cmd_data_size))
|
||||
if (datagram_data_size) {
|
||||
if (ec_domain_add_datagram(domain, datagram_offset,
|
||||
datagram_data_size))
|
||||
return -1;
|
||||
cmd_count++;
|
||||
datagram_count++;
|
||||
}
|
||||
|
||||
if (!cmd_count) {
|
||||
if (!datagram_count) {
|
||||
EC_WARN("Domain %i contains no data!\n", domain->index);
|
||||
ec_domain_clear_field_regs(domain);
|
||||
ec_domain_clear_data_regs(domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set all process data pointers
|
||||
list_for_each_entry(field_reg, &domain->field_regs, list) {
|
||||
for (i = 0; i < field_reg->slave->fmmu_count; i++) {
|
||||
fmmu = &field_reg->slave->fmmus[i];
|
||||
if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
|
||||
field_off = fmmu->logical_start_address +
|
||||
field_reg->field_offset;
|
||||
list_for_each_entry(data_reg, &domain->data_regs, list) {
|
||||
for (i = 0; i < data_reg->slave->fmmu_count; i++) {
|
||||
fmmu = &data_reg->slave->fmmus[i];
|
||||
if (fmmu->domain == domain && fmmu->sync == data_reg->sync) {
|
||||
pdo_off = fmmu->logical_start_address + data_reg->sync_offset;
|
||||
// search datagram
|
||||
list_for_each_entry(datagram, &domain->datagrams, list) {
|
||||
field_off_cmd = field_off - datagram->address.logical;
|
||||
if (field_off >= datagram->address.logical &&
|
||||
field_off_cmd < datagram->mem_size) {
|
||||
*field_reg->data_ptr = datagram->data + field_off_cmd;
|
||||
pdo_off_datagram = pdo_off - datagram->address.logical;
|
||||
if (pdo_off >= datagram->address.logical &&
|
||||
pdo_off_datagram < datagram->mem_size) {
|
||||
*data_reg->data_ptr = datagram->data +
|
||||
pdo_off_datagram;
|
||||
}
|
||||
}
|
||||
if (!field_reg->data_ptr) {
|
||||
if (!data_reg->data_ptr) {
|
||||
EC_ERR("Failed to assign data pointer!\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -303,10 +356,10 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
}
|
||||
|
||||
EC_INFO("Domain %i - Allocated %i bytes in %i datagram%s\n",
|
||||
domain->index, domain->data_size, cmd_count,
|
||||
cmd_count == 1 ? "" : "s");
|
||||
domain->index, domain->data_size, datagram_count,
|
||||
datagram_count == 1 ? "" : "s");
|
||||
|
||||
ec_domain_clear_field_regs(domain);
|
||||
ec_domain_clear_data_regs(domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -314,20 +367,15 @@ int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sets the number of responding slaves and outputs it on demand.
|
||||
This number isn't really the number of responding slaves, but the sum of
|
||||
the working counters of all domain datagrams. Some slaves increase the
|
||||
working counter by 2, some by 1.
|
||||
Places all process data datagrams in the masters datagram queue.
|
||||
*/
|
||||
|
||||
void ec_domain_response_count(ec_domain_t *domain, /**< EtherCAT domain */
|
||||
unsigned int count /**< new WC sum */
|
||||
)
|
||||
void ec_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
|
||||
{
|
||||
if (count != domain->response_count) {
|
||||
domain->response_count = count;
|
||||
EC_INFO("Domain %i working counter change: %i\n", domain->index,
|
||||
count);
|
||||
ec_datagram_t *datagram;
|
||||
|
||||
list_for_each_entry(datagram, &domain->datagrams, list) {
|
||||
ec_master_queue_datagram(domain->master, datagram);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,62 +405,45 @@ ssize_t ec_show_domain_attribute(struct kobject *kobj, /**< kobject */
|
|||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
Registers a data field in a domain.
|
||||
- If \a data_ptr is NULL, the slave is only checked against its type.
|
||||
- If \a field_count is 0, it is assumed that one data field is to be
|
||||
registered.
|
||||
- If \a field_count is greater then 1, it is assumed that \a data_ptr
|
||||
is an array of the respective size.
|
||||
Registers a PDO in a domain.
|
||||
- If \a data_ptr is NULL, the slave is only validated.
|
||||
\return pointer to the slave on success, else NULL
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain,
|
||||
/**< EtherCAT domain */
|
||||
const char *address,
|
||||
/**< ASCII address of the slave,
|
||||
see ecrt_master_get_slave() */
|
||||
const char *vendor_name,
|
||||
/**< vendor name */
|
||||
const char *product_name,
|
||||
/**< product name */
|
||||
void **data_ptr,
|
||||
/**< address of the process data
|
||||
pointer */
|
||||
const char *field_name,
|
||||
/**< data field name */
|
||||
unsigned int field_index,
|
||||
/**< offset of data fields with
|
||||
\a field_type */
|
||||
unsigned int field_count
|
||||
/**< number of data fields (with
|
||||
the same type) to register */
|
||||
)
|
||||
ec_slave_t *ecrt_domain_register_pdo(ec_domain_t *domain,
|
||||
/**< EtherCAT domain */
|
||||
const char *address,
|
||||
/**< ASCII address of the slave,
|
||||
see ecrt_master_get_slave() */
|
||||
uint32_t vendor_id,
|
||||
/**< vendor ID */
|
||||
uint32_t product_code,
|
||||
/**< product code */
|
||||
uint16_t pdo_index,
|
||||
/**< PDO index */
|
||||
uint8_t pdo_subindex,
|
||||
/**< PDO subindex */
|
||||
void **data_ptr
|
||||
/**< address of the process data
|
||||
pointer */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
const ec_slave_type_t *type;
|
||||
ec_master_t *master;
|
||||
const ec_sync_t *sync;
|
||||
const ec_field_t *field;
|
||||
unsigned int field_counter, i, j, orig_field_index, orig_field_count;
|
||||
uint32_t field_offset;
|
||||
const ec_sii_pdo_t *pdo;
|
||||
const ec_sii_pdo_entry_t *entry;
|
||||
|
||||
master = domain->master;
|
||||
|
||||
// translate address
|
||||
if (!(slave = ecrt_master_get_slave(master, address))) return NULL;
|
||||
|
||||
if (!(type = slave->type)) {
|
||||
EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
|
||||
slave->ring_position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(vendor_name, type->vendor_name) ||
|
||||
strcmp(product_name, type->product_name)) {
|
||||
EC_ERR("Invalid slave type at position %i - Requested: \"%s %s\","
|
||||
" found: \"%s %s\".\n", slave->ring_position, vendor_name,
|
||||
product_name, type->vendor_name, type->product_name);
|
||||
if (vendor_id != slave->sii_vendor_id ||
|
||||
product_code != slave->sii_product_code) {
|
||||
EC_ERR("Invalid slave type at position %i - Requested: 0x%08X 0x%08X,"
|
||||
" found: 0x%08X 0x%08X\".\n", slave->ring_position, vendor_id,
|
||||
product_code, slave->sii_vendor_id, slave->sii_product_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -421,32 +452,22 @@ ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain,
|
|||
slave->registered = 1;
|
||||
}
|
||||
|
||||
if (!field_count) field_count = 1;
|
||||
orig_field_index = field_index;
|
||||
orig_field_count = field_count;
|
||||
list_for_each_entry(pdo, &slave->sii_pdos, list) {
|
||||
list_for_each_entry(entry, &pdo->entries, list) {
|
||||
if (entry->index != pdo_index
|
||||
|| entry->subindex != pdo_subindex) continue;
|
||||
|
||||
field_counter = 0;
|
||||
for (i = 0; type->sync_managers[i]; i++) {
|
||||
sync = type->sync_managers[i];
|
||||
field_offset = 0;
|
||||
for (j = 0; sync->fields[j]; j++) {
|
||||
field = sync->fields[j];
|
||||
if (!strcmp(field->name, field_name)) {
|
||||
if (field_counter++ == field_index) {
|
||||
if (data_ptr)
|
||||
ec_domain_reg_field(domain, slave, sync, field_offset,
|
||||
data_ptr++);
|
||||
if (!(--field_count)) return slave;
|
||||
field_index++;
|
||||
}
|
||||
if (data_ptr) {
|
||||
ec_domain_reg_pdo_entry(domain, slave, pdo, entry, data_ptr);
|
||||
}
|
||||
field_offset += field->size;
|
||||
|
||||
return slave;
|
||||
}
|
||||
}
|
||||
|
||||
EC_ERR("Slave %i (\"%s %s\") registration mismatch: Field \"%s\","
|
||||
" index %i, count %i.\n", slave->ring_position, vendor_name,
|
||||
product_name, field_name, orig_field_index, orig_field_count);
|
||||
EC_ERR("Slave %i does not provide PDO 0x%04X:%i.\n",
|
||||
slave->ring_position, pdo_index, pdo_subindex);
|
||||
slave->registered = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -459,20 +480,21 @@ ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain,
|
|||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_domain_register_field_list(ec_domain_t *domain,
|
||||
/**< EtherCAT domain */
|
||||
const ec_field_init_t *fields
|
||||
/**< array of data field registrations */
|
||||
)
|
||||
int ecrt_domain_register_pdo_list(ec_domain_t *domain,
|
||||
/**< EtherCAT domain */
|
||||
const ec_pdo_reg_t *pdos
|
||||
/**< array of PDO registrations */
|
||||
)
|
||||
{
|
||||
const ec_field_init_t *field;
|
||||
const ec_pdo_reg_t *pdo;
|
||||
|
||||
for (field = fields; field->slave_address; field++)
|
||||
if (!ecrt_domain_register_field(domain, field->slave_address,
|
||||
field->vendor_name,
|
||||
field->product_name, field->data_ptr,
|
||||
field->field_name, field->field_index,
|
||||
field->field_count))
|
||||
for (pdo = pdos; pdo->slave_address; pdo++)
|
||||
if (!ecrt_domain_register_pdo(domain, pdo->slave_address,
|
||||
pdo->vendor_id,
|
||||
pdo->product_code,
|
||||
pdo->pdo_index,
|
||||
pdo->pdo_subindex,
|
||||
pdo->data_ptr))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -481,23 +503,7 @@ int ecrt_domain_register_field_list(ec_domain_t *domain,
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Places all process data datagrams in the masters datagram queue.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_domain_queue(ec_domain_t *domain /**< EtherCAT domain */)
|
||||
{
|
||||
ec_datagram_t *datagram;
|
||||
|
||||
list_for_each_entry(datagram, &domain->datagrams, list) {
|
||||
ec_master_queue_datagram(domain->master, datagram);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Processes received process data.
|
||||
Processes received process data and requeues the domain datagram(s).
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
|
|
@ -507,14 +513,19 @@ void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */)
|
|||
ec_datagram_t *datagram;
|
||||
|
||||
working_counter_sum = 0;
|
||||
|
||||
list_for_each_entry(datagram, &domain->datagrams, list) {
|
||||
if (datagram->state == EC_CMD_RECEIVED) {
|
||||
if (datagram->state == EC_DATAGRAM_RECEIVED) {
|
||||
working_counter_sum += datagram->working_counter;
|
||||
}
|
||||
}
|
||||
|
||||
ec_domain_response_count(domain, working_counter_sum);
|
||||
if (working_counter_sum != domain->response_count) {
|
||||
domain->response_count = working_counter_sum;
|
||||
EC_INFO("Domain %i working counter change: %i\n", domain->index,
|
||||
domain->response_count);
|
||||
}
|
||||
|
||||
ec_domain_queue(domain);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -525,12 +536,12 @@ void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */)
|
|||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_domain_state(ec_domain_t *domain /**< EtherCAT domain */)
|
||||
int ecrt_domain_state(const ec_domain_t *domain /**< EtherCAT domain */)
|
||||
{
|
||||
ec_datagram_t *datagram;
|
||||
|
||||
list_for_each_entry(datagram, &domain->datagrams, list) {
|
||||
if (datagram->state != EC_CMD_RECEIVED) return -1;
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -540,9 +551,8 @@ int ecrt_domain_state(ec_domain_t *domain /**< EtherCAT domain */)
|
|||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_domain_register_field);
|
||||
EXPORT_SYMBOL(ecrt_domain_register_field_list);
|
||||
EXPORT_SYMBOL(ecrt_domain_queue);
|
||||
EXPORT_SYMBOL(ecrt_domain_register_pdo);
|
||||
EXPORT_SYMBOL(ecrt_domain_register_pdo_list);
|
||||
EXPORT_SYMBOL(ecrt_domain_process);
|
||||
EXPORT_SYMBOL(ecrt_domain_state);
|
||||
|
||||
|
|
|
|||
|
|
@ -45,24 +45,8 @@
|
|||
#include <linux/kobject.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "datagram.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Data field registration type.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
ec_slave_t *slave; /**< slave */
|
||||
const ec_sync_t *sync; /**< sync manager */
|
||||
uint32_t field_offset; /**< data field offset */
|
||||
void **data_ptr; /**< pointer to process data pointer(s) */
|
||||
}
|
||||
ec_field_reg_t;
|
||||
#include "master.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -82,7 +66,7 @@ struct ec_domain
|
|||
struct list_head datagrams; /**< process data datagrams */
|
||||
uint32_t base_address; /**< logical offset address of the process data */
|
||||
unsigned int response_count; /**< number of responding slaves */
|
||||
struct list_head field_regs; /**< data field registrations */
|
||||
struct list_head data_regs; /**< PDO data registrations */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -90,6 +74,7 @@ struct ec_domain
|
|||
int ec_domain_init(ec_domain_t *, ec_master_t *, unsigned int);
|
||||
void ec_domain_clear(struct kobject *);
|
||||
int ec_domain_alloc(ec_domain_t *, uint32_t);
|
||||
void ec_domain_queue(ec_domain_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -155,10 +155,8 @@ int ec_eoe_init(ec_eoe_t *eoe /**< EoE handler */)
|
|||
|
||||
void ec_eoe_clear(ec_eoe_t *eoe /**< EoE handler */)
|
||||
{
|
||||
if (eoe->dev) { // TODO: dev never NULL?
|
||||
unregister_netdev(eoe->dev);
|
||||
free_netdev(eoe->dev);
|
||||
}
|
||||
unregister_netdev(eoe->dev);
|
||||
free_netdev(eoe->dev);
|
||||
|
||||
// empty transmit queue
|
||||
ec_eoe_flush(eoe);
|
||||
|
|
@ -292,22 +290,6 @@ unsigned int ec_eoe_active(const ec_eoe_t *eoe /**< EoE handler */)
|
|||
return eoe->slave && eoe->opened;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Prints EoE handler information.
|
||||
*/
|
||||
|
||||
void ec_eoe_print(const ec_eoe_t *eoe /**< EoE handler */)
|
||||
{
|
||||
EC_INFO(" EoE handler %s\n", eoe->dev->name);
|
||||
EC_INFO(" State: %s\n", eoe->opened ? "opened" : "closed");
|
||||
if (eoe->slave)
|
||||
EC_INFO(" Coupled to slave %i.\n", eoe->slave->ring_position);
|
||||
else
|
||||
EC_INFO(" Not coupled.\n");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* STATE PROCESSING FUNCTIONS
|
||||
*****************************************************************************/
|
||||
|
|
@ -338,7 +320,7 @@ void ec_eoe_state_rx_start(ec_eoe_t *eoe /**< EoE handler */)
|
|||
|
||||
void ec_eoe_state_rx_check(ec_eoe_t *eoe /**< EoE handler */)
|
||||
{
|
||||
if (eoe->datagram.state != EC_CMD_RECEIVED) {
|
||||
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
|
||||
eoe->stats.rx_errors++;
|
||||
eoe->state = ec_eoe_state_tx_start;
|
||||
return;
|
||||
|
|
@ -369,7 +351,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */)
|
|||
uint8_t frame_number, fragment_offset, fragment_number;
|
||||
off_t offset;
|
||||
|
||||
if (eoe->datagram.state != EC_CMD_RECEIVED) {
|
||||
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
|
||||
eoe->stats.rx_errors++;
|
||||
eoe->state = ec_eoe_state_tx_start;
|
||||
return;
|
||||
|
|
@ -570,7 +552,7 @@ void ec_eoe_state_tx_start(ec_eoe_t *eoe /**< EoE handler */)
|
|||
|
||||
void ec_eoe_state_tx_sent(ec_eoe_t *eoe /**< EoE handler */)
|
||||
{
|
||||
if (eoe->datagram.state != EC_CMD_RECEIVED) {
|
||||
if (eoe->datagram.state != EC_DATAGRAM_RECEIVED) {
|
||||
eoe->stats.tx_errors++;
|
||||
eoe->state = ec_eoe_state_rx_start;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -98,6 +98,5 @@ int ec_eoe_init(ec_eoe_t *);
|
|||
void ec_eoe_clear(ec_eoe_t *);
|
||||
void ec_eoe_run(ec_eoe_t *);
|
||||
unsigned int ec_eoe_active(const ec_eoe_t *);
|
||||
void ec_eoe_print(const ec_eoe_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
704
master/fsm.c
704
master/fsm.c
File diff suppressed because it is too large
Load Diff
|
|
@ -41,6 +41,7 @@
|
|||
#ifndef __EC_STATES__
|
||||
#define __EC_STATES__
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
|
|
@ -84,6 +85,14 @@ void ec_fsm_clear(ec_fsm_t *);
|
|||
void ec_fsm_reset(ec_fsm_t *);
|
||||
void ec_fsm_execute(ec_fsm_t *);
|
||||
|
||||
void ec_fsm_startup(ec_fsm_t *);
|
||||
int ec_fsm_startup_running(ec_fsm_t *);
|
||||
int ec_fsm_startup_success(ec_fsm_t *);
|
||||
|
||||
void ec_fsm_configuration(ec_fsm_t *);
|
||||
int ec_fsm_configuration_running(ec_fsm_t *);
|
||||
int ec_fsm_configuration_success(ec_fsm_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
#define EC_MASTER_VERSION_MAIN 1
|
||||
|
||||
/** master sub version (after the dot) */
|
||||
#define EC_MASTER_VERSION_SUB 0
|
||||
#define EC_MASTER_VERSION_SUB 1
|
||||
|
||||
/** master extra version (just a string) */
|
||||
#define EC_MASTER_VERSION_EXTRA "trunk"
|
||||
|
|
@ -65,6 +65,9 @@
|
|||
/** clock frequency for the EoE state machines */
|
||||
#define EC_EOE_FREQUENCY 1000
|
||||
|
||||
/** datagram timeout in microseconds */
|
||||
#define EC_IO_TIMEOUT 500
|
||||
|
||||
/******************************************************************************
|
||||
* EtherCAT protocol
|
||||
*****************************************************************************/
|
||||
|
|
@ -170,9 +173,9 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
extern void ec_print_data(const uint8_t *, size_t);
|
||||
extern void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
|
||||
extern void ec_print_states(uint8_t);
|
||||
void ec_print_data(const uint8_t *, size_t);
|
||||
void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t);
|
||||
size_t ec_state_string(uint8_t, char *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -192,4 +195,3 @@ ec_code_msg_t;
|
|||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -165,83 +165,3 @@ uint8_t *ec_slave_mbox_fetch(const ec_slave_t *slave, /**< slave */
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sends a mailbox datagram and waits for its reception.
|
||||
\return pointer to the received data
|
||||
*/
|
||||
|
||||
uint8_t *ec_slave_mbox_simple_io(const ec_slave_t *slave, /**< slave */
|
||||
ec_datagram_t *datagram, /**< datagram */
|
||||
size_t *size /**< size of the received data */
|
||||
)
|
||||
{
|
||||
uint8_t type;
|
||||
|
||||
type = EC_READ_U8(datagram->data + 5);
|
||||
|
||||
if (unlikely(ec_master_simple_io(slave->master, datagram))) {
|
||||
EC_ERR("Mailbox checking failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ec_slave_mbox_simple_receive(slave, datagram, type, size);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Waits for the reception of a mailbox datagram.
|
||||
\return pointer to the received data
|
||||
*/
|
||||
|
||||
uint8_t *ec_slave_mbox_simple_receive(const ec_slave_t *slave, /**< slave */
|
||||
ec_datagram_t *datagram, /**< datagram */
|
||||
uint8_t type, /**< expected protocol */
|
||||
size_t *size /**< received data size */
|
||||
)
|
||||
{
|
||||
cycles_t start, end, timeout;
|
||||
|
||||
start = get_cycles();
|
||||
timeout = (cycles_t) 100 * cpu_khz; // 100ms
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (ec_slave_mbox_prepare_check(slave, datagram)) return NULL;
|
||||
if (unlikely(ec_master_simple_io(slave->master, datagram))) {
|
||||
EC_ERR("Mailbox checking failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = get_cycles();
|
||||
|
||||
if (ec_slave_mbox_check(datagram))
|
||||
break; // proceed with receiving data
|
||||
|
||||
if ((end - start) >= timeout) {
|
||||
EC_ERR("Mailbox check - Slave %i timed out.\n",
|
||||
slave->ring_position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (ec_slave_mbox_prepare_fetch(slave, datagram)) return NULL;
|
||||
if (unlikely(ec_master_simple_io(slave->master, datagram))) {
|
||||
EC_ERR("Mailbox receiving failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unlikely(slave->master->debug_level) > 1)
|
||||
EC_DBG("Mailbox receive took %ius.\n",
|
||||
((unsigned int) (end - start) * 1000 / cpu_khz));
|
||||
|
||||
return ec_slave_mbox_fetch(slave, datagram, type, size);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
598
master/master.c
598
master/master.c
|
|
@ -48,13 +48,13 @@
|
|||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "slave.h"
|
||||
#include "types.h"
|
||||
#include "device.h"
|
||||
#include "datagram.h"
|
||||
#include "ethernet.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_master_sync_io(ec_master_t *);
|
||||
void ec_master_idle_run(void *);
|
||||
void ec_master_eoe_run(unsigned long);
|
||||
ssize_t ec_show_master_attribute(struct kobject *, struct attribute *, char *);
|
||||
|
|
@ -115,7 +115,6 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
INIT_LIST_HEAD(&master->datagram_queue);
|
||||
INIT_LIST_HEAD(&master->domains);
|
||||
INIT_LIST_HEAD(&master->eoe_handlers);
|
||||
ec_datagram_init(&master->simple_datagram);
|
||||
INIT_WORK(&master->idle_work, ec_master_idle_run, (void *) master);
|
||||
init_timer(&master->eoe_timer);
|
||||
master->eoe_timer.function = ec_master_eoe_run;
|
||||
|
|
@ -186,7 +185,6 @@ void ec_master_clear(struct kobject *kobj /**< kobject of the master */)
|
|||
|
||||
ec_master_reset(master);
|
||||
ec_fsm_clear(&master->fsm);
|
||||
ec_datagram_clear(&master->simple_datagram);
|
||||
destroy_workqueue(master->workqueue);
|
||||
|
||||
// clear EoE objects
|
||||
|
|
@ -225,7 +223,7 @@ void ec_master_reset(ec_master_t *master /**< EtherCAT master */)
|
|||
list_for_each_entry_safe(datagram, next_c,
|
||||
&master->datagram_queue, queue) {
|
||||
list_del_init(&datagram->queue);
|
||||
datagram->state = EC_CMD_ERROR;
|
||||
datagram->state = EC_DATAGRAM_ERROR;
|
||||
}
|
||||
|
||||
// clear domains
|
||||
|
|
@ -237,7 +235,6 @@ void ec_master_reset(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
master->datagram_index = 0;
|
||||
master->debug_level = 0;
|
||||
master->timeout = 500; // 500us
|
||||
|
||||
master->stats.timeouts = 0;
|
||||
master->stats.delayed = 0;
|
||||
|
|
@ -289,7 +286,7 @@ void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
|||
// check, if the datagram is already queued
|
||||
list_for_each_entry(queued_datagram, &master->datagram_queue, queue) {
|
||||
if (queued_datagram == datagram) {
|
||||
datagram->state = EC_CMD_QUEUED;
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
if (unlikely(master->debug_level))
|
||||
EC_WARN("datagram already queued.\n");
|
||||
return;
|
||||
|
|
@ -297,7 +294,7 @@ void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
|||
}
|
||||
|
||||
list_add_tail(&datagram->queue, &master->datagram_queue);
|
||||
datagram->state = EC_CMD_QUEUED;
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -331,7 +328,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
// fill current frame with datagrams
|
||||
list_for_each_entry(datagram, &master->datagram_queue, queue) {
|
||||
if (datagram->state != EC_CMD_QUEUED) continue;
|
||||
if (datagram->state != EC_DATAGRAM_QUEUED) continue;
|
||||
|
||||
// does the current datagram fit in the frame?
|
||||
datagram_size = EC_DATAGRAM_HEADER_SIZE + datagram->data_size
|
||||
|
|
@ -341,7 +338,7 @@ void ec_master_send_datagrams(ec_master_t *master /**< EtherCAT master */)
|
|||
break;
|
||||
}
|
||||
|
||||
datagram->state = EC_CMD_SENT;
|
||||
datagram->state = EC_DATAGRAM_SENT;
|
||||
datagram->t_sent = t_start;
|
||||
datagram->index = master->datagram_index++;
|
||||
|
||||
|
|
@ -456,7 +453,7 @@ void ec_master_receive(ec_master_t *master, /**< EtherCAT master */
|
|||
// search for matching datagram in the queue
|
||||
matched = 0;
|
||||
list_for_each_entry(datagram, &master->datagram_queue, queue) {
|
||||
if (datagram->state == EC_CMD_SENT
|
||||
if (datagram->state == EC_DATAGRAM_SENT
|
||||
&& datagram->type == datagram_type
|
||||
&& datagram->index == datagram_index
|
||||
&& datagram->data_size == data_size) {
|
||||
|
|
@ -482,57 +479,13 @@ void ec_master_receive(ec_master_t *master, /**< EtherCAT master */
|
|||
cur_data += EC_DATAGRAM_FOOTER_SIZE;
|
||||
|
||||
// dequeue the received datagram
|
||||
datagram->state = EC_CMD_RECEIVED;
|
||||
datagram->state = EC_DATAGRAM_RECEIVED;
|
||||
list_del_init(&datagram->queue);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sends a single datagram and waits for its reception.
|
||||
If the slave doesn't respond, the datagram is sent again.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_master_simple_io(ec_master_t *master, /**< EtherCAT master */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
unsigned int response_tries_left;
|
||||
|
||||
response_tries_left = 10000;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ec_master_queue_datagram(master, datagram);
|
||||
ecrt_master_sync_io(master);
|
||||
|
||||
if (datagram->state == EC_CMD_RECEIVED) {
|
||||
if (likely(datagram->working_counter))
|
||||
return 0;
|
||||
}
|
||||
else if (datagram->state == EC_CMD_TIMEOUT) {
|
||||
EC_ERR("Simple-IO TIMEOUT!\n");
|
||||
return -1;
|
||||
}
|
||||
else if (datagram->state == EC_CMD_ERROR) {
|
||||
EC_ERR("Simple-IO datagram error!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// no direct response, wait a little bit...
|
||||
udelay(100);
|
||||
|
||||
if (unlikely(--response_tries_left)) {
|
||||
EC_ERR("No response in simple-IO!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Scans the EtherCAT bus for slaves.
|
||||
Creates a list of slave structures for further processing.
|
||||
|
|
@ -541,102 +494,22 @@ int ec_master_simple_io(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
int ec_master_bus_scan(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
ec_slave_ident_t *ident;
|
||||
ec_datagram_t *datagram;
|
||||
unsigned int i;
|
||||
uint16_t coupler_index, coupler_subindex;
|
||||
uint16_t reverse_coupler_index, current_coupler_index;
|
||||
ec_fsm_t *fsm = &master->fsm;
|
||||
|
||||
if (!list_empty(&master->slaves)) {
|
||||
EC_ERR("Slave scan already done!\n");
|
||||
ec_fsm_startup(fsm); // init startup state machine
|
||||
|
||||
do {
|
||||
ec_fsm_execute(fsm);
|
||||
ec_master_sync_io(master);
|
||||
}
|
||||
while (ec_fsm_startup_running(fsm));
|
||||
|
||||
if (!ec_fsm_startup_success(fsm)) {
|
||||
ec_master_clear_slaves(master);
|
||||
return -1;
|
||||
}
|
||||
|
||||
datagram = &master->simple_datagram;
|
||||
|
||||
// determine number of slaves on bus
|
||||
if (ec_datagram_brd(datagram, 0x0000, 4)) return -1;
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) return -1;
|
||||
master->slave_count = datagram->working_counter;
|
||||
EC_INFO("Found %i slaves on bus.\n", master->slave_count);
|
||||
|
||||
if (!master->slave_count) return 0;
|
||||
|
||||
// init slaves
|
||||
for (i = 0; i < master->slave_count; i++) {
|
||||
if (!(slave =
|
||||
(ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate slave %i!\n", i);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (ec_slave_init(slave, master, i, i + 1)) goto out_free;
|
||||
|
||||
if (kobject_add(&slave->kobj)) {
|
||||
EC_ERR("Failed to add kobject.\n");
|
||||
kobject_put(&slave->kobj); // free
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
list_add_tail(&slave->list, &master->slaves);
|
||||
}
|
||||
|
||||
coupler_index = 0;
|
||||
reverse_coupler_index = 0xFFFF;
|
||||
current_coupler_index = 0x3FFF;
|
||||
coupler_subindex = 0;
|
||||
|
||||
// for every slave on the bus
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
|
||||
// write station address
|
||||
if (ec_datagram_apwr(datagram, slave->ring_position, 0x0010,
|
||||
sizeof(uint16_t))) goto out_free;
|
||||
EC_WRITE_U16(datagram->data, slave->station_address);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Writing station address failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
// fetch all slave information
|
||||
if (ec_slave_fetch(slave)) goto out_free;
|
||||
|
||||
// search for identification in "database"
|
||||
ident = slave_idents;
|
||||
while (ident->type) {
|
||||
if (unlikely(ident->vendor_id == slave->sii_vendor_id
|
||||
&& ident->product_code == slave->sii_product_code)) {
|
||||
slave->type = ident->type;
|
||||
break;
|
||||
}
|
||||
ident++;
|
||||
}
|
||||
|
||||
if (!slave->type) {
|
||||
EC_WARN("Unknown slave device (vendor 0x%08X, code 0x%08X) at"
|
||||
" position %i.\n", slave->sii_vendor_id,
|
||||
slave->sii_product_code, slave->ring_position);
|
||||
}
|
||||
else if (slave->type->special == EC_TYPE_BUS_COUPLER) {
|
||||
if (slave->sii_alias)
|
||||
current_coupler_index = reverse_coupler_index--;
|
||||
else
|
||||
current_coupler_index = coupler_index++;
|
||||
coupler_subindex = 0;
|
||||
}
|
||||
|
||||
slave->coupler_index = current_coupler_index;
|
||||
slave->coupler_subindex = coupler_subindex;
|
||||
coupler_subindex++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
ec_master_clear_slaves(master);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -682,7 +555,7 @@ void ec_master_idle_start(ec_master_t *master /**< EtherCAT master */)
|
|||
{
|
||||
if (master->mode == EC_MASTER_MODE_IDLE) return;
|
||||
|
||||
if (master->mode == EC_MASTER_MODE_RUNNING) {
|
||||
if (master->mode == EC_MASTER_MODE_OPERATION) {
|
||||
EC_ERR("ec_master_idle_start: Master already running!\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -731,12 +604,12 @@ void ec_master_idle_run(void *data /**< master pointer */)
|
|||
// aquire master lock
|
||||
spin_lock_bh(&master->internal_lock);
|
||||
|
||||
ecrt_master_async_receive(master);
|
||||
ecrt_master_receive(master);
|
||||
|
||||
// execute master state machine
|
||||
ec_fsm_execute(&master->fsm);
|
||||
|
||||
ecrt_master_async_send(master);
|
||||
ecrt_master_send(master);
|
||||
|
||||
// release master lock
|
||||
spin_unlock_bh(&master->internal_lock);
|
||||
|
|
@ -748,11 +621,11 @@ void ec_master_idle_run(void *data /**< master pointer */)
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes a sync manager configuration page.
|
||||
Initializes a sync manager configuration page with EEPROM data.
|
||||
The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes.
|
||||
*/
|
||||
|
||||
void ec_sync_config(const ec_sync_t *sync, /**< sync manager */
|
||||
void ec_sync_config(const ec_sii_sync_t *sync, /**< sync manager */
|
||||
const ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint8_t *data /**> configuration memory */
|
||||
)
|
||||
|
|
@ -761,29 +634,6 @@ void ec_sync_config(const ec_sync_t *sync, /**< sync manager */
|
|||
|
||||
sync_size = ec_slave_calc_sync_size(slave, sync);
|
||||
|
||||
EC_WRITE_U16(data, sync->physical_start_address);
|
||||
EC_WRITE_U16(data + 2, sync_size);
|
||||
EC_WRITE_U8 (data + 4, sync->control_byte);
|
||||
EC_WRITE_U8 (data + 5, 0x00); // status byte (read only)
|
||||
EC_WRITE_U16(data + 6, 0x0001); // enable
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes a sync manager configuration page with EEPROM data.
|
||||
The referenced memory (\a data) must be at least EC_SYNC_SIZE bytes.
|
||||
*/
|
||||
|
||||
void ec_eeprom_sync_config(const ec_eeprom_sync_t *sync, /**< sync manager */
|
||||
const ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint8_t *data /**> configuration memory */
|
||||
)
|
||||
{
|
||||
size_t sync_size;
|
||||
|
||||
sync_size = ec_slave_calc_eeprom_sync_size(slave, sync);
|
||||
|
||||
if (slave->master->debug_level) {
|
||||
EC_INFO("Slave %i, sync manager %i:\n", slave->ring_position,
|
||||
sync->index);
|
||||
|
|
@ -821,7 +671,8 @@ void ec_fmmu_config(const ec_fmmu_t *fmmu, /**< FMMU */
|
|||
EC_WRITE_U8 (data + 7, 0x07); // logical end bit
|
||||
EC_WRITE_U16(data + 8, fmmu->sync->physical_start_address);
|
||||
EC_WRITE_U8 (data + 10, 0x00); // physical start bit
|
||||
EC_WRITE_U8 (data + 11, (fmmu->sync->control_byte & 0x04) ? 0x02 : 0x01);
|
||||
EC_WRITE_U8 (data + 11, ((fmmu->sync->control_register & 0x04)
|
||||
? 0x02 : 0x01));
|
||||
EC_WRITE_U16(data + 12, 0x0001); // enable
|
||||
EC_WRITE_U16(data + 14, 0x0000); // reserved
|
||||
}
|
||||
|
|
@ -849,8 +700,8 @@ ssize_t ec_show_master_attribute(struct kobject *kobj, /**< kobject */
|
|||
return sprintf(buffer, "ORPHANED\n");
|
||||
case EC_MASTER_MODE_IDLE:
|
||||
return sprintf(buffer, "IDLE\n");
|
||||
case EC_MASTER_MODE_RUNNING:
|
||||
return sprintf(buffer, "RUNNING\n");
|
||||
case EC_MASTER_MODE_OPERATION:
|
||||
return sprintf(buffer, "OPERATION\n");
|
||||
}
|
||||
}
|
||||
else if (attr == &attr_debug_level) {
|
||||
|
|
@ -922,7 +773,7 @@ ssize_t ec_store_master_attribute(struct kobject *kobj, /**< slave's kobject */
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves.
|
||||
Starts/Stops Ethernet-over-EtherCAT processing on demand.
|
||||
*/
|
||||
|
||||
void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
|
||||
|
|
@ -933,12 +784,17 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
if (master->eoe_running) return;
|
||||
|
||||
// if the locking callbacks are not set in operation mode,
|
||||
// the EoE timer my not be started.
|
||||
if (master->mode == EC_MASTER_MODE_OPERATION
|
||||
&& (!master->request_cb || !master->release_cb)) return;
|
||||
|
||||
// decouple all EoE handlers
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list)
|
||||
eoe->slave = NULL;
|
||||
coupled = 0;
|
||||
|
||||
// couple a free EoE handler to every EoE-capable slave
|
||||
coupled = 0;
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
if (!(slave->sii_mailbox_protocols & EC_MBOX_EOE)) continue;
|
||||
|
||||
|
|
@ -950,12 +806,8 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
|
|||
coupled++;
|
||||
EC_INFO("Coupling device %s to slave %i.\n",
|
||||
eoe->dev->name, slave->ring_position);
|
||||
if (eoe->opened) {
|
||||
slave->requested_state = EC_SLAVE_STATE_OP;
|
||||
}
|
||||
else {
|
||||
slave->requested_state = EC_SLAVE_STATE_INIT;
|
||||
}
|
||||
if (eoe->opened) slave->requested_state = EC_SLAVE_STATE_OP;
|
||||
else slave->requested_state = EC_SLAVE_STATE_INIT;
|
||||
slave->error_flag = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1026,7 +878,7 @@ void ec_master_eoe_run(unsigned long data /**< master pointer */)
|
|||
if (!active) goto queue_timer;
|
||||
|
||||
// aquire master lock...
|
||||
if (master->mode == EC_MASTER_MODE_RUNNING) {
|
||||
if (master->mode == EC_MASTER_MODE_OPERATION) {
|
||||
// request_cb must return 0, if the lock has been aquired!
|
||||
if (master->request_cb(master->cb_data))
|
||||
goto queue_timer;
|
||||
|
|
@ -1038,14 +890,14 @@ void ec_master_eoe_run(unsigned long data /**< master pointer */)
|
|||
goto queue_timer;
|
||||
|
||||
// actual EoE stuff
|
||||
ecrt_master_async_receive(master);
|
||||
ecrt_master_receive(master);
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list) {
|
||||
ec_eoe_run(eoe);
|
||||
}
|
||||
ecrt_master_async_send(master);
|
||||
ecrt_master_send(master);
|
||||
|
||||
// release lock...
|
||||
if (master->mode == EC_MASTER_MODE_RUNNING) {
|
||||
if (master->mode == EC_MASTER_MODE_OPERATION) {
|
||||
master->release_cb(master->cb_data);
|
||||
}
|
||||
else if (master->mode == EC_MASTER_MODE_IDLE) {
|
||||
|
|
@ -1057,6 +909,38 @@ void ec_master_eoe_run(unsigned long data /**< master pointer */)
|
|||
add_timer(&master->eoe_timer);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Calculates Advanced Position Adresses.
|
||||
*/
|
||||
|
||||
void ec_master_calc_addressing(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
uint16_t coupler_index, coupler_subindex;
|
||||
uint16_t reverse_coupler_index, current_coupler_index;
|
||||
ec_slave_t *slave;
|
||||
|
||||
coupler_index = 0;
|
||||
reverse_coupler_index = 0xFFFF;
|
||||
current_coupler_index = 0x0000;
|
||||
coupler_subindex = 0;
|
||||
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
if (ec_slave_is_coupler(slave)) {
|
||||
if (slave->sii_alias)
|
||||
current_coupler_index = reverse_coupler_index--;
|
||||
else
|
||||
current_coupler_index = coupler_index++;
|
||||
coupler_subindex = 0;
|
||||
}
|
||||
|
||||
slave->coupler_index = current_coupler_index;
|
||||
slave->coupler_subindex = coupler_subindex;
|
||||
coupler_subindex++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Realtime interface
|
||||
*****************************************************************************/
|
||||
|
|
@ -1115,17 +999,10 @@ ec_domain_t *ecrt_master_create_domain(ec_master_t *master /**< master */)
|
|||
|
||||
int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
unsigned int j;
|
||||
ec_slave_t *slave;
|
||||
ec_datagram_t *datagram;
|
||||
const ec_sync_t *sync;
|
||||
const ec_slave_type_t *type;
|
||||
const ec_fmmu_t *fmmu;
|
||||
uint32_t domain_offset;
|
||||
ec_domain_t *domain;
|
||||
ec_eeprom_sync_t *eeprom_sync, mbox_sync;
|
||||
|
||||
datagram = &master->simple_datagram;
|
||||
ec_fsm_t *fsm = &master->fsm;
|
||||
ec_slave_t *slave;
|
||||
|
||||
// allocate all domains
|
||||
domain_offset = 0;
|
||||
|
|
@ -1137,150 +1014,30 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
|||
domain_offset += domain->data_size;
|
||||
}
|
||||
|
||||
// configure and activate slaves
|
||||
// determine initial states.
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
|
||||
// change state to INIT
|
||||
if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_INIT)))
|
||||
return -1;
|
||||
|
||||
// check for slave registration
|
||||
type = slave->type;
|
||||
if (!type)
|
||||
EC_WARN("Slave %i has unknown type!\n", slave->ring_position);
|
||||
|
||||
// check and reset CRC fault counters
|
||||
ec_slave_check_crc(slave);
|
||||
|
||||
// reset FMMUs
|
||||
if (slave->base_fmmu_count) {
|
||||
if (ec_datagram_npwr(datagram, slave->station_address, 0x0600,
|
||||
EC_FMMU_SIZE * slave->base_fmmu_count))
|
||||
return -1;
|
||||
memset(datagram->data, 0x00,
|
||||
EC_FMMU_SIZE * slave->base_fmmu_count);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Resetting FMMUs failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
if (ec_slave_is_coupler(slave) || slave->registered) {
|
||||
slave->requested_state = EC_SLAVE_STATE_OP;
|
||||
}
|
||||
|
||||
// reset sync managers
|
||||
if (slave->base_sync_count) {
|
||||
if (ec_datagram_npwr(datagram, slave->station_address, 0x0800,
|
||||
EC_SYNC_SIZE * slave->base_sync_count))
|
||||
return -1;
|
||||
memset(datagram->data, 0x00,
|
||||
EC_SYNC_SIZE * slave->base_sync_count);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Resetting sync managers failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
slave->requested_state = EC_SLAVE_STATE_PREOP;
|
||||
}
|
||||
|
||||
// configure sync managers
|
||||
|
||||
// does the slave provide sync manager information?
|
||||
if (!list_empty(&slave->eeprom_syncs)) {
|
||||
list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) {
|
||||
if (ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x800 + eeprom_sync->index *
|
||||
EC_SYNC_SIZE,
|
||||
EC_SYNC_SIZE)) return -1;
|
||||
ec_eeprom_sync_config(eeprom_sync, slave, datagram->data);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Setting sync manager %i failed on slave %i!\n",
|
||||
eeprom_sync->index, slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (type) { // known slave type, take type's SM information
|
||||
for (j = 0; type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
|
||||
sync = type->sync_managers[j];
|
||||
if (ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x0800 + j * EC_SYNC_SIZE, EC_SYNC_SIZE))
|
||||
return -1;
|
||||
ec_sync_config(sync, slave, datagram->data);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Setting sync manager %i failed on slave %i!\n",
|
||||
j, slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no sync manager information; guess mailbox settings
|
||||
else if (slave->sii_mailbox_protocols) {
|
||||
mbox_sync.physical_start_address =
|
||||
slave->sii_rx_mailbox_offset;
|
||||
mbox_sync.length = slave->sii_rx_mailbox_size;
|
||||
mbox_sync.control_register = 0x26;
|
||||
mbox_sync.enable = 1;
|
||||
if (ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x800,EC_SYNC_SIZE)) return -1;
|
||||
ec_eeprom_sync_config(&mbox_sync, slave, datagram->data);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Setting sync manager 0 failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbox_sync.physical_start_address =
|
||||
slave->sii_tx_mailbox_offset;
|
||||
mbox_sync.length = slave->sii_tx_mailbox_size;
|
||||
mbox_sync.control_register = 0x22;
|
||||
mbox_sync.enable = 1;
|
||||
if (ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x808, EC_SYNC_SIZE)) return -1;
|
||||
ec_eeprom_sync_config(&mbox_sync, slave, datagram->data);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Setting sync manager 1 failed on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// change state to PREOP
|
||||
if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_PREOP)))
|
||||
return -1;
|
||||
|
||||
// stop activation here for slaves without type
|
||||
if (!type) continue;
|
||||
|
||||
// slaves that are not registered are only brought into PREOP
|
||||
// state -> nice blinking and mailbox communication possible
|
||||
if (!slave->registered && !slave->type->special) {
|
||||
EC_WARN("Slave %i was not registered!\n", slave->ring_position);
|
||||
continue;
|
||||
}
|
||||
|
||||
// configure FMMUs
|
||||
for (j = 0; j < slave->fmmu_count; j++) {
|
||||
fmmu = &slave->fmmus[j];
|
||||
if (ec_datagram_npwr(datagram, slave->station_address,
|
||||
0x0600 + j * EC_FMMU_SIZE, EC_FMMU_SIZE))
|
||||
return -1;
|
||||
ec_fmmu_config(fmmu, slave, datagram->data);
|
||||
if (unlikely(ec_master_simple_io(master, datagram))) {
|
||||
EC_ERR("Setting FMMU %i failed on slave %i!\n",
|
||||
j, slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// change state to SAVEOP
|
||||
if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_SAVEOP)))
|
||||
return -1;
|
||||
|
||||
// change state to OP
|
||||
if (unlikely(ec_slave_state_change(slave, EC_SLAVE_STATE_OP)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_fsm_configuration(fsm); // init configuration state machine
|
||||
|
||||
do {
|
||||
ec_fsm_execute(fsm);
|
||||
ec_master_sync_io(master);
|
||||
}
|
||||
while (ec_fsm_configuration_running(fsm));
|
||||
|
||||
if (!ec_fsm_configuration_success(fsm)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_fsm_reset(&master->fsm); // prepare for operation state machine
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1293,59 +1050,39 @@ int ecrt_master_activate(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
void ecrt_master_deactivate(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_fsm_t *fsm = &master->fsm;
|
||||
ec_slave_t *slave;
|
||||
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
ec_slave_check_crc(slave);
|
||||
ec_slave_state_change(slave, EC_SLAVE_STATE_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Fetches the SDO dictionaries of all slaves.
|
||||
Slaves that do not support the CoE protocol are left out.
|
||||
\return 0 in case of success, else < 0
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_master_fetch_sdo_lists(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
|
||||
list_for_each_entry(slave, &master->slaves, list) {
|
||||
if (slave->sii_mailbox_protocols & EC_MBOX_COE) {
|
||||
if (unlikely(ec_slave_fetch_sdo_list(slave))) {
|
||||
EC_ERR("Failed to fetch SDO list on slave %i!\n",
|
||||
slave->ring_position);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
slave->requested_state = EC_SLAVE_STATE_INIT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ec_fsm_configuration(fsm); // init configuration state machine
|
||||
|
||||
do {
|
||||
ec_fsm_execute(fsm);
|
||||
ec_master_sync_io(master);
|
||||
}
|
||||
while (ec_fsm_configuration_running(fsm));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sends queued datagrams and waits for their reception.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_sync_io(ec_master_t *master /**< EtherCAT master */)
|
||||
void ec_master_sync_io(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_datagram_t *datagram, *n;
|
||||
unsigned int datagrams_sent;
|
||||
cycles_t t_start, t_end, t_timeout;
|
||||
|
||||
// send datagrams
|
||||
ecrt_master_async_send(master);
|
||||
ecrt_master_send(master);
|
||||
|
||||
t_start = get_cycles(); // measure io time
|
||||
t_timeout = (cycles_t) master->timeout * (cpu_khz / 1000);
|
||||
t_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
|
||||
|
||||
while (1) { // active waiting
|
||||
ec_device_call_isr(master->device);
|
||||
|
|
@ -1355,9 +1092,9 @@ void ecrt_master_sync_io(ec_master_t *master /**< EtherCAT master */)
|
|||
|
||||
datagrams_sent = 0;
|
||||
list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
|
||||
if (datagram->state == EC_CMD_RECEIVED)
|
||||
if (datagram->state == EC_DATAGRAM_RECEIVED)
|
||||
list_del_init(&datagram->queue);
|
||||
else if (datagram->state == EC_CMD_SENT)
|
||||
else if (datagram->state == EC_DATAGRAM_SENT)
|
||||
datagrams_sent++;
|
||||
}
|
||||
|
||||
|
|
@ -1367,13 +1104,13 @@ void ecrt_master_sync_io(ec_master_t *master /**< EtherCAT master */)
|
|||
// timeout; dequeue all datagrams
|
||||
list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
|
||||
switch (datagram->state) {
|
||||
case EC_CMD_SENT:
|
||||
case EC_CMD_QUEUED:
|
||||
datagram->state = EC_CMD_TIMEOUT;
|
||||
case EC_DATAGRAM_SENT:
|
||||
case EC_DATAGRAM_QUEUED:
|
||||
datagram->state = EC_DATAGRAM_TIMED_OUT;
|
||||
master->stats.timeouts++;
|
||||
ec_master_output_stats(master);
|
||||
break;
|
||||
case EC_CMD_RECEIVED:
|
||||
case EC_DATAGRAM_RECEIVED:
|
||||
master->stats.delayed++;
|
||||
ec_master_output_stats(master);
|
||||
break;
|
||||
|
|
@ -1391,14 +1128,14 @@ void ecrt_master_sync_io(ec_master_t *master /**< EtherCAT master */)
|
|||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_async_send(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_master_send(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_datagram_t *datagram, *n;
|
||||
|
||||
if (unlikely(!master->device->link_state)) {
|
||||
// link is down, no datagram can be sent
|
||||
list_for_each_entry_safe(datagram, n, &master->datagram_queue, queue) {
|
||||
datagram->state = EC_CMD_ERROR;
|
||||
datagram->state = EC_DATAGRAM_ERROR;
|
||||
list_del_init(&datagram->queue);
|
||||
}
|
||||
|
||||
|
|
@ -1418,7 +1155,7 @@ void ecrt_master_async_send(ec_master_t *master /**< EtherCAT master */)
|
|||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_async_receive(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_master_receive(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_datagram_t *datagram, *next;
|
||||
cycles_t t_received, t_timeout;
|
||||
|
|
@ -1426,21 +1163,21 @@ void ecrt_master_async_receive(ec_master_t *master /**< EtherCAT master */)
|
|||
ec_device_call_isr(master->device);
|
||||
|
||||
t_received = get_cycles();
|
||||
t_timeout = (cycles_t) master->timeout * (cpu_khz / 1000);
|
||||
t_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
|
||||
|
||||
// dequeue all received datagrams
|
||||
list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue)
|
||||
if (datagram->state == EC_CMD_RECEIVED)
|
||||
if (datagram->state == EC_DATAGRAM_RECEIVED)
|
||||
list_del_init(&datagram->queue);
|
||||
|
||||
// dequeue all datagrams that timed out
|
||||
list_for_each_entry_safe(datagram, next, &master->datagram_queue, queue) {
|
||||
switch (datagram->state) {
|
||||
case EC_CMD_SENT:
|
||||
case EC_CMD_QUEUED:
|
||||
case EC_DATAGRAM_SENT:
|
||||
case EC_DATAGRAM_QUEUED:
|
||||
if (t_received - datagram->t_sent > t_timeout) {
|
||||
list_del_init(&datagram->queue);
|
||||
datagram->state = EC_CMD_TIMEOUT;
|
||||
datagram->state = EC_DATAGRAM_TIMED_OUT;
|
||||
master->stats.timeouts++;
|
||||
ec_master_output_stats(master);
|
||||
}
|
||||
|
|
@ -1456,23 +1193,23 @@ void ecrt_master_async_receive(ec_master_t *master /**< EtherCAT master */)
|
|||
/**
|
||||
Prepares synchronous IO.
|
||||
Queues all domain datagrams and sends them. Then waits a certain time, so
|
||||
that ecrt_master_sasync_receive() can be called securely.
|
||||
that ecrt_master_receive() can be called securely.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_prepare_async_io(ec_master_t *master /**< EtherCAT master */)
|
||||
void ecrt_master_prepare(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
ec_domain_t *domain;
|
||||
cycles_t t_start, t_end, t_timeout;
|
||||
|
||||
// queue datagrams of all domains
|
||||
list_for_each_entry(domain, &master->domains, list)
|
||||
ecrt_domain_queue(domain);
|
||||
ec_domain_queue(domain);
|
||||
|
||||
ecrt_master_async_send(master);
|
||||
ecrt_master_send(master);
|
||||
|
||||
t_start = get_cycles(); // take sending time
|
||||
t_timeout = (cycles_t) master->timeout * (cpu_khz / 1000);
|
||||
t_timeout = (cycles_t) EC_IO_TIMEOUT * (cpu_khz / 1000);
|
||||
|
||||
// active waiting
|
||||
while (1) {
|
||||
|
|
@ -1576,8 +1313,7 @@ ec_slave_t *ecrt_master_get_slave(const ec_master_t *master, /**< Master */
|
|||
}
|
||||
|
||||
if (alias_requested) {
|
||||
if (!alias_slave->type ||
|
||||
alias_slave->type->special != EC_TYPE_BUS_COUPLER) {
|
||||
if (!ec_slave_is_coupler(alias_slave)) {
|
||||
EC_ERR("Slave address \"%s\": Alias slave must be bus coupler"
|
||||
" in colon mode.\n", address);
|
||||
return NULL;
|
||||
|
|
@ -1628,92 +1364,16 @@ void ecrt_master_callbacks(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Starts Ethernet-over-EtherCAT processing for all EoE-capable slaves.
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
int ecrt_master_start_eoe(ec_master_t *master /**< EtherCAT master */)
|
||||
{
|
||||
if (!master->request_cb || !master->release_cb) {
|
||||
EC_ERR("EoE requires master callbacks to be set!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec_master_eoe_start(master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sets the debug level of the master.
|
||||
The following levels are valid:
|
||||
- 1: only output positions marks and basic data
|
||||
- 2: additional frame data output
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_debug(ec_master_t *master, /**< EtherCAT master */
|
||||
int level /**< debug level */
|
||||
)
|
||||
{
|
||||
if (level != master->debug_level) {
|
||||
master->debug_level = level;
|
||||
EC_INFO("Master debug level set to %i.\n", level);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Outputs all master information.
|
||||
Verbosity:
|
||||
- 0: Only slave types and positions
|
||||
- 1: with EEPROM contents
|
||||
- >1: with SDO dictionaries
|
||||
\ingroup RealtimeInterface
|
||||
*/
|
||||
|
||||
void ecrt_master_print(const ec_master_t *master, /**< EtherCAT master */
|
||||
unsigned int verbosity /**< verbosity level */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave;
|
||||
ec_eoe_t *eoe;
|
||||
|
||||
EC_INFO("*** Begin master information ***\n");
|
||||
if (master->slave_count) {
|
||||
EC_INFO("Slave list:\n");
|
||||
list_for_each_entry(slave, &master->slaves, list)
|
||||
ec_slave_print(slave, verbosity);
|
||||
}
|
||||
if (!list_empty(&master->eoe_handlers)) {
|
||||
EC_INFO("Ethernet-over-EtherCAT (EoE) objects:\n");
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list) {
|
||||
ec_eoe_print(eoe);
|
||||
}
|
||||
}
|
||||
EC_INFO("*** End master information ***\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_master_create_domain);
|
||||
EXPORT_SYMBOL(ecrt_master_activate);
|
||||
EXPORT_SYMBOL(ecrt_master_deactivate);
|
||||
EXPORT_SYMBOL(ecrt_master_fetch_sdo_lists);
|
||||
EXPORT_SYMBOL(ecrt_master_prepare_async_io);
|
||||
EXPORT_SYMBOL(ecrt_master_sync_io);
|
||||
EXPORT_SYMBOL(ecrt_master_async_send);
|
||||
EXPORT_SYMBOL(ecrt_master_async_receive);
|
||||
EXPORT_SYMBOL(ecrt_master_prepare);
|
||||
EXPORT_SYMBOL(ecrt_master_send);
|
||||
EXPORT_SYMBOL(ecrt_master_receive);
|
||||
EXPORT_SYMBOL(ecrt_master_run);
|
||||
EXPORT_SYMBOL(ecrt_master_callbacks);
|
||||
EXPORT_SYMBOL(ecrt_master_start_eoe);
|
||||
EXPORT_SYMBOL(ecrt_master_debug);
|
||||
EXPORT_SYMBOL(ecrt_master_print);
|
||||
EXPORT_SYMBOL(ecrt_master_get_slave);
|
||||
|
||||
/** \endcond */
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ typedef enum
|
|||
{
|
||||
EC_MASTER_MODE_ORPHANED,
|
||||
EC_MASTER_MODE_IDLE,
|
||||
EC_MASTER_MODE_RUNNING
|
||||
EC_MASTER_MODE_OPERATION
|
||||
}
|
||||
ec_master_mode_t;
|
||||
|
||||
|
|
@ -104,10 +104,6 @@ struct ec_master
|
|||
|
||||
struct list_head domains; /**< list of domains */
|
||||
|
||||
ec_datagram_t simple_datagram; /**< datagram structure for
|
||||
initialization */
|
||||
unsigned int timeout; /**< timeout in synchronous IO */
|
||||
|
||||
int debug_level; /**< master debug level */
|
||||
ec_stats_t stats; /**< cyclic statistics */
|
||||
|
||||
|
|
@ -145,18 +141,18 @@ void ec_master_eoe_stop(ec_master_t *);
|
|||
// IO
|
||||
void ec_master_receive(ec_master_t *, const uint8_t *, size_t);
|
||||
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
|
||||
int ec_master_simple_io(ec_master_t *, ec_datagram_t *);
|
||||
|
||||
// slave management
|
||||
int ec_master_bus_scan(ec_master_t *);
|
||||
|
||||
// misc.
|
||||
void ec_master_clear_slaves(ec_master_t *);
|
||||
void ec_sync_config(const ec_sync_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_eeprom_sync_config(const ec_eeprom_sync_t *, const ec_slave_t *,
|
||||
uint8_t *);
|
||||
void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_master_output_stats(ec_master_t *);
|
||||
void ec_master_clear_slaves(ec_master_t *);
|
||||
|
||||
// other methods
|
||||
void ec_sync_config(const ec_sii_sync_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_fmmu_config(const ec_fmmu_t *, const ec_slave_t *, uint8_t *);
|
||||
void ec_master_calc_addressing(ec_master_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -237,33 +237,38 @@ void ec_print_data_diff(const uint8_t *d1, /**< first data */
|
|||
Prints slave states in clear text.
|
||||
*/
|
||||
|
||||
void ec_print_states(const uint8_t states /**< slave states */)
|
||||
size_t ec_state_string(uint8_t states, /**< slave states */
|
||||
char *buffer /**< target buffer (min. 25 bytes) */
|
||||
)
|
||||
{
|
||||
off_t off = 0;
|
||||
unsigned int first = 1;
|
||||
|
||||
if (!states) {
|
||||
printk("(unknown)");
|
||||
return;
|
||||
off += sprintf(buffer + off, "(unknown)");
|
||||
return off;
|
||||
}
|
||||
|
||||
if (states & EC_SLAVE_STATE_INIT) {
|
||||
printk("INIT");
|
||||
off += sprintf(buffer + off, "INIT");
|
||||
first = 0;
|
||||
}
|
||||
if (states & EC_SLAVE_STATE_PREOP) {
|
||||
if (!first) printk(", ");
|
||||
printk("PREOP");
|
||||
if (!first) off += sprintf(buffer + off, ", ");
|
||||
off += sprintf(buffer + off, "PREOP");
|
||||
first = 0;
|
||||
}
|
||||
if (states & EC_SLAVE_STATE_SAVEOP) {
|
||||
if (!first) printk(", ");
|
||||
printk("SAVEOP");
|
||||
if (!first) off += sprintf(buffer + off, ", ");
|
||||
off += sprintf(buffer + off, "SAVEOP");
|
||||
first = 0;
|
||||
}
|
||||
if (states & EC_SLAVE_STATE_OP) {
|
||||
if (!first) printk(", ");
|
||||
printk("OP");
|
||||
if (!first) off += sprintf(buffer + off, ", ");
|
||||
off += sprintf(buffer + off, "OP");
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
@ -426,7 +431,7 @@ ec_master_t *ecrt_request_master(unsigned int master_index
|
|||
|
||||
ec_master_idle_stop(master);
|
||||
ec_master_reset(master);
|
||||
master->mode = EC_MASTER_MODE_RUNNING;
|
||||
master->mode = EC_MASTER_MODE_OPERATION;
|
||||
|
||||
if (!master->device->link_state) EC_WARN("Link is DOWN.\n");
|
||||
|
||||
|
|
|
|||
1031
master/slave.c
1031
master/slave.c
File diff suppressed because it is too large
Load Diff
114
master/slave.h
114
master/slave.h
|
|
@ -44,9 +44,10 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "types.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -89,20 +90,6 @@ enum
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
FMMU configuration.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const ec_domain_t *domain; /**< domain */
|
||||
const ec_sync_t *sync; /**< sync manager */
|
||||
uint32_t logical_start_address; /**< logical start address */
|
||||
}
|
||||
ec_fmmu_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
String object (EEPROM).
|
||||
*/
|
||||
|
|
@ -113,7 +100,7 @@ typedef struct
|
|||
size_t size; /**< size in bytes */
|
||||
char *data; /**< string data */
|
||||
}
|
||||
ec_eeprom_string_t;
|
||||
ec_sii_string_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -130,7 +117,7 @@ typedef struct
|
|||
uint8_t control_register; /**< control register value */
|
||||
uint8_t enable; /**< enable bit */
|
||||
}
|
||||
ec_eeprom_sync_t;
|
||||
ec_sii_sync_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -143,7 +130,7 @@ typedef enum
|
|||
EC_RX_PDO, /**< Reveive PDO */
|
||||
EC_TX_PDO /**< Transmit PDO */
|
||||
}
|
||||
ec_pdo_type_t;
|
||||
ec_sii_pdo_type_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -154,13 +141,13 @@ ec_pdo_type_t;
|
|||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
ec_pdo_type_t type; /**< PDO type */
|
||||
ec_sii_pdo_type_t type; /**< PDO type */
|
||||
uint16_t index; /**< PDO index */
|
||||
uint8_t sync_manager; /**< assigned sync manager */
|
||||
uint8_t sync_index; /**< assigned sync manager */
|
||||
char *name; /**< PDO name */
|
||||
struct list_head entries; /**< entry list */
|
||||
}
|
||||
ec_eeprom_pdo_t;
|
||||
ec_sii_pdo_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -176,7 +163,7 @@ typedef struct
|
|||
char *name; /**< entry name */
|
||||
uint8_t bit_length; /**< entry length in bit */
|
||||
}
|
||||
ec_eeprom_pdo_entry_t;
|
||||
ec_sii_pdo_entry_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -188,7 +175,6 @@ typedef struct
|
|||
{
|
||||
struct list_head list; /**< list item */
|
||||
uint16_t index; /**< SDO index */
|
||||
//uint16_t type;
|
||||
uint8_t object_code; /**< object code */
|
||||
char *name; /**< SDO name */
|
||||
struct list_head entries; /**< entry list */
|
||||
|
|
@ -213,6 +199,20 @@ ec_sdo_entry_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
FMMU configuration.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const ec_domain_t *domain; /**< domain */
|
||||
const ec_sii_sync_t *sync; /**< sync manager */
|
||||
uint32_t logical_start_address; /**< logical start address */
|
||||
}
|
||||
ec_fmmu_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Variable-sized field information.
|
||||
*/
|
||||
|
|
@ -220,7 +220,7 @@ ec_sdo_entry_t;
|
|||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< list item */
|
||||
const ec_field_t *field; /**< data field */
|
||||
const ec_sii_pdo_t *pdo; /**< PDO */
|
||||
size_t size; /**< field size */
|
||||
}
|
||||
ec_varsize_t;
|
||||
|
|
@ -237,6 +237,12 @@ struct ec_slave
|
|||
struct kobject kobj; /**< kobject */
|
||||
ec_master_t *master; /**< master owning the slave */
|
||||
|
||||
ec_slave_state_t requested_state; /**< requested slave state */
|
||||
ec_slave_state_t current_state; /**< current slave state */
|
||||
unsigned int error_flag; /**< stop processing after an error */
|
||||
unsigned int online; /**< non-zero, if the slave responds. */
|
||||
uint8_t registered; /**< true, if slave has been registered */
|
||||
|
||||
// addresses
|
||||
uint16_t ring_position; /**< ring position */
|
||||
uint16_t station_address; /**< configured station address */
|
||||
|
|
@ -255,6 +261,12 @@ struct ec_slave
|
|||
uint8_t dl_loop[4]; /**< loop closed */
|
||||
uint8_t dl_signal[4]; /**< detected signal on RX port */
|
||||
|
||||
// EEPROM
|
||||
uint8_t *eeprom_data; /**< Complete EEPROM image */
|
||||
uint16_t eeprom_size; /**< size of the EEPROM contents in byte */
|
||||
uint16_t *new_eeprom_data; /**< new EEPROM data to write */
|
||||
uint16_t new_eeprom_size; /**< size of new EEPROM data in words */
|
||||
|
||||
// slave information interface
|
||||
uint16_t sii_alias; /**< configured station alias */
|
||||
uint32_t sii_vendor_id; /**< vendor id */
|
||||
|
|
@ -267,34 +279,19 @@ struct ec_slave
|
|||
uint16_t sii_tx_mailbox_size; /**< mailbox size (slave to master) */
|
||||
uint16_t sii_mailbox_protocols; /**< supported mailbox protocols */
|
||||
uint8_t sii_physical_layer[4]; /**< port media */
|
||||
|
||||
const ec_slave_type_t *type; /**< pointer to slave type object */
|
||||
|
||||
uint8_t registered; /**< true, if slave has been registered */
|
||||
struct list_head sii_strings; /**< EEPROM STRING categories */
|
||||
struct list_head sii_syncs; /**< EEPROM SYNC MANAGER categories */
|
||||
struct list_head sii_pdos; /**< EEPROM [RT]XPDO categories */
|
||||
char *sii_group; /**< slave group acc. to EEPROM */
|
||||
char *sii_image; /**< slave image name acc. to EEPROM */
|
||||
char *sii_order; /**< slave order number acc. to EEPROM */
|
||||
char *sii_name; /**< slave name acc. to EEPROM */
|
||||
|
||||
ec_fmmu_t fmmus[EC_MAX_FMMUS]; /**< FMMU configurations */
|
||||
uint8_t fmmu_count; /**< number of FMMUs used */
|
||||
|
||||
uint8_t *eeprom_data; /**< Complete EEPROM image */
|
||||
uint16_t eeprom_size; /**< size of the EEPROM contents in byte */
|
||||
struct list_head eeprom_strings; /**< EEPROM STRING categories */
|
||||
struct list_head eeprom_syncs; /**< EEPROM SYNC MANAGER categories */
|
||||
struct list_head eeprom_pdos; /**< EEPROM [RT]XPDO categories */
|
||||
char *eeprom_group; /**< slave group acc. to EEPROM */
|
||||
char *eeprom_image; /**< slave image name acc. to EEPROM */
|
||||
char *eeprom_order; /**< slave order number acc. to EEPROM */
|
||||
char *eeprom_name; /**< slave name acc. to EEPROM */
|
||||
|
||||
uint16_t *new_eeprom_data; /**< new EEPROM data to write */
|
||||
size_t new_eeprom_size; /**< size of new EEPROM data in words */
|
||||
|
||||
struct list_head sdo_dictionary; /**< SDO directory list */
|
||||
|
||||
ec_slave_state_t requested_state; /**< requested slave state */
|
||||
ec_slave_state_t current_state; /**< current slave state */
|
||||
unsigned int error_flag; /**< stop processing after an error */
|
||||
unsigned int online; /**< non-zero, if the slave responds. */
|
||||
|
||||
struct list_head varsize_fields; /**< size information for variable-sized
|
||||
data fields. */
|
||||
};
|
||||
|
|
@ -305,32 +302,27 @@ struct ec_slave
|
|||
int ec_slave_init(ec_slave_t *, ec_master_t *, uint16_t, uint16_t);
|
||||
void ec_slave_clear(struct kobject *);
|
||||
|
||||
// slave control
|
||||
int ec_slave_fetch(ec_slave_t *);
|
||||
int ec_slave_sii_read16(ec_slave_t *, uint16_t, uint16_t *);
|
||||
int ec_slave_sii_read32(ec_slave_t *, uint16_t, uint32_t *);
|
||||
int ec_slave_sii_write16(ec_slave_t *, uint16_t, uint16_t);
|
||||
int ec_slave_state_change(ec_slave_t *, uint8_t);
|
||||
int ec_slave_prepare_fmmu(ec_slave_t *, const ec_domain_t *,
|
||||
const ec_sync_t *);
|
||||
const ec_sii_sync_t *);
|
||||
|
||||
// CoE
|
||||
int ec_slave_fetch_sdo_list(ec_slave_t *);
|
||||
//int ec_slave_fetch_sdo_list(ec_slave_t *);
|
||||
|
||||
// state machine
|
||||
// SII categories
|
||||
int ec_slave_fetch_strings(ec_slave_t *, const uint8_t *);
|
||||
int ec_slave_fetch_general(ec_slave_t *, const uint8_t *);
|
||||
void ec_slave_fetch_general(ec_slave_t *, const uint8_t *);
|
||||
int ec_slave_fetch_sync(ec_slave_t *, const uint8_t *, size_t);
|
||||
int ec_slave_fetch_pdo(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t);
|
||||
int ec_slave_fetch_pdo(ec_slave_t *, const uint8_t *, size_t,
|
||||
ec_sii_pdo_type_t);
|
||||
int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
|
||||
|
||||
// misc.
|
||||
size_t ec_slave_calc_sync_size(const ec_slave_t *, const ec_sync_t *);
|
||||
uint16_t ec_slave_calc_eeprom_sync_size(const ec_slave_t *,
|
||||
const ec_eeprom_sync_t *);
|
||||
uint16_t ec_slave_calc_sync_size(const ec_slave_t *,
|
||||
const ec_sii_sync_t *);
|
||||
|
||||
void ec_slave_print(const ec_slave_t *, unsigned int);
|
||||
int ec_slave_check_crc(ec_slave_t *);
|
||||
int ec_slave_is_coupler(const ec_slave_t *);
|
||||
//int ec_slave_check_crc(ec_slave_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
280
master/types.c
280
master/types.c
|
|
@ -1,280 +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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT slave descriptions.
|
||||
\cond
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "types.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_sync_t mailbox_sm0 = {0x1800, 246, 0x26, {NULL}};
|
||||
const ec_sync_t mailbox_sm1 = {0x18F6, 246, 0x22, {NULL}};
|
||||
|
||||
/******************************************************************************
|
||||
* slave objects
|
||||
*****************************************************************************/
|
||||
|
||||
const ec_slave_type_t Beckhoff_EK1100 = {
|
||||
"Beckhoff", "EK1100", "Bus Coupler", EC_TYPE_BUS_COUPLER,
|
||||
{NULL} // no sync managers
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_slave_type_t Beckhoff_EK1110 = {
|
||||
"Beckhoff", "EK1110", "Extension terminal", EC_TYPE_INFRA,
|
||||
{NULL} // no sync managers
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t bk1120_out = {"Outputs", 0}; // variable size
|
||||
const ec_field_t bk1120_in = {"Inputs", 0}; // variable size
|
||||
|
||||
const ec_sync_t bk1120_sm0 = {0x1C00, 264, 0x26, {NULL}};
|
||||
const ec_sync_t bk1120_sm1 = {0x1E00, 264, 0x22, {NULL}};
|
||||
|
||||
const ec_sync_t bk1120_sm2 = { // outputs
|
||||
0x1000, 0, 0x24, // variable size
|
||||
{&bk1120_out, NULL}
|
||||
};
|
||||
|
||||
const ec_sync_t bk1120_sm3 = { // inputs
|
||||
0x1600, 0, 0x00, // variable size
|
||||
{&bk1120_in, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_BK1120 = {
|
||||
"Beckhoff", "BK1120", "KBUS Coupler", EC_TYPE_NORMAL,
|
||||
{&bk1120_sm0, &bk1120_sm1, &bk1120_sm2, &bk1120_sm3, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el1004_in = {"InputValue", 1};
|
||||
|
||||
const ec_sync_t el1004_sm0 = { // inputs
|
||||
0x1000, 1, 0x00,
|
||||
{&el1004_in, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL1004 = {
|
||||
"Beckhoff", "EL1004", "4x Digital Input, 3ms", EC_TYPE_NORMAL,
|
||||
{&el1004_sm0, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el1014_in = {"InputValue", 1};
|
||||
|
||||
const ec_sync_t el1014_sm0 = { // inputs
|
||||
0x1000, 1, 0x00,
|
||||
{&el1014_in, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL1014 = {
|
||||
"Beckhoff", "EL1014", "4x Digital Input, 10us", EC_TYPE_NORMAL,
|
||||
{&el1014_sm0, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el20XX_out = {"OutputValue", 1};
|
||||
|
||||
const ec_sync_t el20XX_sm0 = {
|
||||
0x0F00, 1, 0x46,
|
||||
{&el20XX_out, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL2004 = {
|
||||
"Beckhoff", "EL2004", "4x Digital Output", EC_TYPE_NORMAL,
|
||||
{&el20XX_sm0, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL2032 = {
|
||||
"Beckhoff", "EL2032", "2x Digital Output (2A)", EC_TYPE_NORMAL,
|
||||
{&el20XX_sm0, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el31X2_st1 = {"Status", 1};
|
||||
const ec_field_t el31X2_ip1 = {"InputValue", 2};
|
||||
const ec_field_t el31X2_st2 = {"Status", 1};
|
||||
const ec_field_t el31X2_ip2 = {"InputValue", 2};
|
||||
|
||||
const ec_sync_t el31X2_sm2 = {0x1000, 4, 0x24, {NULL}};
|
||||
|
||||
const ec_sync_t el31X2_sm3 = {
|
||||
0x1100, 6, 0x20,
|
||||
{&el31X2_st1, &el31X2_ip1, &el31X2_st2, &el31X2_ip2, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL3102 = {
|
||||
"Beckhoff", "EL3102", "2x Analog Input diff.", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el31X2_sm2, &el31X2_sm3, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL3162 = {
|
||||
"Beckhoff", "EL3162", "2x Analog Input", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el31X2_sm2, &el31X2_sm3, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el41X2_op = {"OutputValue", 2};
|
||||
|
||||
const ec_sync_t el41X2_sm2 = {
|
||||
0x1000, 4, 0x24,
|
||||
{&el41X2_op, &el41X2_op, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL4102 = {
|
||||
"Beckhoff", "EL4102", "2x Analog Output", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el41X2_sm2, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL4132 = {
|
||||
"Beckhoff", "EL4132", "2x Analog Output diff.", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el41X2_sm2, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el5001_st = {"Status", 1};
|
||||
const ec_field_t el5001_ip = {"InputValue", 4};
|
||||
|
||||
const ec_sync_t el5001_sm2 = {
|
||||
0x1000, 4, 0x24,
|
||||
{NULL}
|
||||
};
|
||||
|
||||
const ec_sync_t el5001_sm3 = {
|
||||
0x1100, 5, 0x20,
|
||||
{&el5001_st, &el5001_ip, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL5001 = {
|
||||
"Beckhoff", "EL5001", "SSI-Interface", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el5001_sm2, &el5001_sm3, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t el5101_ct = {"Control", 1};
|
||||
const ec_field_t el5101_op = {"OutputValue", 2};
|
||||
const ec_field_t el5101_st = {"Status", 1};
|
||||
const ec_field_t el5101_ip = {"InputValue", 2};
|
||||
const ec_field_t el5101_la = {"LatchValue", 2};
|
||||
|
||||
const ec_sync_t el5101_sm2 = {
|
||||
0x1000, 3, 0x24,
|
||||
{&el5101_ct, &el5101_op, NULL}
|
||||
};
|
||||
|
||||
const ec_sync_t el5101_sm3 = {
|
||||
0x1100, 5, 0x20,
|
||||
{&el5101_st, &el5101_ip, &el5101_la, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL5101 = {
|
||||
"Beckhoff", "EL5101", "Incremental Encoder Interface", EC_TYPE_NORMAL,
|
||||
{&mailbox_sm0, &mailbox_sm1, &el5101_sm2, &el5101_sm3, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_sync_t el6601_sm0 = {0x1800, 522, 0x26, {NULL}};
|
||||
const ec_sync_t el6601_sm1 = {0x1C00, 522, 0x22, {NULL}};
|
||||
|
||||
const ec_slave_type_t Beckhoff_EL6601 = {
|
||||
"Beckhoff", "EL6601", "1-Port Ethernet Switch Terminal", EC_TYPE_EOE,
|
||||
{&el6601_sm0, &el6601_sm1, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const ec_field_t trlinenc2_st = {"Status", 1};
|
||||
const ec_field_t trlinenc2_ip = {"InputValue", 4};
|
||||
|
||||
const ec_sync_t trlinenc2_sm0 = {0x1800, 192, 0x26, {NULL}};
|
||||
const ec_sync_t trlinenc2_sm1 = {0x1C00, 192, 0x22, {NULL}};
|
||||
const ec_sync_t trlinenc2_sm2 = {0x1000, 4, 0x24, {NULL}};
|
||||
|
||||
const ec_sync_t trlinenc2_sm3 = {
|
||||
0x1100, 5, 0x20,
|
||||
{&trlinenc2_st, &trlinenc2_ip, NULL}
|
||||
};
|
||||
|
||||
const ec_slave_type_t TR_Electronic_LinEnc2 = {
|
||||
"TR-Electronic", "LinEnc2", "SSI-Encoder", EC_TYPE_NORMAL,
|
||||
{&trlinenc2_sm0, &trlinenc2_sm1, &trlinenc2_sm2, &trlinenc2_sm3, NULL}
|
||||
};
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Mapping between vendor IDs and product codes <=> slave objects.
|
||||
*/
|
||||
|
||||
ec_slave_ident_t slave_idents[] = {
|
||||
{0x00000002, 0x03EC3052, &Beckhoff_EL1004},
|
||||
{0x00000002, 0x03F63052, &Beckhoff_EL1014},
|
||||
{0x00000002, 0x044C2C52, &Beckhoff_EK1100},
|
||||
{0x00000002, 0x04562C52, &Beckhoff_EK1110},
|
||||
{0x00000002, 0x04602C22, &Beckhoff_BK1120},
|
||||
{0x00000002, 0x07D43052, &Beckhoff_EL2004},
|
||||
{0x00000002, 0x07F03052, &Beckhoff_EL2032},
|
||||
{0x00000002, 0x0C1E3052, &Beckhoff_EL3102},
|
||||
{0x00000002, 0x0C5A3052, &Beckhoff_EL3162},
|
||||
{0x00000002, 0x10063052, &Beckhoff_EL4102},
|
||||
{0x00000002, 0x10243052, &Beckhoff_EL4132},
|
||||
{0x00000002, 0x13893052, &Beckhoff_EL5001},
|
||||
{0x00000002, 0x13ED3052, &Beckhoff_EL5101},
|
||||
{0x00000002, 0x19C93052, &Beckhoff_EL6601},
|
||||
{0x000000D4, 0x00000017, &TR_Electronic_LinEnc2},
|
||||
{}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
130
master/types.h
130
master/types.h
|
|
@ -1,130 +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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
EtherCAT slave types.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _EC_TYPES_H_
|
||||
#define _EC_TYPES_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define EC_MAX_FIELDS 10 /**< maximal number of data fields per sync manager */
|
||||
#define EC_MAX_SYNC 16 /**< maximal number of sync managers per type */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Special slaves.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EC_TYPE_NORMAL, /**< no special slave */
|
||||
EC_TYPE_BUS_COUPLER, /**< slave is a bus coupler */
|
||||
EC_TYPE_INFRA, /**< infrastructure slaves, that contain no process data */
|
||||
EC_TYPE_EOE /**< slave is an EoE switch */
|
||||
}
|
||||
ec_special_type_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Process data field.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name; /**< field name */
|
||||
size_t size; /**< field size in bytes */
|
||||
}
|
||||
ec_field_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Sync manager.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t physical_start_address; /**< physical start address */
|
||||
uint16_t size; /**< size in bytes */
|
||||
uint8_t control_byte; /**< control register value */
|
||||
const ec_field_t *fields[EC_MAX_FIELDS]; /**< field array */
|
||||
}
|
||||
ec_sync_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Slave description type.
|
||||
*/
|
||||
|
||||
typedef struct ec_slave_type
|
||||
{
|
||||
const char *vendor_name; /**< vendor name*/
|
||||
const char *product_name; /**< product name */
|
||||
const char *description; /**< free description */
|
||||
ec_special_type_t special; /**< special slave type? */
|
||||
const ec_sync_t *sync_managers[EC_MAX_SYNC]; /**< sync managers */
|
||||
}
|
||||
ec_slave_type_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Slave type identification.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t vendor_id; /**< vendor id */
|
||||
uint32_t product_code; /**< product code */
|
||||
const ec_slave_type_t *type; /**< associated slave description object */
|
||||
}
|
||||
ec_slave_ident_t;
|
||||
|
||||
extern ec_slave_ident_t slave_idents[]; /**< array with slave descriptions */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -163,7 +163,7 @@ case "$1" in
|
|||
fi
|
||||
|
||||
# unload conflicting modules at first
|
||||
for mod in 8139too 8139cp; do
|
||||
for mod in 8139too; do
|
||||
if lsmod | grep "^$mod " > /dev/null; then
|
||||
if ! rmmod $mod; then
|
||||
/bin/false
|
||||
|
|
@ -175,6 +175,7 @@ case "$1" in
|
|||
|
||||
# load master module
|
||||
if ! modprobe ec_master ec_eoeif_count=$EOE_INTERFACES; then
|
||||
modprobe 8139too
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
|
|
@ -182,6 +183,8 @@ case "$1" in
|
|||
|
||||
# load device module
|
||||
if ! modprobe ec_8139too ec_device_index=$DEVICE_INDEX; then
|
||||
rmmod ec_master
|
||||
modprobe 8139too
|
||||
/bin/false
|
||||
rc_status -v
|
||||
rc_exit
|
||||
|
|
|
|||
115
script/lsec.pl
115
script/lsec.pl
|
|
@ -42,7 +42,6 @@ use Getopt::Std;
|
|||
|
||||
my $master_index;
|
||||
my $master_dir;
|
||||
my $show_sii_naming;
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -63,45 +62,43 @@ sub query_master
|
|||
sub query_slaves
|
||||
{
|
||||
my $dirhandle;
|
||||
my $slave_dir;
|
||||
my $entry;
|
||||
my $slave_index;
|
||||
my $file_name;
|
||||
my $vendor_name;
|
||||
my @slaves;
|
||||
my $slave;
|
||||
my $abs;
|
||||
my $line;
|
||||
|
||||
unless (opendir $dirhandle, $master_dir) {
|
||||
print "Failed to open directory \"$master_dir\".\n";
|
||||
exit 1;
|
||||
print "Failed to open directory \"$master_dir\".\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
while ($entry = readdir $dirhandle) {
|
||||
next unless $entry =~ /^slave(\d+)$/;
|
||||
$slave_dir = $master_dir . "/" . $entry;
|
||||
|
||||
$slave = {};
|
||||
$slave->{'ring_position'} =
|
||||
&read_integer("$slave_dir/ring_position");
|
||||
$slave->{'advanced_position'} =
|
||||
&read_string("$slave_dir/advanced_position");
|
||||
unless ($show_sii_naming) {
|
||||
$slave->{'vendor_name'} =
|
||||
&read_string("$slave_dir/vendor_name");
|
||||
$slave->{'product_name'} =
|
||||
&read_string("$slave_dir/product_name");
|
||||
$slave->{'product_desc'} =
|
||||
&read_string("$slave_dir/product_desc");
|
||||
}
|
||||
else {
|
||||
$slave->{'name'} =
|
||||
&read_string("$slave_dir/name");
|
||||
}
|
||||
$slave->{'type'} =
|
||||
&read_string("$slave_dir/type");
|
||||
$slave = {};
|
||||
|
||||
push @slaves, $slave;
|
||||
open INFO, "$master_dir/$entry/info" or die
|
||||
"ERROR: Failed to open $master_dir/$entry/info";
|
||||
|
||||
while ($line = <INFO>) {
|
||||
if ($line =~ /^Name: (.*)$/) {
|
||||
$slave->{'name'} = $1;
|
||||
}
|
||||
elsif ($line =~ /^Ring position: (\d+)$/) {
|
||||
$slave->{'ring_position'} = $1;
|
||||
}
|
||||
elsif ($line =~ /^Advanced position: (\d+:\d+)$/) {
|
||||
$slave->{'advanced_position'} = $1;
|
||||
}
|
||||
elsif ($line =~ /^State: (.+)$/) {
|
||||
$slave->{'state'} = $1;
|
||||
}
|
||||
}
|
||||
|
||||
close INFO;
|
||||
|
||||
push @slaves, $slave;
|
||||
}
|
||||
closedir $dirhandle;
|
||||
|
||||
|
|
@ -109,82 +106,40 @@ sub query_slaves
|
|||
|
||||
print "EtherCAT bus listing for master $master_index:\n";
|
||||
for $slave (@slaves) {
|
||||
if ($slave->{'type'} eq "coupler") {
|
||||
print "--------------------------------------------------------\n";
|
||||
}
|
||||
|
||||
$abs = sprintf "%i", $slave->{'ring_position'};
|
||||
printf(" %3s %8s ", $abs, $slave->{'advanced_position'});
|
||||
unless ($show_sii_naming) {
|
||||
printf("%-12s %-10s %s\n", $slave->{'vendor_name'},
|
||||
$slave->{'product_name'}, $slave->{'product_desc'});
|
||||
}
|
||||
else {
|
||||
printf("%s\n", $slave->{'name'});
|
||||
}
|
||||
$abs = sprintf "%i", $slave->{'ring_position'};
|
||||
printf(" %3s %8s %-6s %s\n",
|
||||
$abs, $slave->{'advanced_position'},
|
||||
$slave->{'state'}, $slave->{'name'});
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
sub read_string
|
||||
{
|
||||
(my $file_name) = @_;
|
||||
my $data;
|
||||
|
||||
$data = `cat $file_name 2>/dev/null`;
|
||||
if ($?) {
|
||||
print "ERROR: Unable to read string $file_name!\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
chomp $data;
|
||||
return $data;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
sub read_integer
|
||||
{
|
||||
(my $file_name) = @_;
|
||||
|
||||
if (`cat $file_name 2>/dev/null` !~ /^(\d+)$/) {
|
||||
print "ERROR: Unable to read integer $file_name!\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
return int $1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
sub get_options
|
||||
{
|
||||
my %opt;
|
||||
my $optret;
|
||||
|
||||
$optret = getopts "m:sh", \%opt;
|
||||
$optret = getopts "m:h", \%opt;
|
||||
|
||||
&print_usage if defined $opt{'h'} or $#ARGV > -1 or !$optret;
|
||||
|
||||
if (defined $opt{'m'}) {
|
||||
$master_index = $opt{'m'};
|
||||
$master_index = $opt{'m'};
|
||||
}
|
||||
else {
|
||||
$master_index = 0;
|
||||
$master_index = 0;
|
||||
}
|
||||
|
||||
$show_sii_naming = defined $opt{'s'};
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
sub print_usage
|
||||
{
|
||||
print "Usage: $0 [OPTIONS]\n";
|
||||
my $cmd = `basename $0`;
|
||||
chomp $cmd;
|
||||
print "Usage: $cmd [OPTIONS]\n";
|
||||
print " -m <IDX> Query master <IDX>.\n";
|
||||
print " -s Show EEPROM name instead of";
|
||||
print " vendor/product/description.\n";
|
||||
print " -h Show this help.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue