--- a/Makefile.am Fri Jan 22 10:11:58 2016 +0100
+++ b/Makefile.am Fri Jan 22 13:09:43 2016 +0100
@@ -119,7 +119,11 @@
configure \
configure.in \
libtool \
- stamp-h1
+ stamp-h1 \
+ ethercat.spec \
+ script/init.d/ethercat \
+ m4/*.m4 \
+ `find -path ./documentation -prune -o "(" -name Makefile -o -name Makefile.in -o -name Kbuild -o -name .deps -o -name Module.symvers -o -name .tmp_versions ")" -print`
doc:
doxygen Doxyfile
--- a/configure.ac Fri Jan 22 10:11:58 2016 +0100
+++ b/configure.ac Fri Jan 22 13:09:43 2016 +0100
@@ -820,6 +820,35 @@
fi
#------------------------------------------------------------------------------
+# Force the reference clock to OP even if unconfigured
+#------------------------------------------------------------------------------
+
+AC_MSG_CHECKING([whether to force the reference clock to OP])
+
+AC_ARG_ENABLE([refclkop],
+ AS_HELP_STRING([--enable-refclkop],
+ [Force reference clock to OP (default: no)]),
+ [
+ case "${enableval}" in
+ yes) refclkop=1
+ ;;
+ no) refclkop=0
+ ;;
+ *) AC_MSG_ERROR([Invalid value for --enable-refclkop])
+ ;;
+ esac
+ ],
+ [refclkop=0]
+)
+
+if test "x${refclkop}" = "x1"; then
+ AC_DEFINE([EC_REFCLKOP], [1], [Force refclk to OP])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+#------------------------------------------------------------------------------
# Command-line tool
#-----------------------------------------------------------------------------
--- a/include/ecrt.h Fri Jan 22 10:11:58 2016 +0100
+++ b/include/ecrt.h Fri Jan 22 13:09:43 2016 +0100
@@ -815,7 +815,7 @@
uint16_t slave_position, /**< Slave position. */
uint16_t index, /**< Index of the SDO. */
uint8_t subindex, /**< Subindex of the SDO. */
- uint8_t *data, /**< Data buffer to download. */
+ const uint8_t *data, /**< Data buffer to download. */
size_t data_size, /**< Size of the data buffer. */
uint32_t *abort_code /**< Abort code of the SDO download. */
);
@@ -834,7 +834,7 @@
ec_master_t *master, /**< EtherCAT master. */
uint16_t slave_position, /**< Slave position. */
uint16_t index, /**< Index of the SDO. */
- uint8_t *data, /**< Data buffer to download. */
+ const uint8_t *data, /**< Data buffer to download. */
size_t data_size, /**< Size of the data buffer. */
uint32_t *abort_code /**< Abort code of the SDO download. */
);
@@ -956,8 +956,10 @@
*
* Has to be called cyclically by the application after ecrt_master_activate()
* has returned.
- */
-void ecrt_master_send(
+ *
+ * Returns the number of bytes sent.
+ */
+size_t ecrt_master_send(
ec_master_t *master /**< EtherCAT master. */
);
@@ -1145,6 +1147,17 @@
*/
);
+/** Configure whether 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.
*
* This method has to be called in non-realtime context before
--- a/lib/master.c Fri Jan 22 10:11:58 2016 +0100
+++ b/lib/master.c Fri Jan 22 13:09:43 2016 +0100
@@ -60,6 +60,11 @@
ec_domain_t *d, *next_d;
ec_slave_config_t *c, *next_c;
+ if (master->process_data) {
+ munmap(master->process_data, master->process_data_size);
+ master->process_data = NULL;
+ }
+
d = master->first_domain;
while (d) {
next_d = d->next;
@@ -81,10 +86,6 @@
void ec_master_clear(ec_master_t *master)
{
- if (master->process_data) {
- munmap(master->process_data, master->process_data_size);
- }
-
ec_master_clear_config(master);
if (master->fd != -1) {
@@ -389,7 +390,7 @@
/****************************************************************************/
int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
- uint16_t index, uint8_t subindex, uint8_t *data,
+ uint16_t index, uint8_t subindex, const uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_ioctl_slave_sdo_download_t download;
@@ -418,7 +419,7 @@
/****************************************************************************/
int ecrt_master_sdo_download_complete(ec_master_t *master,
- uint16_t slave_position, uint16_t index, uint8_t *data,
+ uint16_t slave_position, uint16_t index, const uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_ioctl_slave_sdo_download_t download;
@@ -606,15 +607,18 @@
/****************************************************************************/
-void ecrt_master_send(ec_master_t *master)
-{
- int ret;
-
- ret = ioctl(master->fd, EC_IOCTL_SEND, NULL);
+size_t ecrt_master_send(ec_master_t *master)
+{
+ int ret;
+ size_t sent_bytes = 0;
+
+ ret = ioctl(master->fd, EC_IOCTL_SEND, &sent_bytes);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to send: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
+
+ return sent_bytes;
}
/****************************************************************************/
@@ -714,11 +718,16 @@
ret = ioctl(master->fd, EC_IOCTL_REF_CLOCK_TIME, time);
if (EC_IOCTL_IS_ERROR(ret)) {
- fprintf(stderr, "Failed to get reference clock time: %s\n",
- strerror(EC_IOCTL_ERRNO(ret)));
- }
-
- return ret;
+ ret = EC_IOCTL_ERRNO(ret);
+ if (ret != EIO && ret != ENXIO) {
+ // do not log if no refclk or no refclk time yet
+ fprintf(stderr, "Failed to get reference clock time: %s\n",
+ strerror(ret));
+ }
+ return -ret;
+ }
+
+ return 0;
}
/****************************************************************************/
--- a/lib/slave_config.c Fri Jan 22 10:11:58 2016 +0100
+++ b/lib/slave_config.c Fri Jan 22 13:09:43 2016 +0100
@@ -120,6 +120,23 @@
/*****************************************************************************/
+void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
+ uint8_t allow_overlapping_pdos)
+{
+ ec_ioctl_config_t data;
+
+ memset(&data, 0, 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)
{
--- a/master/device.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/device.h Fri Jan 22 13:09:43 2016 +0100
@@ -48,7 +48,7 @@
* different memory regions, because otherwise the network device DMA could
* send the same data twice, if it is called twice.
*/
-#define EC_TX_RING_SIZE 2
+#define EC_TX_RING_SIZE 0x10
#ifdef EC_DEBUG_IF
#include "debug.h"
--- a/master/domain.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/domain.c Fri Jan 22 13:09:43 2016 +0100
@@ -47,6 +47,11 @@
*/
#define DEBUG_REDUNDANCY 0
+#ifndef list_next_entry
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+#endif
+
/*****************************************************************************/
void ec_domain_clear_data(ec_domain_t *);
@@ -79,6 +84,10 @@
domain->working_counter_changes = 0;
domain->redundancy_active = 0;
domain->notify_jiffies = 0;
+
+ /* Used by ec_domain_add_fmmu_config */
+ memset(domain->offset_used, 0, sizeof(domain->offset_used));
+ domain->sc_in_work = 0;
}
/*****************************************************************************/
@@ -124,14 +133,45 @@
ec_fmmu_config_t *fmmu /**< FMMU configuration. */
)
{
+ const ec_slave_config_t *sc;
+ uint32_t logical_domain_offset;
+ unsigned fmmu_data_size;
+
fmmu->domain = domain;
-
- domain->data_size += fmmu->data_size;
+ sc = fmmu->sc;
+
+ fmmu_data_size = ec_pdo_list_total_size(
+ &sc->sync_configs[fmmu->sync_index].pdos);
+
+ if (sc->allow_overlapping_pdos && (sc == domain->sc_in_work)) {
+ // If we permit overlapped PDOs, and we already have an allocated FMMU
+ // for this slave, allocate the subsequent FMMU offsets by direction
+ logical_domain_offset = domain->offset_used[fmmu->dir];
+ } else {
+ // otherwise, allocate to the furthest extent of any allocated
+ // FMMU on this domain.
+ logical_domain_offset = max(domain->offset_used[EC_DIR_INPUT],
+ domain->offset_used[EC_DIR_OUTPUT]);
+ // rebase the free offsets to the current position
+ domain->offset_used[EC_DIR_INPUT] = logical_domain_offset;
+ domain->offset_used[EC_DIR_OUTPUT] = logical_domain_offset;
+ }
+ domain->sc_in_work = sc;
+
+ // consume the offset space for this FMMU's direction
+ domain->offset_used[fmmu->dir] += fmmu_data_size;
+
+ ec_fmmu_set_domain_offset_size(fmmu, logical_domain_offset, fmmu_data_size);
+
list_add_tail(&fmmu->list, &domain->fmmu_configs);
+ // Determine domain size from furthest extent of FMMU data
+ domain->data_size = max(domain->offset_used[EC_DIR_INPUT],
+ domain->offset_used[EC_DIR_OUTPUT]);
+
EC_MASTER_DBG(domain->master, 1, "Domain %u:"
- " Added %u bytes, total %zu.\n",
- domain->index, fmmu->data_size, domain->data_size);
+ " Added %u bytes at %u.\n",
+ domain->index, fmmu->data_size, logical_domain_offset);
}
/*****************************************************************************/
@@ -192,7 +232,7 @@
*
* \return Non-zero if slave connfig was already counted.
*/
-int shall_count(
+static int shall_count(
const ec_fmmu_config_t *cur_fmmu, /**< Current FMMU with direction to
search for. */
const ec_fmmu_config_t *first_fmmu /**< Datagram's first FMMU. */
@@ -213,13 +253,55 @@
/*****************************************************************************/
+/** Domain finish helper function.
+ *
+ * Known boundaries for a datagram have been identified. Scans the datagram
+ * FMMU boundaries for WKC counters and then creates the datagram_pair.
+ *
+ * \param domain The parent domain
+ * \param datagram_begin_offset Datagram's logical beginning offset
+ * \param datagram_end_offset Logical end offset (one past last byte)
+ * \param datagram_first_fmmu The begin FMMU in the datagram
+ * \param datagram_end_fmmu The end (one past last) FMMU
+ *
+ * \return Non-zero if error emplacing domain
+ */
+static int emplace_datagram(ec_domain_t *domain,
+ uint32_t datagram_begin_offset,
+ uint32_t datagram_end_offset,
+ const ec_fmmu_config_t *datagram_first_fmmu,
+ const ec_fmmu_config_t *datagram_end_fmmu
+ )
+{
+ unsigned int datagram_used[EC_DIR_COUNT];
+ const ec_fmmu_config_t *curr_fmmu;
+ size_t data_size;
+
+ data_size = datagram_end_offset - datagram_begin_offset;
+
+ memset(datagram_used, 0, sizeof(datagram_used));
+ for (curr_fmmu = datagram_first_fmmu;
+ &curr_fmmu->list != &datagram_end_fmmu->list;
+ curr_fmmu = list_next_entry(curr_fmmu, list)) {
+ if (shall_count(curr_fmmu, datagram_first_fmmu)) {
+ datagram_used[curr_fmmu->dir]++;
+ }
+ }
+
+ return ec_domain_add_datagram_pair(domain,
+ domain->logical_base_address + datagram_begin_offset,
+ data_size,
+ domain->data + datagram_begin_offset,
+ datagram_used);
+}
+
+/*****************************************************************************/
+
/** Finishes a domain.
*
* This allocates the necessary datagrams and writes the correct logical
* addresses to every configured FMMU.
*
- * \todo Check for FMMUs that do not fit into any datagram.
- *
* \retval 0 Success
* \retval <0 Error code.
*/
@@ -228,12 +310,13 @@
uint32_t base_address /**< Logical base address. */
)
{
- uint32_t datagram_offset;
- size_t datagram_size;
- unsigned int datagram_count;
- unsigned int datagram_used[EC_DIR_COUNT];
+ uint32_t datagram_offset = 0;
+ unsigned int datagram_count = 0;
ec_fmmu_config_t *fmmu;
const ec_fmmu_config_t *datagram_first_fmmu = NULL;
+ const ec_fmmu_config_t *valid_fmmu = NULL;
+ unsigned candidate_start = 0;
+ unsigned valid_start = 0;
const ec_datagram_pair_t *datagram_pair;
int ret;
@@ -253,56 +336,49 @@
// - correct the logical base addresses
// - set up the datagrams to carry the process data
// - calculate the datagrams' expected working counters
- datagram_offset = 0;
- datagram_size = 0;
- datagram_count = 0;
- datagram_used[EC_DIR_OUTPUT] = 0;
- datagram_used[EC_DIR_INPUT] = 0;
-
if (!list_empty(&domain->fmmu_configs)) {
datagram_first_fmmu =
list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list);
}
list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
-
- // Correct logical FMMU address
- fmmu->logical_start_address += base_address;
-
- // Increment Input/Output counter to determine datagram types
- // and calculate expected working counters
- if (shall_count(fmmu, datagram_first_fmmu)) {
- datagram_used[fmmu->dir]++;
- }
-
- // 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) {
- ret = ec_domain_add_datagram_pair(domain,
- domain->logical_base_address + datagram_offset,
- datagram_size, domain->data + datagram_offset,
- datagram_used);
- if (ret < 0)
- return ret;
-
- datagram_offset += datagram_size;
- datagram_size = 0;
- datagram_count++;
- datagram_used[EC_DIR_OUTPUT] = 0;
- datagram_used[EC_DIR_INPUT] = 0;
- datagram_first_fmmu = fmmu;
- }
-
- datagram_size += fmmu->data_size;
+ if (fmmu->data_size > EC_MAX_DATA_SIZE) {
+ EC_MASTER_ERR(domain->master,
+ "FMMU size %u bytes exceeds maximum data size %u",
+ fmmu->data_size, EC_MAX_DATA_SIZE);
+ return -EINVAL;
+ }
+ if (fmmu->logical_domain_offset >= candidate_start) {
+ // As FMMU offsets increase monotonically, and candidate start
+ // offset has never been contradicted, it can now never be
+ // contradicted, as no future FMMU can cross it.
+ // All FMMUs prior to this point approved for next datagram
+ valid_fmmu = fmmu;
+ valid_start = candidate_start;
+ if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset
+ > EC_MAX_DATA_SIZE) {
+ // yet the new candidate exceeds the datagram size, so we
+ // use the last known valid candidate to create the datagram
+ ret = emplace_datagram(domain, datagram_offset, valid_start,
+ datagram_first_fmmu, valid_fmmu);
+ if (ret < 0)
+ return ret;
+
+ datagram_offset = valid_start;
+ datagram_count++;
+ datagram_first_fmmu = fmmu;
+ }
+ }
+ if (fmmu->logical_domain_offset + fmmu->data_size > candidate_start) {
+ candidate_start = fmmu->logical_domain_offset + fmmu->data_size;
+ }
}
/* Allocate last datagram pair, if data are left (this is also the case if
* the process data fit into a single datagram) */
- if (datagram_size) {
- ret = ec_domain_add_datagram_pair(domain,
- domain->logical_base_address + datagram_offset,
- datagram_size, domain->data + datagram_offset,
- datagram_used);
+ if (domain->data_size > datagram_offset) {
+ ret = emplace_datagram(domain, datagram_offset, domain->data_size,
+ datagram_first_fmmu, fmmu);
if (ret < 0)
return ret;
datagram_count++;
@@ -317,9 +393,9 @@
const ec_datagram_t *datagram =
&datagram_pair->datagrams[EC_DEVICE_MAIN];
EC_MASTER_INFO(domain->master, " Datagram %s: Logical offset 0x%08x,"
- " %zu byte, type %s.\n", datagram->name,
+ " %zu byte, type %s at %p.\n", datagram->name,
EC_READ_U32(datagram->address), datagram->data_size,
- ec_datagram_type_string(datagram));
+ ec_datagram_type_string(datagram), datagram);
}
return 0;
@@ -503,19 +579,17 @@
continue;
}
- if (fmmu->logical_start_address >=
- logical_datagram_address + datagram_size) {
+ if (fmmu->logical_domain_offset >= datagram_size) {
// fmmu data contained in next datagram pair
break;
}
- datagram_offset =
- fmmu->logical_start_address - logical_datagram_address;
+ datagram_offset = fmmu->logical_domain_offset;
#if DEBUG_REDUNDANCY
EC_MASTER_DBG(domain->master, 1,
- "input fmmu log=%u size=%u offset=%u\n",
- fmmu->logical_start_address, fmmu->data_size,
+ "input fmmu log_off=%u size=%u offset=%u\n",
+ fmmu->logical_domain_offset, fmmu->data_size,
datagram_offset);
if (domain->master->debug_level > 0) {
ec_print_data(pair->send_buffer + datagram_offset,
--- a/master/domain.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/domain.h Fri Jan 22 13:09:43 2016 +0100
@@ -72,6 +72,11 @@
since last notification. */
unsigned int redundancy_active; /**< Non-zero, if redundancy is in use. */
unsigned long notify_jiffies; /**< Time of last notification. */
+ uint32_t offset_used[EC_DIR_COUNT]; /**< Next available domain offset of
+ PDO, by direction */
+ const ec_slave_config_t *sc_in_work; /**< slave_config which is actively
+ being registered in this domain
+ (i.e. ecrt_slave_config_reg_pdo_entry() ) */
};
/*****************************************************************************/
--- a/master/ethernet.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/ethernet.c Fri Jan 22 13:09:43 2016 +0100
@@ -79,6 +79,7 @@
int ec_eoedev_stop(struct net_device *);
int ec_eoedev_tx(struct sk_buff *, struct net_device *);
struct net_device_stats *ec_eoedev_stats(struct net_device *);
+static int ec_eoedev_set_mac(struct net_device *netdev, void *p);
/*****************************************************************************/
@@ -90,11 +91,34 @@
.ndo_stop = ec_eoedev_stop,
.ndo_start_xmit = ec_eoedev_tx,
.ndo_get_stats = ec_eoedev_stats,
+ .ndo_set_mac_address = ec_eoedev_set_mac,
};
#endif
/*****************************************************************************/
+/**
+ * ec_eoedev_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int
+ec_eoedev_set_mac(struct net_device *netdev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+ return 0;
+}
+
+/*****************************************************************************/
+
/** EoE constructor.
*
* Initializes the EoE handler, creates a net_device and registers it.
@@ -107,9 +131,13 @@
)
{
ec_eoe_t **priv;
- int i, ret = 0;
+ int ret = 0;
char name[EC_DATAGRAM_NAME_SIZE];
+ struct net_device *dev;
+ unsigned char lo_mac[ETH_ALEN] = {0};
+ unsigned int use_master_mac = 0;
+
eoe->slave = slave;
ec_datagram_init(&eoe->datagram);
@@ -165,8 +193,65 @@
eoe->dev->get_stats = ec_eoedev_stats;
#endif
- for (i = 0; i < ETH_ALEN; i++)
- eoe->dev->dev_addr[i] = i | (i << 4);
+ // First check if the MAC address assigned to the master is globally
+ // unique
+ if ((slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[0] & 0x02) !=
+ 0x02) {
+ // The master MAC is unique and the NIC part can be used for the EoE
+ // interface MAC
+ use_master_mac = 1;
+ }
+ else {
+ // The master MAC is not unique, so we check for unique MAC in other
+ // interfaces
+ dev = first_net_device(&init_net);
+ while (dev) {
+ // Check if globally unique MAC address
+ if (dev->addr_len == ETH_ALEN) {
+ if (memcmp(dev->dev_addr, lo_mac, ETH_ALEN) != 0) {
+ if ((dev->dev_addr[0] & 0x02) != 0x02) {
+ // The first globally unique MAC address has been
+ // identified
+ break;
+ }
+ }
+ }
+ dev = next_net_device(dev);
+ }
+ if (eoe->dev->addr_len == ETH_ALEN) {
+ if (dev) {
+ // A unique MAC were identified in one of the other network
+ // interfaces and the NIC part can be used for the EoE
+ // interface MAC.
+ EC_SLAVE_INFO(slave, "%s MAC address derived from"
+ " NIC part of %s MAC address",
+ eoe->dev->name, dev->name);
+ eoe->dev->dev_addr[1] = dev->dev_addr[3];
+ eoe->dev->dev_addr[2] = dev->dev_addr[4];
+ eoe->dev->dev_addr[3] = dev->dev_addr[5];
+ }
+ else {
+ use_master_mac = 1;
+ }
+ }
+ }
+ if (eoe->dev->addr_len == ETH_ALEN) {
+ if (use_master_mac) {
+ EC_SLAVE_INFO(slave, "%s MAC address derived"
+ " from NIC part of %s MAC address",
+ eoe->dev->name,
+ slave->master->devices[EC_DEVICE_MAIN].dev->name);
+ eoe->dev->dev_addr[1] =
+ slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[3];
+ eoe->dev->dev_addr[2] =
+ slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[4];
+ eoe->dev->dev_addr[3] =
+ slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[5];
+ }
+ eoe->dev->dev_addr[0] = 0x02;
+ eoe->dev->dev_addr[4] = (uint8_t)(slave->ring_position >> 8);
+ eoe->dev->dev_addr[5] = (uint8_t)(slave->ring_position);
+ }
// initialize private data
priv = netdev_priv(eoe->dev);
@@ -188,8 +273,6 @@
goto out_free;
}
- // make the last address octet unique
- eoe->dev->dev_addr[ETH_ALEN - 1] = (uint8_t) eoe->dev->ifindex;
return 0;
out_free:
@@ -266,7 +349,8 @@
current_size = remaining_size;
last_fragment = 1;
} else {
- current_size = ((eoe->slave->configured_tx_mailbox_size - 10) / 32) * 32;
+ current_size =
+ ((eoe->slave->configured_tx_mailbox_size - 10) / 32) * 32;
last_fragment = 0;
}
--- a/master/fmmu_config.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fmmu_config.c Fri Jan 22 13:09:43 2016 +0100
@@ -60,13 +60,23 @@
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);
+ fmmu->logical_domain_offset = 0;
+ fmmu->data_size = 0;
ec_domain_add_fmmu_config(domain, fmmu);
}
+void ec_fmmu_set_domain_offset_size(
+ ec_fmmu_config_t *fmmu, /**< EtherCAT FMMU configuration. */
+ uint32_t logical_domain_offset, /**< Logical offset address
+ relative to domain->logical_base_address. */
+ unsigned data_size /**< Covered PDO size. */
+ )
+{
+ fmmu->logical_domain_offset = logical_domain_offset;
+ fmmu->data_size = data_size;
+}
+
/*****************************************************************************/
/** Initializes an FMMU configuration page.
@@ -79,13 +89,14 @@
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: LogOff 0x%08X, Size %3u,"
" PhysAddr 0x%04X, SM%u, Dir %s\n",
- fmmu->logical_start_address, fmmu->data_size,
+ fmmu->logical_domain_offset, fmmu->data_size,
sync->physical_start_address, fmmu->sync_index,
fmmu->dir == EC_DIR_INPUT ? "in" : "out");
- EC_WRITE_U32(data, fmmu->logical_start_address);
+ EC_WRITE_U32(data, fmmu->domain->logical_base_address +
+ fmmu->logical_domain_offset);
EC_WRITE_U16(data + 4, fmmu->data_size); // size of fmmu
EC_WRITE_U8 (data + 6, 0x00); // logical start bit
EC_WRITE_U8 (data + 7, 0x07); // logical end bit
--- a/master/fmmu_config.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fmmu_config.h Fri Jan 22 13:09:43 2016 +0100
@@ -49,7 +49,8 @@
const ec_domain_t *domain; /**< Domain. */
uint8_t sync_index; /**< Index of sync manager to use. */
ec_direction_t dir; /**< FMMU direction. */
- uint32_t logical_start_address; /**< Logical start address. */
+ uint32_t logical_domain_offset; /**< Logical offset address relative to
+ domain->logical_base_address. */
unsigned int data_size; /**< Covered PDO size. */
} ec_fmmu_config_t;
@@ -58,6 +59,15 @@
void ec_fmmu_config_init(ec_fmmu_config_t *, ec_slave_config_t *,
ec_domain_t *, uint8_t, ec_direction_t);
+/**
+ * @param fmmu EtherCAT FMMU configuration.
+ * @param logical_domain_offset Logical offset address
+ relative to domain->logical_base_address.
+ * @param data_size Covered PDO size.
+*/
+void ec_fmmu_set_domain_offset_size(ec_fmmu_config_t *fmmu,
+ uint32_t logical_domain_offset, unsigned data_size);
+
void ec_fmmu_config_page(const ec_fmmu_config_t *, const ec_sync_t *,
uint8_t *);
--- a/master/fsm_foe.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fsm_foe.c Fri Jan 22 13:09:43 2016 +0100
@@ -42,9 +42,10 @@
/*****************************************************************************/
-/** Maximum time in ms to wait for responses when reading out the dictionary.
- */
-#define EC_FSM_FOE_TIMEOUT 3000
+/** Maximum time in jiffies to wait for responses when reading out the
+ * dictionary.
+ */
+#define EC_FSM_FOE_TIMEOUT_JIFFIES (3 * HZ)
/** Size of the FoE header.
*/
@@ -256,6 +257,10 @@
EC_WRITE_U16(data, EC_FOE_OPCODE_DATA); // OpCode = DataBlock req.
EC_WRITE_U32(data + 2, fsm->tx_packet_no); // PacketNo, Password
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "sending opcode %u packet %u\n",
+ EC_FOE_OPCODE_DATA, fsm->tx_packet_no);
+#endif
memcpy(data + EC_FOE_HEADER_SIZE,
fsm->tx_buffer + fsm->tx_buffer_offset, current_size);
@@ -293,6 +298,10 @@
EC_WRITE_U16( data, EC_FOE_OPCODE_WRQ); // fsm write request
EC_WRITE_U32( data + 2, fsm->tx_packet_no );
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "sending opcode %u packet %u\n",
+ EC_FOE_OPCODE_WRQ, fsm->tx_packet_no);
+#endif
memcpy(data + EC_FOE_HEADER_SIZE, fsm->tx_filename, current_size);
@@ -365,9 +374,8 @@
if (!ec_slave_mbox_check(fsm->datagram)) {
// slave did not put anything in the mailbox yet
- unsigned long diff_ms = (fsm->datagram->jiffies_received -
- fsm->jiffies_start) * 1000 / HZ;
- if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
+ if (time_after(fsm->datagram->jiffies_received,
+ fsm->jiffies_start + EC_FSM_FOE_TIMEOUT_JIFFIES)) {
ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
return;
@@ -431,6 +439,9 @@
}
opCode = EC_READ_U8(data);
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "received opcode %u\n", opCode);
+#endif
if (opCode == EC_FOE_OPCODE_BUSY) {
// slave not ready
@@ -443,6 +454,20 @@
return;
}
+ if (opCode == EC_FOE_OPCODE_ERR) {
+ fsm->request->error_code = EC_READ_U32(data + 2);
+ EC_SLAVE_ERR(slave, "Received FoE Error Request (code 0x%08x).\n",
+ fsm->request->error_code);
+ if (rec_size > 6 && data[6]) {
+ uint8_t text[256];
+ strncpy(text, data + 6, min(rec_size - 6, sizeof(text)));
+ text[sizeof(text)-1] = 0;
+ EC_SLAVE_ERR(slave, "FoE Error Text: %s\n", text);
+ }
+ ec_foe_set_tx_error(fsm, FOE_OPCODE_ERROR);
+ return;
+ }
+
if (opCode == EC_FOE_OPCODE_ACK) {
fsm->tx_packet_no++;
fsm->tx_buffer_offset += fsm->tx_current_size;
@@ -566,6 +591,9 @@
EC_WRITE_U16(data, EC_FOE_OPCODE_RRQ); // fsm read request
EC_WRITE_U32(data + 2, 0x00000000); // no passwd
memcpy(data + EC_FOE_HEADER_SIZE, fsm->rx_filename, current_size);
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "sending opcode %u\n", EC_FOE_OPCODE_RRQ);
+#endif
if (fsm->slave->master->debug_level) {
EC_SLAVE_DBG(fsm->slave, 1, "FoE Read Request:\n");
@@ -596,6 +624,10 @@
EC_WRITE_U16(data, EC_FOE_OPCODE_ACK);
EC_WRITE_U32(data + 2, fsm->rx_expected_packet_no);
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "sending opcode %u packet %u\n",
+ EC_FOE_OPCODE_ACK, fsm->rx_expected_packet_no);
+#endif
return 0;
}
@@ -704,9 +736,8 @@
}
if (!ec_slave_mbox_check(fsm->datagram)) {
- unsigned long diff_ms = (fsm->datagram->jiffies_received -
- fsm->jiffies_start) * 1000 / HZ;
- if (diff_ms >= EC_FSM_FOE_TIMEOUT) {
+ if (time_after(fsm->datagram->jiffies_received,
+ fsm->jiffies_start + EC_FSM_FOE_TIMEOUT_JIFFIES)) {
ec_foe_set_tx_error(fsm, FOE_TIMEOUT_ERROR);
EC_SLAVE_ERR(slave, "Timeout while waiting for ack response.\n");
return;
@@ -734,7 +765,8 @@
)
{
size_t rec_size;
- uint8_t *data, opCode, packet_no, mbox_prot;
+ uint32_t packet_no;
+ uint8_t *data, opCode, mbox_prot;
ec_slave_t *slave = fsm->slave;
@@ -770,11 +802,21 @@
}
opCode = EC_READ_U8(data);
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "received opcode %u\n", opCode);
+#endif
if (opCode == EC_FOE_OPCODE_BUSY) {
+ fsm->rx_expected_packet_no--;
if (ec_foe_prepare_send_ack(fsm, datagram)) {
ec_foe_set_rx_error(fsm, FOE_PROT_ERROR);
+ } else {
+ fsm->state = ec_fsm_foe_state_sent_ack;
}
+#ifdef DEBUG_FOE
+ EC_SLAVE_DBG(fsm->slave, 0, "%s() busy. Next pkt %u\n", __func__,
+ fsm->rx_expected_packet_no);
+#endif
return;
}
@@ -782,9 +824,10 @@
fsm->request->error_code = EC_READ_U32(data + 2);
EC_SLAVE_ERR(slave, "Received FoE Error Request (code 0x%08x).\n",
fsm->request->error_code);
- if (rec_size > 6) {
+ if (rec_size > 6 && data[6]) {
uint8_t text[256];
strncpy(text, data + 6, min(rec_size - 6, sizeof(text)));
+ text[sizeof(text)-1] = 0;
EC_SLAVE_ERR(slave, "FoE Error Text: %s\n", text);
}
ec_foe_set_rx_error(fsm, FOE_OPCODE_ERROR);
@@ -799,9 +842,10 @@
return;
}
- packet_no = EC_READ_U16(data + 2);
+ packet_no = EC_READ_U32(data + 2);
if (packet_no != fsm->rx_expected_packet_no) {
- EC_SLAVE_ERR(slave, "Received unexpected packet number.\n");
+ EC_SLAVE_ERR(slave, "Received packet number %u, expected %u.\n",
+ packet_no, fsm->rx_expected_packet_no);
ec_foe_set_rx_error(fsm, FOE_PACKETNO_ERROR);
return;
}
--- a/master/fsm_master.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fsm_master.c Fri Jan 22 13:09:43 2016 +0100
@@ -246,6 +246,9 @@
return;
}
+ // check for detached config requests
+ ec_master_expire_slave_config_requests(fsm->master);
+
ec_datagram_brd(fsm->datagram, 0x0130, 2);
ec_datagram_zero(fsm->datagram);
fsm->datagram->device_index = fsm->dev_idx;
@@ -490,6 +493,11 @@
continue;
}
+ if (!ec_fsm_slave_is_ready(&slave->fsm)) {
+ EC_SLAVE_DBG(slave, 1, "Busy - processing external request!\n");
+ continue;
+ }
+
list_for_each_entry(req, &slave->config->sdo_requests, list) {
if (req->state == EC_INT_REQUEST_QUEUED) {
--- a/master/fsm_slave.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fsm_slave.c Fri Jan 22 13:09:43 2016 +0100
@@ -201,6 +201,18 @@
ec_datagram_t *datagram /**< Datagram to use. */
)
{
+ ec_slave_t *slave = fsm->slave;
+ ec_sdo_request_t *req;
+
+ if (slave->config) {
+ list_for_each_entry(req, &slave->config->sdo_requests, list) {
+ if (req->state == EC_INT_REQUEST_QUEUED || req->state == EC_INT_REQUEST_BUSY) {
+ EC_SLAVE_DBG(slave, 1, "Busy - processing internal SDO request!\n");
+ return;
+ }
+ }
+ }
+
// Check for pending external SDO requests
if (ec_fsm_slave_action_process_sdo(fsm, datagram)) {
return;
--- a/master/fsm_slave_config.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/fsm_slave_config.c Fri Jan 22 13:09:43 2016 +0100
@@ -1399,8 +1399,12 @@
EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
diff_ms);
} else {
- EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
- diff_ms, abs_sync_diff);
+ static unsigned long last_diff_ms = 0;
+ if ((diff_ms < last_diff_ms) || (diff_ms >= (last_diff_ms + 100))) {
+ last_diff_ms = diff_ms;
+ EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
+ diff_ms, abs_sync_diff);
+ }
// check synchrony again
ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
--- a/master/globals.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/globals.h Fri Jan 22 13:09:43 2016 +0100
@@ -88,8 +88,14 @@
#define EC_ADDR_LEN 4
/** Resulting maximum data size of a single datagram in a frame. */
+#ifdef DEBUG_DATAGRAM_OVERFLOW
+// Define a runt datagram which can be easily overflowed on
+// available hardware for use when testing ec_domain_finish()
+#define EC_MAX_DATA_SIZE (128)
+#else
#define EC_MAX_DATA_SIZE (ETH_DATA_LEN - EC_FRAME_HEADER_SIZE \
- EC_DATAGRAM_HEADER_SIZE - EC_DATAGRAM_FOOTER_SIZE)
+#endif // DEBUG_DATAGRAM_OVERFLOW
/** Mailbox header size. */
#define EC_MBOX_HEADER_SIZE 6
--- a/master/ioctl.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/ioctl.c Fri Jan 22 13:09:43 2016 +0100
@@ -544,7 +544,7 @@
data.slave_config_position = fmmu->sc->position;
data.sync_index = fmmu->sync_index;
data.dir = fmmu->dir;
- data.logical_address = fmmu->logical_start_address;
+ data.logical_address = fmmu->domain->logical_base_address + fmmu->logical_domain_offset;
data.data_size = fmmu->data_size;
up(&master->master_sem);
@@ -864,7 +864,7 @@
return -ENOMEM;
}
- if (copy_from_user(sdo_data, (void __user *) data.data, data.data_size)) {
+ if (copy_from_user(sdo_data, (const void __user *) data.data, data.data_size)) {
kfree(sdo_data);
return -EFAULT;
}
@@ -1913,11 +1913,18 @@
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
+ size_t sent_bytes;
+
if (unlikely(!ctx->requested)) {
return -EPERM;
}
- ecrt_master_send(master);
+ sent_bytes = ecrt_master_send(master);
+
+ if (copy_to_user((void __user *) arg, &sent_bytes, sizeof(sent_bytes))) {
+ return -EFAULT;
+ }
+
return 0;
}
@@ -2254,6 +2261,48 @@
/*****************************************************************************/
+/** Configure wether a slave allows overlapping PDOs.
+ */
+static ATTRIBUTES int ec_ioctl_sc_allow_overlapping_pdos(
+ ec_master_t *master, /**< EtherCAT master. */
+ void *arg, /**< ioctl() argument. */
+ ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
+ )
+{
+ ec_ioctl_config_t data;
+ ec_slave_config_t *sc;
+ int ret = 0;
+
+ if (unlikely(!ctx->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.
*
* \return Zero on success, otherwise a negative error code.
@@ -4447,6 +4496,13 @@
}
ret = ec_ioctl_sc_watchdog(master, arg, ctx);
break;
+ case EC_IOCTL_SC_OVERLAPPING_IO:
+ if (!ctx->writable) {
+ ret = -EPERM;
+ break;
+ }
+ ret = ec_ioctl_sc_allow_overlapping_pdos(master, arg, ctx);
+ break;
case EC_IOCTL_SC_ADD_PDO:
if (!ctx->writable) {
ret = -EPERM;
--- a/master/ioctl.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/ioctl.h Fri Jan 22 13:09:43 2016 +0100
@@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
-#define EC_IOCTL_VERSION_MAGIC 29
+#define EC_IOCTL_VERSION_MAGIC 30
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@@ -153,6 +153,7 @@
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x57, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x58, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x59, size_t)
+#define EC_IOCTL_SC_OVERLAPPING_IO EC_IOW(0x5a, ec_ioctl_config_t)
/*****************************************************************************/
@@ -399,7 +400,7 @@
uint8_t sdo_entry_subindex;
uint8_t complete_access;
size_t data_size;
- uint8_t *data;
+ const uint8_t *data;
// outputs
uint32_t abort_code;
@@ -439,7 +440,7 @@
size_t data_size;
uint32_t result;
uint32_t error_code;
- char file_name[32];
+ char file_name[255];
} ec_ioctl_slave_foe_t;
/*****************************************************************************/
@@ -495,6 +496,7 @@
int32_t slave_position;
uint16_t dc_assign_activate;
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT];
+ uint8_t allow_overlapping_pdos;
} ec_ioctl_config_t;
/*****************************************************************************/
--- a/master/master.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/master.c Fri Jan 22 13:09:43 2016 +0100
@@ -981,7 +981,7 @@
/** Sends the datagrams in the queue for a certain device.
*
*/
-void ec_master_send_datagrams(
+size_t ec_master_send_datagrams(
ec_master_t *master, /**< EtherCAT master */
ec_device_index_t device_index /**< Device index. */
)
@@ -996,6 +996,7 @@
unsigned long jiffies_sent;
unsigned int frame_count, more_datagrams_waiting;
struct list_head sent_datagrams;
+ size_t sent_bytes = 0;
#ifdef EC_HAVE_CYCLES
cycles_start = get_cycles();
@@ -1081,6 +1082,8 @@
// send frame
ec_device_send(&master->devices[device_index],
cur_data - frame_data);
+ /* preamble and inter-frame gap */
+ sent_bytes += ETH_HLEN + cur_data - frame_data + ETH_FCS_LEN + 20;
#ifdef EC_HAVE_CYCLES
cycles_sent = get_cycles();
#endif
@@ -1098,7 +1101,7 @@
frame_count++;
}
- while (more_datagrams_waiting);
+ while (more_datagrams_waiting && frame_count < EC_TX_RING_SIZE);
#ifdef EC_HAVE_CYCLES
if (unlikely(master->debug_level > 1)) {
@@ -1108,6 +1111,7 @@
(unsigned int) (cycles_end - cycles_start) * 1000 / cpu_khz);
}
#endif
+ return sent_bytes;
}
/*****************************************************************************/
@@ -1535,9 +1539,7 @@
{
ec_master_t *master = (ec_master_t *) priv_data;
int fsm_exec;
-#ifdef EC_USE_HRTIMER
size_t sent_bytes;
-#endif
// send interval in IDLE phase
ec_master_set_send_interval(master, 1000000 / HZ);
@@ -1570,11 +1572,7 @@
if (fsm_exec) {
ec_master_queue_datagram(master, &master->fsm_datagram);
}
- ecrt_master_send(master);
-#ifdef EC_USE_HRTIMER
- sent_bytes = master->devices[EC_DEVICE_MAIN].tx_skb[
- master->devices[EC_DEVICE_MAIN].tx_ring_index]->len;
-#endif
+ sent_bytes = ecrt_master_send(master);
up(&master->io_sem);
if (ec_fsm_master_idle(&master->fsm)) {
@@ -1586,7 +1584,8 @@
#endif
} else {
#ifdef EC_USE_HRTIMER
- ec_master_nanosleep(sent_bytes * EC_BYTE_TRANSMISSION_TIME_NS);
+ ec_master_nanosleep(
+ sent_bytes * EC_BYTE_TRANSMISSION_TIME_NS * 6 / 5);
#else
schedule();
#endif
@@ -1785,6 +1784,21 @@
/*****************************************************************************/
+/** Abort active requests for slave configs without attached slaves.
+ */
+void ec_master_expire_slave_config_requests(
+ ec_master_t *master /**< EtherCAT master. */
+ )
+{
+ ec_slave_config_t *sc;
+
+ list_for_each_entry(sc, &master->configs, list) {
+ ec_slave_config_expire_disconnected_requests(sc);
+ }
+}
+
+/*****************************************************************************/
+
/** Common implementation for ec_master_find_slave()
* and ec_master_find_slave_const().
*/
@@ -2224,10 +2238,12 @@
}
}
+#ifdef EC_REFCLKOP
// always set DC reference clock to OP
if (master->dc_ref_clock) {
ec_slave_request_state(master->dc_ref_clock, EC_SLAVE_STATE_OP);
}
+#endif
}
/******************************************************************************
@@ -2430,10 +2446,12 @@
/*****************************************************************************/
-void ecrt_master_send(ec_master_t *master)
+size_t ecrt_master_send(ec_master_t *master)
{
ec_datagram_t *datagram, *n;
ec_device_index_t dev_idx;
+ size_t sent_bytes = 0;
+
if (master->injection_seq_rt != master->injection_seq_fsm) {
// inject datagram produced by master FSM
@@ -2468,8 +2486,11 @@
}
// send frames
- ec_master_send_datagrams(master, dev_idx);
- }
+ sent_bytes = max(sent_bytes,
+ ec_master_send_datagrams(master, dev_idx));
+ }
+
+ return sent_bytes;
}
/*****************************************************************************/
@@ -2832,7 +2853,7 @@
/*****************************************************************************/
int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
- uint16_t index, uint8_t subindex, uint8_t *data,
+ uint16_t index, uint8_t subindex, const uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_sdo_request_t request;
@@ -2916,7 +2937,7 @@
/*****************************************************************************/
int ecrt_master_sdo_download_complete(ec_master_t *master,
- uint16_t slave_position, uint16_t index, uint8_t *data,
+ uint16_t slave_position, uint16_t index, const uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_sdo_request_t request;
--- a/master/master.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/master.h Fri Jan 22 13:09:43 2016 +0100
@@ -351,6 +351,7 @@
// misc.
void ec_master_set_send_interval(ec_master_t *, unsigned int);
void ec_master_attach_slave_configs(ec_master_t *);
+void ec_master_expire_slave_config_requests(ec_master_t *);
ec_slave_t *ec_master_find_slave(ec_master_t *, uint16_t, uint16_t);
const ec_slave_t *ec_master_find_slave_const(const ec_master_t *, uint16_t,
uint16_t);
--- a/master/slave_config.c Fri Jan 22 10:11:58 2016 +0100
+++ b/master/slave_config.c Fri Jan 22 13:09:43 2016 +0100
@@ -70,6 +70,7 @@
sc->vendor_id = vendor_id;
sc->product_code = product_code;
sc->watchdog_divider = 0; // use default
+ sc->allow_overlapping_pdos = 0; // default not allowed
sc->watchdog_intervals = 0; // use default
sc->slave = NULL;
@@ -181,7 +182,7 @@
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->logical_domain_offset;
}
if (sc->used_fmmus == EC_MAX_FMMUS) {
@@ -189,13 +190,44 @@
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);
+
+#if 0 //TODO overlapping PDOs
+ // Overlapping PDO Support from 4751747d4e6d
+ // FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
+ // parent code does not call ec_fmmu_config_domain
+ // FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
+ fmmu_logical_start_address = domain->tx_size;
+ tx_size = fmmu->data_size;
+
+ // FIXME is it enough to take only the *previous* FMMU into account?
+
+ // FIXME Need to qualify allow_overlapping_pdos with slave->sii.general_flags.enable_not_lrw
+
+ 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 != 0) {
+ // prev fmmu has opposite direction
+ // and is not already paired with prev-prev fmmu
+ old_prev_tx_size = prev_fmmu->tx_size;
+ prev_fmmu->tx_size = max(fmmu->data_size, prev_fmmu->data_size);
+ domain->tx_size += prev_fmmu->tx_size - old_prev_tx_size;
+ tx_size = 0;
+ fmmu_logical_start_address = prev_fmmu->logical_domain_offset;
+ }
+ }
+
+ ec_fmmu_config_domain(fmmu, domain, fmmu_logical_start_address, tx_size);
+ // Overlapping PDO Support from 4751747d4e6d
+#endif
+
+ sc->used_fmmus++;
up(&sc->master->master_sem);
- return fmmu->logical_start_address;
+ return fmmu->logical_domain_offset;
}
/*****************************************************************************/
@@ -276,6 +308,10 @@
list_for_each_entry(reg, &sc->reg_requests, list) {
if (sc->slave->fsm.reg_request == reg) {
sc->slave->fsm.reg_request = NULL;
+ EC_SLAVE_WARN(sc->slave, "Aborting register request,"
+ " slave is detaching.\n");
+ reg->state = EC_INT_REQUEST_FAILURE;
+ wake_up_all(&sc->slave->master->request_queue);
break;
}
}
@@ -517,6 +553,36 @@
return NULL;
}
+/*****************************************************************************/
+
+/** Expires any requests that have been started on a detached slave.
+ */
+void ec_slave_config_expire_disconnected_requests(
+ ec_slave_config_t *sc /**< Slave configuration. */
+ )
+{
+ ec_sdo_request_t *sdo_req;
+ ec_reg_request_t *reg_req;
+
+ if (sc->slave) { return; }
+
+ list_for_each_entry(sdo_req, &sc->sdo_requests, list) {
+ if (sdo_req->state == EC_INT_REQUEST_QUEUED ||
+ sdo_req->state == EC_INT_REQUEST_BUSY) {
+ EC_CONFIG_DBG(sc, 1, "Aborting SDO request; no slave attached.\n");
+ sdo_req->state = EC_INT_REQUEST_FAILURE;
+ }
+ }
+
+ list_for_each_entry(reg_req, &sc->reg_requests, list) {
+ if (reg_req->state == EC_INT_REQUEST_QUEUED ||
+ reg_req->state == EC_INT_REQUEST_BUSY) {
+ EC_CONFIG_DBG(sc, 1, "Aborting register request; no slave attached.\n");
+ reg_req->state = EC_INT_REQUEST_FAILURE;
+ }
+ }
+}
+
/******************************************************************************
* Application interface
*****************************************************************************/
@@ -560,6 +626,17 @@
/*****************************************************************************/
+void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
+ uint8_t allow_overlapping_pdos )
+{
+ EC_CONFIG_DBG(sc, 1, "%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)
{
--- a/master/slave_config.h Fri Jan 22 10:11:58 2016 +0100
+++ b/master/slave_config.h Fri Jan 22 13:09:43 2016 +0100
@@ -130,6 +130,8 @@
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. */
@@ -172,6 +174,7 @@
unsigned int);
ec_voe_handler_t *ec_slave_config_find_voe_handler(ec_slave_config_t *,
unsigned int);
+void ec_slave_config_expire_disconnected_requests(ec_slave_config_t *);
ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
ec_slave_config_t *, uint16_t, uint8_t, size_t);
--- a/script/init.d/ethercat.in Fri Jan 22 10:11:58 2016 +0100
+++ b/script/init.d/ethercat.in Fri Jan 22 13:09:43 2016 +0100
@@ -227,6 +227,7 @@
$0 stop || exit 1
sleep 1
$0 start
+ exit
;;
status)
--- a/tool/CommandDownload.cpp Fri Jan 22 10:11:58 2016 +0100
+++ b/tool/CommandDownload.cpp Fri Jan 22 13:09:43 2016 +0100
@@ -173,16 +173,17 @@
throwCommandException(err);
}
data.data_size = contents.size();
- data.data = new uint8_t[data.data_size + 1];
+ uint8_t *sdo_data = new uint8_t[data.data_size + 1];
+ data.data = sdo_data;
try {
data.data_size = interpretAsType(
- dataType, contents, data.data, data.data_size);
+ dataType, contents, sdo_data, data.data_size);
} catch (SizeException &e) {
- delete [] data.data;
+ delete [] sdo_data;
throwCommandException(e.what());
} catch (ios::failure &e) {
- delete [] data.data;
+ delete [] sdo_data;
err << "Invalid value argument '" << args[2]
<< "' for type '" << dataType->name << "'!";
throwInvalidUsageException(err);
@@ -195,16 +196,17 @@
data.data_size = DefaultBufferSize;
}
- data.data = new uint8_t[data.data_size + 1];
+ uint8_t *sdo_data = new uint8_t[data.data_size + 1];
+ data.data = sdo_data;
try {
data.data_size = interpretAsType(
- dataType, args[valueIndex], data.data, data.data_size);
+ dataType, args[valueIndex], sdo_data, data.data_size);
} catch (SizeException &e) {
- delete [] data.data;
+ delete [] sdo_data;
throwCommandException(e.what());
} catch (ios::failure &e) {
- delete [] data.data;
+ delete [] sdo_data;
err << "Invalid value argument '" << args[2]
<< "' for type '" << dataType->name << "'!";
throwInvalidUsageException(err);
@@ -212,19 +214,6 @@
}
try {
- data.data_size = interpretAsType(
- dataType, args[valueIndex], data.data, data.data_size);
- } catch (SizeException &e) {
- delete [] data.data;
- throwCommandException(e.what());
- } catch (ios::failure &e) {
- delete [] data.data;
- err << "Invalid value argument '" << args[2]
- << "' for type '" << dataType->name << "'!";
- throwInvalidUsageException(err);
- }
-
- try {
m.sdoDownload(&data);
} catch (MasterDeviceSdoAbortException &e) {
delete [] data.data;
--- a/tool/DataTypeHandler.cpp Fri Jan 22 10:11:58 2016 +0100
+++ b/tool/DataTypeHandler.cpp Fri Jan 22 13:09:43 2016 +0100
@@ -33,6 +33,7 @@
#include <iostream>
#endif
+#include <string.h>
#include <iomanip>
#include <sstream>
using namespace std;
@@ -106,6 +107,8 @@
stringstream str;
size_t dataSize = type->byteSize;
+ memset(target, 0, targetSize);
+
#if DEBUG
cerr << __func__ << "(targetSize=" << targetSize << ")" << endl;
#endif
@@ -192,7 +195,7 @@
<< dataSize << " > " << targetSize << ")";
throw SizeException(err.str());
}
- str >> (char *) target;
+ str.read((char *) target, dataSize);
break;
case 0x0011: // double
{