# HG changeset patch # User Martin Troxler # Date 1273579078 -7200 # Node ID 6aa393418fb37c68cbfba9e3c118b030036914fd # Parent ea38efeeb7b3b53099fa584cc0dfeb31ad670a75# Parent 365a90e931616c979a6d14a68bb12f7b74ef7f8a merged diff -r 365a90e93161 -r 6aa393418fb3 include/ecrt.h --- a/include/ecrt.h Thu May 06 11:56:35 2010 +0200 +++ b/include/ecrt.h Tue May 11 13:57:58 2010 +0200 @@ -5,7 +5,7 @@ * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT master userspace library. - * + * * The IgH EtherCAT master userspace library is free software; you can * redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; version 2.1 @@ -19,9 +19,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with the IgH EtherCAT master userspace library. If not, see * . - * + * * --- - * + * * The license mentioned above concerns the source code only. Using the * EtherCAT technology and brand is only permitted in compliance with the * industrial property and similar rights of Beckhoff Automation GmbH. @@ -47,7 +47,7 @@ * ecrt_master_sync_slave_clocks() for offset and drift compensation. The * EC_TIMEVAL2NANO() macro can be used for epoch time conversion, while the * ecrt_master_sync_monitor_queue() and ecrt_master_sync_monitor_process() - * methods can be used to monitor the synchrony. + * methods can be used to monitor the synchrony. * - Improved the callback mechanism. ecrt_master_callbacks() now takes two * callback functions for sending and receiving datagrams. * ecrt_master_send_ext() is used to execute the sending of non-application @@ -78,6 +78,9 @@ * - Added ecrt_slave_config_idn() method for storing SoE IDN configurations, * and ecrt_master_read_idn() and ecrt_master_write_idn() to read/write IDNs * ad-hoc via the user-space library. + * - Added support for overlapping PDOs which allows inputs to use the same + * space as outputs on the frame. This reduces the frame length. + * * * @{ */ @@ -135,6 +138,9 @@ */ #define EC_MAX_STRING_LENGTH 64 +/** Maximum number of slave ports. */ +#define EC_MAX_PORTS 4 + /** Timeval to nanoseconds conversion. * * This macro converts a Unix epoch time to EtherCAT DC time. @@ -147,7 +153,7 @@ (((TV).tv_sec - 946684800ULL) * 1000000000ULL + (TV).tv_usec * 1000ULL) /****************************************************************************** - * Data types + * Data types *****************************************************************************/ struct ec_master; @@ -192,7 +198,7 @@ /** Slave configuration state. * * This is used as an output parameter of ecrt_slave_config_state(). - * + * * \see ecrt_slave_config_state(). */ typedef struct { @@ -220,12 +226,33 @@ typedef struct { unsigned int slave_count; /**< Number of slaves in the bus. */ unsigned int link_up : 1; /**< \a true, if the network link is up. */ - uint8_t scan_busy; /**< \a true, while the master is scanning the bus */ + uint8_t scan_busy; /**< \a true, while the master is scanning the bus */ uint64_t app_time; /**< Application time. */ } ec_master_info_t; /*****************************************************************************/ +/** EtherCAT slave port descriptor. + */ +typedef enum { + EC_PORT_NOT_IMPLEMENTED, /**< Port is not implemented. */ + EC_PORT_NOT_CONFIGURED, /**< Port is not configured. */ + EC_PORT_EBUS, /**< Port is an e-bus. */ + EC_PORT_MII /**< Port is a mii. */ +} ec_slave_port_desc_t; + +/*****************************************************************************/ + +/** EtherCAT slave port information. + */ +typedef struct { + uint8_t link_up; /**< Link detected. */ + uint8_t loop_closed; /**< Loop closed. */ + uint8_t signal_detected; /**< Detected signal on RX port. */ +} ec_slave_port_link_t; + +/*****************************************************************************/ + /** Slave information. * * This is used as an output parameter of ecrt_master_get_slave(). @@ -240,6 +267,13 @@ uint32_t serial_number; /**< Serial-Number stored on the slave. */ uint16_t alias; /**< The slaves alias if not equal to 0. */ int16_t current_on_ebus; /**< Used current in mA. */ + struct { + ec_slave_port_desc_t desc; + ec_slave_port_link_t link; + uint32_t receive_time; + uint16_t next_slave; + uint32_t delay_to_next_dc; + } ports[EC_MAX_PORTS]; uint8_t al_state; /**< Current state of the slave. */ uint8_t error_flag; /**< Error flag for that slave. */ uint8_t sync_count; /**< Number of sync managers. */ @@ -311,9 +345,9 @@ /*****************************************************************************/ /** PDO configuration information. - * + * * This is the data type of the \a pdos field in ec_sync_info_t. - * + * * \see ecrt_slave_config_pdos(). */ typedef struct { @@ -362,7 +396,7 @@ uint8_t subindex; /**< PDO entry subindex. */ unsigned int *offset; /**< Pointer to a variable to store the PDO entry's (byte-)offset in the process data. */ - unsigned int *bit_position; /**< Pointer to a variable to store a bit + unsigned int *bit_position; /**< Pointer to a variable to store a bit position (0-7) within the \a offset. Can be NULL, in which case an error is raised if the PDO entry does not byte-align. */ @@ -397,7 +431,7 @@ unsigned int ecrt_version_magic(void); /** Requests an EtherCAT master for realtime operation. - * + * * Before an application can access an EtherCAT master, it has to reserve one * for exclusive use. * @@ -788,17 +822,29 @@ ec_master_state_t *state /**< Structure to store the information. */ ); +/** Reads the current master state and the al_state of all configured slaves. + * + * use this function instead of ecrt_master_state if there are unused + * slaves on the bus + * Stores the master state information in the given \a state structure. + * \see ecrt_master_state() + */ +void ecrt_master_configured_slaves_state( + const ec_master_t *master, /**< EtherCAT master. */ + ec_master_state_t *state /**< Structure to store the information. */ + ); + /** Sets the application time. * * The master has to know the application's time when operating slaves with * distributed clocks. The time is not incremented by the master itself, so * this method has to be called cyclically. - * + * * The time is used when setting the slaves' System Time Offset and * Cyclic Operation Start Time registers and when synchronizing the * DC reference clock to the application time via * ecrt_master_sync_reference_clock(). - * + * * The time is defined as nanoseconds from 2000-01-01 00:00. Converting an * epoch time can be done with the EC_TIMEVAL2NANO() macro. */ @@ -879,6 +925,17 @@ */ ); +/** Configure wether a slave allows overlapping PDOs. + * + * Overlapping PDOs allows inputs to use the same space as outputs on the frame. + * This reduces the frame length. + */ +void ecrt_slave_config_overlapping_pdos( + ec_slave_config_t *sc, /**< Slave configuration. */ + uint8_t allow_overlapping_pdos /**< Allow overlapping PDOs */ + ); + + /** Add a PDO to a sync manager's PDO assignment. * * \see ecrt_slave_config_pdos() @@ -896,7 +953,7 @@ * This can be called before assigning PDOs via * ecrt_slave_config_pdo_assign_add(), to clear the default assignment of a * sync manager. - * + * * \see ecrt_slave_config_pdos() */ void ecrt_slave_config_pdo_assign_clear( @@ -950,28 +1007,28 @@ * {0x3101, 1, 8}, // status * {0x3101, 2, 16} // value * }; - * + * * ec_pdo_entry_info_t el3162_channel2[] = { * {0x3102, 1, 8}, // status * {0x3102, 2, 16} // value * }; - * + * * ec_pdo_info_t el3162_pdos[] = { * {0x1A00, 2, el3162_channel1}, * {0x1A01, 2, el3162_channel2} * }; - * + * * ec_sync_info_t el3162_syncs[] = { * {2, EC_DIR_OUTPUT}, * {3, EC_DIR_INPUT, 2, el3162_pdos}, * {0xff} * }; - * + * * if (ecrt_slave_config_pdos(sc_ana_in, EC_END, el3162_syncs)) { * // handle error * } * \endcode - * + * * The next example shows, how to configure the PDO assignment only. The * entries for each assigned PDO are taken from the PDO's default mapping. * Please note, that PDO entry registration will fail, if the PDO @@ -982,11 +1039,11 @@ * {0x1600}, // Channel 1 * {0x1601} // Channel 2 * }; - * + * * ec_sync_info_t syncs[] = { * {3, EC_DIR_INPUT, 2, pdos}, * }; - * + * * if (ecrt_slave_config_pdos(slave_config_ana_in, 1, syncs)) { * // handle error * } @@ -1028,7 +1085,7 @@ uint16_t entry_index, /**< Index of the PDO entry to register. */ uint8_t entry_subindex, /**< Subindex of the PDO entry to register. */ ec_domain_t *domain, /**< Domain. */ - unsigned int *bit_position /**< Optional address if bit addressing + unsigned int *bit_position /**< Optional address if bit addressing is desired */ ); diff -r 365a90e93161 -r 6aa393418fb3 lib/master.c --- a/lib/master.c Thu May 06 11:56:35 2010 +0200 +++ b/lib/master.c Tue May 11 13:57:58 2010 +0200 @@ -1,11 +1,11 @@ /****************************************************************************** - * + * * $Id$ - * + * * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH - * + * * This file is part of the IgH EtherCAT master userspace library. - * + * * The IgH EtherCAT master userspace library is free software; you can * redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; version 2.1 @@ -19,9 +19,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with the IgH EtherCAT master userspace library. If not, see * . - * + * * --- - * + * * The license mentioned above concerns the source code only. Using the * EtherCAT technology and brand is only permitted in compliance with the * industrial property and similar rights of Beckhoff Automation GmbH. @@ -63,12 +63,12 @@ fprintf(stderr, "Failed to allocate memory.\n"); return 0; } - + index = ioctl(master->fd, EC_IOCTL_CREATE_DOMAIN, NULL); if (index == -1) { fprintf(stderr, "Failed to create domain: %s\n", strerror(errno)); free(domain); - return 0; + return 0; } domain->index = (unsigned int) index; @@ -92,17 +92,17 @@ fprintf(stderr, "Failed to allocate memory.\n"); return 0; } - + data.alias = alias; data.position = position; data.vendor_id = vendor_id; data.product_code = product_code; - + if (ioctl(master->fd, EC_IOCTL_CREATE_SLAVE_CONFIG, &data) == -1) { fprintf(stderr, "Failed to create slave config: %s\n", strerror(errno)); free(sc); - return 0; + return 0; } sc->master = master; @@ -136,7 +136,7 @@ ec_slave_info_t *slave_info) { ec_ioctl_slave_t data; - int index; + int index, i; data.position = slave_position; @@ -152,6 +152,15 @@ slave_info->serial_number = data.serial_number; slave_info->alias = data.alias; slave_info->current_on_ebus = data.current_on_ebus; + for ( i = 0; i < EC_MAX_PORTS; i++ ) { + slave_info->ports[i].desc = data.ports[i].desc; + slave_info->ports[i].link.link_up = data.ports[i].link.link_up; + slave_info->ports[i].link.loop_closed = data.ports[i].link.loop_closed; + slave_info->ports[i].link.signal_detected = data.ports[i].link.signal_detected; + slave_info->ports[i].receive_time = data.ports[i].receive_time; + slave_info->ports[i].next_slave = data.ports[i].next_slave; + slave_info->ports[i].delay_to_next_dc = data.ports[i].delay_to_next_dc; + } slave_info->al_state = data.al_state; slave_info->error_flag = data.error_flag; slave_info->sync_count = data.sync_count; @@ -372,7 +381,7 @@ } // Access the mapped region to cause the initial page fault - printf("pd: %x\n", master->process_data[0]); + memset(master->process_data, 0, master->process_data_size); } return 0; @@ -432,6 +441,16 @@ /*****************************************************************************/ +void ecrt_master_configured_slaves_state(const ec_master_t *master, + ec_master_state_t *state) +{ + if (ioctl(master->fd, EC_IOCTL_MASTER_SC_STATE, state) == -1) { + fprintf(stderr, "Failed to get master state: %s\n", strerror(errno)); + } +} + +/*****************************************************************************/ + void ecrt_master_application_time(ec_master_t *master, uint64_t app_time) { ec_ioctl_app_time_t data; diff -r 365a90e93161 -r 6aa393418fb3 lib/slave_config.c --- a/lib/slave_config.c Thu May 06 11:56:35 2010 +0200 +++ b/lib/slave_config.c Tue May 11 13:57:58 2010 +0200 @@ -87,6 +87,23 @@ /*****************************************************************************/ +void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc, + uint8_t allow_overlapping_pdos) +{ + ec_ioctl_config_t data; + + memset(&data, 0x00, sizeof(ec_ioctl_config_t)); + data.config_index = sc->index; + data.allow_overlapping_pdos = allow_overlapping_pdos; + + if (ioctl(sc->master->fd, EC_IOCTL_SC_OVERLAPPING_IO, &data) == -1) { + fprintf(stderr, "Failed to config overlapping PDOs: %s\n", + strerror(errno)); + } +} + +/*****************************************************************************/ + int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc, uint8_t sync_index, uint16_t pdo_index) { diff -r 365a90e93161 -r 6aa393418fb3 master/cdev.c --- a/master/cdev.c Thu May 06 11:56:35 2010 +0200 +++ b/master/cdev.c Tue May 11 13:57:58 2010 +0200 @@ -539,6 +539,7 @@ } data.data_size = domain->data_size; + data.tx_size = domain->tx_size; data.logical_base_address = domain->logical_base_address; data.working_counter = domain->working_counter; data.expected_working_counter = domain->expected_working_counter; @@ -592,6 +593,7 @@ data.sync_index = fmmu->sync_index; data.dir = fmmu->dir; data.logical_address = fmmu->logical_start_address; + data.domain_address = fmmu->domain_address; data.data_size = fmmu->data_size; up(&master->master_sem); @@ -1814,6 +1816,29 @@ /*****************************************************************************/ +/** Get the master state of all configured slaves. + */ +int ec_cdev_ioctl_master_sc_state( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_master_state_t data; + + if (unlikely(!priv->requested)) + return -EPERM; + + ecrt_master_configured_slaves_state(master, &data); + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + +/*****************************************************************************/ + /** Get the master state. */ int ec_cdev_ioctl_app_time( @@ -2011,6 +2036,50 @@ return ret; } + +/*****************************************************************************/ + +/** Configure wether a slave allows overlapping PDOs. + */ +int ec_cdev_ioctl_sc_allow_overlapping_pdos( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_config_t data; + ec_slave_config_t *sc; + int ret = 0; + + if (unlikely(!priv->requested)) { + ret = -EPERM; + goto out_return; + } + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + ret = -EFAULT; + goto out_return; + } + + if (down_interruptible(&master->master_sem)) { + ret = -EINTR; + goto out_return; + } + + if (!(sc = ec_master_get_config(master, data.config_index))) { + ret = -ENOENT; + goto out_up; + } + + ecrt_slave_config_overlapping_pdos(sc, + data.allow_overlapping_pdos); + +out_up: + up(&master->master_sem); +out_return: + return ret; +} + /*****************************************************************************/ /** Add a PDO to the assignment. @@ -3660,6 +3729,8 @@ return ec_cdev_ioctl_receive(master, arg, priv); case EC_IOCTL_MASTER_STATE: return ec_cdev_ioctl_master_state(master, arg, priv); + case EC_IOCTL_MASTER_SC_STATE: + return ec_cdev_ioctl_master_sc_state(master, arg, priv); case EC_IOCTL_APP_TIME: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; @@ -3688,6 +3759,10 @@ if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; return ec_cdev_ioctl_sc_watchdog(master, arg, priv); + case EC_IOCTL_SC_OVERLAPPING_IO: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_sc_allow_overlapping_pdos(master,arg,priv); case EC_IOCTL_SC_ADD_PDO: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; diff -r 365a90e93161 -r 6aa393418fb3 master/datagram.c --- a/master/datagram.c Thu May 06 11:56:35 2010 +0200 +++ b/master/datagram.c Tue May 11 13:57:58 2010 +0200 @@ -94,6 +94,7 @@ datagram->data_origin = EC_ORIG_INTERNAL; datagram->mem_size = 0; datagram->data_size = 0; + datagram->domain = NULL; datagram->index = 0x00; datagram->working_counter = 0x0000; datagram->state = EC_DATAGRAM_INIT; diff -r 365a90e93161 -r 6aa393418fb3 master/datagram.h --- a/master/datagram.h Thu May 06 11:56:35 2010 +0200 +++ b/master/datagram.h Tue May 11 13:57:58 2010 +0200 @@ -94,6 +94,7 @@ ec_origin_t data_origin; /**< Origin of the \a data memory. */ size_t mem_size; /**< Datagram \a data memory size. */ size_t data_size; /**< Size of the data in \a data. */ + ec_domain_t *domain; /**< Owning domain (may be null for non-domain datagrams) */ uint8_t index; /**< Index (set by master). */ uint16_t working_counter; /**< Working counter. */ ec_datagram_state_t state; /**< State. */ diff -r 365a90e93161 -r 6aa393418fb3 master/domain.c --- a/master/domain.c Thu May 06 11:56:35 2010 +0200 +++ b/master/domain.c Tue May 11 13:57:58 2010 +0200 @@ -60,6 +60,7 @@ domain->index = index; INIT_LIST_HEAD(&domain->fmmu_configs); domain->data_size = 0; + domain->tx_size = 0; domain->data = NULL; domain->data_origin = EC_ORIG_INTERNAL; domain->logical_base_address = 0x00000000; @@ -113,6 +114,7 @@ fmmu->domain = domain; domain->data_size += fmmu->data_size; + domain->tx_size += fmmu->tx_size; list_add_tail(&fmmu->list, &domain->fmmu_configs); EC_MASTER_DBG(domain->master, 1, "Domain %u:" @@ -179,6 +181,7 @@ ec_datagram_zero(datagram); list_add_tail(&datagram->list, &domain->datagrams); + datagram->domain = domain; return 0; } @@ -238,6 +241,7 @@ list_for_each_entry(fmmu, &domain->fmmu_configs, list) { // Correct logical FMMU address fmmu->logical_start_address += base_address; + fmmu->domain_address += base_address; // Increment Input/Output counter to determine datagram types // and calculate expected working counters @@ -249,7 +253,7 @@ // If the current FMMU's data do not fit in the current datagram, // allocate a new one. - if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) { + if (datagram_size + fmmu->tx_size > EC_MAX_DATA_SIZE) { ret = ec_domain_add_datagram(domain, domain->logical_base_address + datagram_offset, datagram_size, domain->data + datagram_offset, @@ -267,7 +271,7 @@ } } - datagram_size += fmmu->data_size; + datagram_size += fmmu->tx_size; } // Allocate last datagram, if data are left (this is also the case if the diff -r 365a90e93161 -r 6aa393418fb3 master/domain.h --- a/master/domain.h Thu May 06 11:56:35 2010 +0200 +++ b/master/domain.h Tue May 11 13:57:58 2010 +0200 @@ -59,6 +59,7 @@ struct list_head fmmu_configs; /**< FMMU configurations contained. */ size_t data_size; /**< Size of the process data. */ + size_t tx_size; /**< Size of the transmitted data. */ uint8_t *data; /**< Memory for the process data. */ ec_origin_t data_origin; /**< Origin of the \a data memory. */ uint32_t logical_base_address; /**< Logical offset address of the diff -r 365a90e93161 -r 6aa393418fb3 master/fmmu_config.c --- a/master/fmmu_config.c Thu May 06 11:56:35 2010 +0200 +++ b/master/fmmu_config.c Tue May 11 13:57:58 2010 +0200 @@ -43,14 +43,12 @@ /** FMMU configuration constructor. * - * Inits an FMMU configuration, sets the logical start address and adds the - * process data size for the mapped PDOs of the given direction to the domain - * data size. + * Inits an FMMU configuration and the process data size forthe mapped PDOs + * of the given direction to the domain data size. */ void ec_fmmu_config_init( ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */ ec_slave_config_t *sc, /**< EtherCAT slave configuration. */ - ec_domain_t *domain, /**< EtherCAT domain. */ uint8_t sync_index, /**< Sync manager index to use. */ ec_direction_t dir /**< PDO direction. */ ) @@ -59,14 +57,32 @@ fmmu->sc = sc; fmmu->sync_index = sync_index; fmmu->dir = dir; - - fmmu->logical_start_address = domain->data_size; fmmu->data_size = ec_pdo_list_total_size( &sc->sync_configs[sync_index].pdos); +} + +/*****************************************************************************/ + +/** Sets FMMU domain + * + * Sets the logical start address and the size of the transmitted data + */ +void ec_fmmu_config_domain( + ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */ + ec_domain_t *domain, /**< EtherCAT domain. */ + uint32_t logical_start_address, /**< FMMU logical start address. */ + size_t tx_size /**< Size of transmitted data */ + ) +{ + fmmu->domain = domain; + fmmu->domain_address = domain->data_size; + fmmu->logical_start_address = logical_start_address; + fmmu->tx_size = tx_size; ec_domain_add_fmmu_config(domain, fmmu); } + /*****************************************************************************/ /** Initializes an FMMU configuration page. @@ -79,9 +95,11 @@ uint8_t *data /**> Configuration page memory. */ ) { - EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, Size %3u," + EC_CONFIG_DBG(fmmu->sc, 1, "FMMU: LogAddr 0x%08X, DomAddr 0x%08X," + " Size %3u, Tx %3u" " PhysAddr 0x%04X, SM%u, Dir %s\n", - fmmu->logical_start_address, fmmu->data_size, + fmmu->logical_start_address, fmmu->domain_address, + fmmu->data_size, fmmu->data_size, sync->physical_start_address, fmmu->sync_index, fmmu->dir == EC_DIR_INPUT ? "in" : "out"); diff -r 365a90e93161 -r 6aa393418fb3 master/fmmu_config.h --- a/master/fmmu_config.h Thu May 06 11:56:35 2010 +0200 +++ b/master/fmmu_config.h Tue May 11 13:57:58 2010 +0200 @@ -50,13 +50,18 @@ uint8_t sync_index; /**< Index of sync manager to use. */ ec_direction_t dir; /**< FMMU direction. */ uint32_t logical_start_address; /**< Logical start address. */ + size_t tx_size; /**< Transmitted (bus) size. */ + uint32_t domain_address; /** Domain start address */ unsigned int data_size; /**< Covered PDO size. */ } ec_fmmu_config_t; /*****************************************************************************/ void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *, - ec_domain_t *, uint8_t, ec_direction_t); + uint8_t, ec_direction_t); + +void ec_fmmu_config_domain(ec_fmmu_config_t *, ec_domain_t *, + uint32_t , size_t); void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *, uint8_t *); diff -r 365a90e93161 -r 6aa393418fb3 master/fsm_master.c --- a/master/fsm_master.c Thu May 06 11:56:35 2010 +0200 +++ b/master/fsm_master.c Tue May 11 13:57:58 2010 +0200 @@ -890,25 +890,26 @@ ec_fsm_master_t *fsm, /**< Master state machine. */ u64 system_time, /**< System time register. */ u64 old_offset, /**< Time offset register. */ - unsigned long jiffies_since_read /**< Jiffies for correction. */ + u64 correction /**< Correction. */ ) { ec_slave_t *slave = fsm->slave; - u32 correction, system_time32, old_offset32, new_offset; + u32 correction32, system_time32, old_offset32, new_offset; s32 time_diff; - system_time32 = (u32) system_time; - old_offset32 = (u32) old_offset; - - // correct read system time by elapsed time since read operation - correction = jiffies_since_read * 1000 / HZ * 1000000; - system_time32 += correction; + system_time32 = (u32) system_time; + // correct read system time by elapsed time between read operation + // and app_time set time + correction32 = (u32)correction; + system_time32 -= correction32; + old_offset32 = (u32) old_offset; + time_diff = (u32) slave->master->app_time - system_time32; EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:" " system_time=%u (corrected with %u)," " app_time=%u, diff=%i\n", - system_time32, correction, + system_time32, correction32, (u32) slave->master->app_time, time_diff); if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) { @@ -930,17 +931,17 @@ ec_fsm_master_t *fsm, /**< Master state machine. */ u64 system_time, /**< System time register. */ u64 old_offset, /**< Time offset register. */ - unsigned long jiffies_since_read /**< Jiffies for correction. */ + u64 correction /**< Correction. */ ) { ec_slave_t *slave = fsm->slave; - u64 new_offset, correction; + u64 new_offset; s64 time_diff; - // correct read system time by elapsed time since read operation - correction = (u64) (jiffies_since_read * 1000 / HZ) * 1000000; - system_time += correction; - time_diff = fsm->slave->master->app_time - system_time; + // correct read system time by elapsed time between read operation + // and app_time set time + system_time -= correction; + time_diff = fsm->slave->master->app_time - system_time; EC_SLAVE_DBG(slave, 1, "DC system time offset calculation:" " system_time=%llu (corrected with %llu)," @@ -970,8 +971,7 @@ { ec_datagram_t *datagram = fsm->datagram; ec_slave_t *slave = fsm->slave; - u64 system_time, old_offset, new_offset; - unsigned long jiffies_since_read; + u64 system_time, old_offset, new_offset, correction; if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) return; @@ -994,14 +994,25 @@ system_time = EC_READ_U64(datagram->data); // 0x0910 old_offset = EC_READ_U64(datagram->data + 16); // 0x0920 - jiffies_since_read = jiffies - datagram->jiffies_sent; + /* correct read system time by elapsed time since read operation + and the app_time set time */ +#ifdef EC_HAVE_CYCLES + correction = + (datagram->cycles_sent - slave->master->dc_cycles_app_time) + * 1000000LL; + do_div(correction,cpu_khz); +#else + correction = + (u64) ((datagram->jiffies_sent-slave->master->dc_jiffies_app_time) * 1000 / HZ) + * 1000000; +#endif if (slave->base_dc_range == EC_DC_32) { new_offset = ec_fsm_master_dc_offset32(fsm, - system_time, old_offset, jiffies_since_read); + system_time, old_offset, correction); } else { new_offset = ec_fsm_master_dc_offset64(fsm, - system_time, old_offset, jiffies_since_read); + system_time, old_offset, correction); } // set DC system time offset and transmission delay diff -r 365a90e93161 -r 6aa393418fb3 master/globals.h --- a/master/globals.h Thu May 06 11:56:35 2010 +0200 +++ b/master/globals.h Tue May 11 13:57:58 2010 +0200 @@ -97,9 +97,6 @@ /** Word offset of first SII category. */ #define EC_FIRST_SII_CATEGORY_OFFSET 0x40 -/** Maximum number of slave ports. */ -#define EC_MAX_PORTS 4 - /** Size of a sync manager configuration page. */ #define EC_SYNC_PAGE_SIZE 8 @@ -173,23 +170,6 @@ uint8_t enable_not_lrw : 1; /**< Slave does not support LRW. */ } ec_sii_general_flags_t; -/** EtherCAT slave port descriptor. - */ -typedef enum { - EC_PORT_NOT_IMPLEMENTED, - EC_PORT_NOT_CONFIGURED, - EC_PORT_EBUS, - EC_PORT_MII -} ec_slave_port_desc_t; - -/** EtherCAT slave port information. - */ -typedef struct { - uint8_t link_up; /**< Link detected. */ - uint8_t loop_closed; /**< Loop closed. */ - uint8_t signal_detected; /**< Detected signal on RX port. */ -} ec_slave_port_link_t; - /** EtherCAT slave distributed clocks range. */ typedef enum { diff -r 365a90e93161 -r 6aa393418fb3 master/ioctl.h --- a/master/ioctl.h Thu May 06 11:56:35 2010 +0200 +++ b/master/ioctl.h Tue May 11 13:57:58 2010 +0200 @@ -56,7 +56,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 5 +#define EC_IOCTL_VERSION_MAGIC 6 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -134,6 +134,8 @@ #define EC_IOCTL_VOE_EXEC EC_IOWR(0x44, ec_ioctl_voe_t) #define EC_IOCTL_VOE_DATA EC_IOWR(0x45, ec_ioctl_voe_t) #define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x46, size_t) +#define EC_IOCTL_MASTER_SC_STATE EC_IOR(0x47, ec_master_state_t) +#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x48, ec_ioctl_config_t) /*****************************************************************************/ @@ -275,6 +277,7 @@ // outputs uint32_t data_size; + uint32_t tx_size; uint32_t logical_base_address; uint16_t working_counter; uint16_t expected_working_counter; @@ -294,6 +297,7 @@ uint8_t sync_index; ec_direction_t dir; uint32_t logical_address; + uint32_t domain_address; uint32_t data_size; } ec_ioctl_domain_fmmu_t; @@ -454,6 +458,7 @@ } syncs[EC_MAX_SYNC_MANAGERS]; uint16_t watchdog_divider; uint16_t watchdog_intervals; + uint8_t allow_overlapping_pdos; uint32_t sdo_count; int32_t slave_position; uint16_t dc_assign_activate; diff -r 365a90e93161 -r 6aa393418fb3 master/master.c --- a/master/master.c Thu May 06 11:56:35 2010 +0200 +++ b/master/master.c Tue May 11 13:57:58 2010 +0200 @@ -145,10 +145,14 @@ master->slaves = NULL; master->slave_count = 0; - + INIT_LIST_HEAD(&master->configs); master->app_time = 0ULL; +#ifdef EC_HAVE_CYCLES + master->dc_cycles_app_time = 0; +#endif + master->dc_jiffies_app_time = 0; master->app_start_time = 0ULL; master->has_app_time = 0; @@ -846,7 +850,7 @@ { ec_datagram_t *datagram, *next; size_t datagram_size; - uint8_t *frame_data, *cur_data; + uint8_t *frame_data, *cur_data, *frame_datagram_data; void *follows_word; #ifdef EC_HAVE_CYCLES cycles_t cycles_start, cycles_sent, cycles_end; @@ -854,6 +858,7 @@ unsigned long jiffies_sent; unsigned int frame_count, more_datagrams_waiting; struct list_head sent_datagrams; + ec_fmmu_config_t* domain_fmmu; #ifdef EC_HAVE_CYCLES cycles_start = get_cycles(); @@ -902,7 +907,28 @@ cur_data += EC_DATAGRAM_HEADER_SIZE; // EtherCAT datagram data - memcpy(cur_data, datagram->data, datagram->data_size); + frame_datagram_data = cur_data; + if (datagram->domain) { + unsigned int datagram_address = EC_READ_U32(datagram->address); + int i = 0; + uint8_t *domain_data = datagram->data; + list_for_each_entry(domain_fmmu, &datagram->domain->fmmu_configs, list) { + if (domain_fmmu->dir == EC_DIR_OUTPUT ) { + unsigned int frame_offset = domain_fmmu->logical_start_address-datagram_address; + memcpy(frame_datagram_data+frame_offset, domain_data, domain_fmmu->data_size); + if (unlikely(master->debug_level > 1)) { + EC_DBG("sending dg 0x%02X fmmu %u fp=%u dp=%u size=%u\n", + datagram->index, i,frame_offset,domain_data-datagram->data,domain_fmmu->data_size); + ec_print_data(domain_data, domain_fmmu->data_size); + } + } + domain_data += domain_fmmu->data_size; + ++i; + } + } + else { + memcpy(frame_datagram_data, datagram->data, datagram->data_size); + } cur_data += datagram->data_size; // EtherCAT datagram footer @@ -972,8 +998,9 @@ size_t frame_size, data_size; uint8_t datagram_type, datagram_index; unsigned int cmd_follows, matched; - const uint8_t *cur_data; + const uint8_t *cur_data, *frame_datagram_data; ec_datagram_t *datagram; + ec_fmmu_config_t* domain_fmmu; if (unlikely(size < EC_FRAME_HEADER_SIZE)) { if (master->debug_level) { @@ -1056,9 +1083,29 @@ cur_data += data_size + EC_DATAGRAM_FOOTER_SIZE; continue; } - - // copy received data into the datagram memory - memcpy(datagram->data, cur_data, data_size); + frame_datagram_data = cur_data; + if (datagram->domain) { + size_t datagram_address = EC_READ_U32(datagram->address); + int i = 0; + uint8_t *domain_data = datagram->data; + list_for_each_entry(domain_fmmu, &datagram->domain->fmmu_configs, list) { + if (domain_fmmu->dir == EC_DIR_INPUT ) { + unsigned int frame_offset = domain_fmmu->logical_start_address-datagram_address; + memcpy(domain_data, frame_datagram_data+frame_offset, domain_fmmu->data_size); + if (unlikely(master->debug_level > 1)) { + EC_DBG("receiving dg 0x%02X fmmu %u fp=%u dp=%u size=%u\n", + datagram->index, i,frame_offset,domain_data-datagram->data,domain_fmmu->data_size); + ec_print_data(domain_data, domain_fmmu->data_size); + } + } + domain_data += domain_fmmu->data_size; + ++i; + } + } + else { + // copy received data into the datagram memory + memcpy(datagram->data, frame_datagram_data, data_size); + } cur_data += data_size; // set the datagram's working counter @@ -2285,12 +2332,36 @@ /*****************************************************************************/ +void ecrt_master_configured_slaves_state(const ec_master_t *master, ec_master_state_t *state) +{ + const ec_slave_config_t *sc; + ec_slave_config_state_t sc_state; + + // collect al_states of all configured online slaves + state->al_states = 0; + list_for_each_entry(sc, &master->configs, list) { + ecrt_slave_config_state(sc,&sc_state); + if (sc_state.online) + state->al_states |= sc_state.al_state; + } + + state->slaves_responding = master->fsm.slaves_responding; + state->link_up = master->main_device.link_state; +} + +/*****************************************************************************/ + void ecrt_master_application_time(ec_master_t *master, uint64_t app_time) { master->app_time = app_time; +#ifdef EC_HAVE_CYCLES + master->dc_cycles_app_time = get_cycles(); +#endif + master->dc_jiffies_app_time = jiffies; if (unlikely(!master->has_app_time)) { - master->app_start_time = app_time; + EC_MASTER_DBG(master, 1, "set application start time = %llu\n",app_time); + master->app_start_time = app_time; master->has_app_time = 1; } } diff -r 365a90e93161 -r 6aa393418fb3 master/master.h --- a/master/master.h Thu May 06 11:56:35 2010 +0200 +++ b/master/master.h Tue May 11 13:57:58 2010 +0200 @@ -186,7 +186,11 @@ ec_datagram_t sync_mon_datagram; /**< Datagram used for DC synchronisation monitoring. */ ec_slave_t *dc_ref_clock; /**< DC reference clock slave. */ - +#ifdef EC_HAVE_CYCLES + cycles_t dc_cycles_app_time; /** cycles at last ecrt_master_sync() call.*/ +#endif + unsigned long dc_jiffies_app_time;/** jiffies at last + ecrt_master_sync() call.*/ unsigned int scan_busy; /**< Current scan state. */ unsigned int allow_scan; /**< \a True, if slave scanning is allowed. */ struct semaphore scan_sem; /**< Semaphore protecting the \a scan_busy diff -r 365a90e93161 -r 6aa393418fb3 master/slave_config.c --- a/master/slave_config.c Thu May 06 11:56:35 2010 +0200 +++ b/master/slave_config.c Tue May 11 13:57:58 2010 +0200 @@ -70,7 +70,7 @@ sc->product_code = product_code; sc->watchdog_divider = 0; // use default sc->watchdog_intervals = 0; // use default - + sc->allow_overlapping_pdos = 0; // default not allowed sc->slave = NULL; for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) @@ -164,12 +164,15 @@ { unsigned int i; ec_fmmu_config_t *fmmu; + ec_fmmu_config_t *prev_fmmu; + uint32_t fmmu_logical_start_address; + size_t tx_size; // FMMU configuration already prepared? for (i = 0; i < sc->used_fmmus; i++) { fmmu = &sc->fmmu_configs[i]; if (fmmu->domain == domain && fmmu->sync_index == sync_index) - return fmmu->logical_start_address; + return fmmu->domain_address; } if (sc->used_fmmus == EC_MAX_FMMUS) { @@ -177,13 +180,25 @@ return -EOVERFLOW; } - fmmu = &sc->fmmu_configs[sc->used_fmmus++]; + fmmu = &sc->fmmu_configs[sc->used_fmmus]; down(&sc->master->master_sem); - ec_fmmu_config_init(fmmu, sc, domain, sync_index, dir); + ec_fmmu_config_init(fmmu, sc, sync_index, dir); + fmmu_logical_start_address = domain->tx_size; + tx_size = fmmu->data_size; + if (sc->allow_overlapping_pdos && sc->used_fmmus > 0) { + prev_fmmu = &sc->fmmu_configs[sc->used_fmmus-1]; + if (fmmu->dir != prev_fmmu->dir) { + prev_fmmu->tx_size = max(fmmu->data_size,prev_fmmu->data_size); + tx_size = 0; + fmmu_logical_start_address = prev_fmmu->logical_start_address; + } + } + ec_fmmu_config_domain(fmmu,domain,fmmu_logical_start_address,tx_size); up(&sc->master->master_sem); - return fmmu->logical_start_address; + ++sc->used_fmmus; + return fmmu->domain_address; } /*****************************************************************************/ @@ -452,6 +467,18 @@ /*****************************************************************************/ +void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc, + uint8_t allow_overlapping_pdos ) +{ + if (sc->master->debug_level) + EC_DBG("%s(sc = 0x%p, allow_overlapping_pdos = %u)\n", + __func__, sc, allow_overlapping_pdos); + + sc->allow_overlapping_pdos = allow_overlapping_pdos; +} + +/*****************************************************************************/ + int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc, uint8_t sync_index, uint16_t pdo_index) { @@ -975,6 +1002,7 @@ EXPORT_SYMBOL(ecrt_slave_config_sync_manager); EXPORT_SYMBOL(ecrt_slave_config_watchdog); +EXPORT_SYMBOL(ecrt_slave_config_overlapping_pdos); EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_add); EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_clear); EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add); diff -r 365a90e93161 -r 6aa393418fb3 master/slave_config.h --- a/master/slave_config.h Thu May 06 11:56:35 2010 +0200 +++ b/master/slave_config.h Tue May 11 13:57:58 2010 +0200 @@ -126,7 +126,8 @@ intervals (see spec. reg. 0x0400). */ uint16_t watchdog_intervals; /**< Process data watchdog intervals (see spec. reg. 0x0420). */ - + uint8_t allow_overlapping_pdos; /**< Allow input PDOs use the same frame space + as output PDOs. */ ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is offline. */ diff -r 365a90e93161 -r 6aa393418fb3 tool/CommandDomains.cpp --- a/tool/CommandDomains.cpp Thu May 06 11:56:35 2010 +0200 +++ b/tool/CommandDomains.cpp Tue May 11 13:57:58 2010 +0200 @@ -143,6 +143,8 @@ << setw(8) << domain.logical_base_address << ", Size " << dec << setfill(' ') << setw(3) << domain.data_size + << ", TxSize " << dec << setfill(' ') + << setw(3) << domain.tx_size << ", WorkingCounter " << domain.working_counter << "/" << domain.expected_working_counter << endl; @@ -173,7 +175,7 @@ << setw(8) << fmmu.logical_address << ", Size " << dec << fmmu.data_size << endl; - dataOffset = fmmu.logical_address - domain.logical_base_address; + dataOffset = fmmu.domain_address - domain.logical_base_address; if (dataOffset + fmmu.data_size > domain.data_size) { stringstream err; delete [] processData;