This commit is contained in:
Florian Pose 2016-01-22 13:09:43 +01:00
commit 4d70145d53
25 changed files with 627 additions and 144 deletions

View File

@ -119,7 +119,11 @@ mrproper: clean cleandoc
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

View File

@ -819,6 +819,35 @@ else
AC_MSG_RESULT([no])
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
#-----------------------------------------------------------------------------

View File

@ -815,7 +815,7 @@ int ecrt_master_sdo_download(
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 @@ int ecrt_master_sdo_download_complete(
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 @@ int ecrt_master_set_send_interval(
*
* Has to be called cyclically by the application after ecrt_master_activate()
* has returned.
*
* Returns the number of bytes sent.
*/
void ecrt_master_send(
size_t ecrt_master_send(
ec_master_t *master /**< EtherCAT master. */
);
@ -1145,6 +1147,17 @@ void ecrt_slave_config_watchdog(
*/
);
/** 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

View File

@ -60,6 +60,11 @@ void ec_master_clear_config(ec_master_t *master)
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_config(ec_master_t *master)
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_get_pdo_entry(ec_master_t *master, uint16_t slave_position,
/****************************************************************************/
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(ec_master_t *master, uint16_t slave_position,
/****************************************************************************/
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 @@ int ecrt_master_set_send_interval(ec_master_t *master,
/****************************************************************************/
void ecrt_master_send(ec_master_t *master)
size_t ecrt_master_send(ec_master_t *master)
{
int ret;
size_t sent_bytes = 0;
ret = ioctl(master->fd, EC_IOCTL_SEND, NULL);
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 @@ int ecrt_master_reference_clock_time(ec_master_t *master, uint32_t *time)
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)));
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 ret;
return 0;
}
/****************************************************************************/

View File

@ -120,6 +120,23 @@ void ecrt_slave_config_watchdog(ec_slave_config_t *sc,
/*****************************************************************************/
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)
{

View File

@ -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"

186
master/domain.c Normal file → Executable file
View File

@ -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 @@ void ec_domain_init(
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 @@ void ec_domain_add_fmmu_config(
ec_fmmu_config_t *fmmu /**< FMMU configuration. */
)
{
fmmu->domain = domain;
const ec_slave_config_t *sc;
uint32_t logical_domain_offset;
unsigned fmmu_data_size;
fmmu->domain = domain;
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);
domain->data_size += 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 @@ int ec_domain_add_datagram_pair(
*
* \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 @@ int shall_count(
/*****************************************************************************/
/** 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 @@ int ec_domain_finish(
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 @@ int ec_domain_finish(
// - 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 (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;
// 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_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;
}
datagram_size += 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 @@ int ec_domain_finish(
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 @@ void ecrt_domain_process(ec_domain_t *domain)
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,

5
master/domain.h Normal file → Executable file
View File

@ -72,6 +72,11 @@ struct ec_domain
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() ) */
};
/*****************************************************************************/

View File

@ -79,6 +79,7 @@ int ec_eoedev_open(struct net_device *);
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 @@ static const struct net_device_ops ec_eoedev_ops = {
.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 @@ int ec_eoe_init(
)
{
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 @@ int ec_eoe_init(
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 @@ int ec_eoe_init(
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 @@ int ec_eoe_send(ec_eoe_t *eoe /**< EoE handler */)
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;
}

23
master/fmmu_config.c Normal file → Executable file
View File

@ -60,13 +60,23 @@ void ec_fmmu_config_init(
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 @@ void ec_fmmu_config_page(
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

12
master/fmmu_config.h Normal file → Executable file
View File

@ -49,7 +49,8 @@ typedef struct {
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 @@ typedef struct {
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 *);

View File

@ -42,9 +42,10 @@
/*****************************************************************************/
/** Maximum time in ms to wait for responses when reading out the dictionary.
/** Maximum time in jiffies to wait for responses when reading out the
* dictionary.
*/
#define EC_FSM_FOE_TIMEOUT 3000
#define EC_FSM_FOE_TIMEOUT_JIFFIES (3 * HZ)
/** Size of the FoE header.
*/
@ -256,6 +257,10 @@ int ec_foe_prepare_data_send(
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 @@ int ec_foe_prepare_wrq_send(
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 @@ void ec_fsm_foe_state_ack_check(
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 @@ void ec_fsm_foe_state_ack_read(
}
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 @@ void ec_fsm_foe_state_ack_read(
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 @@ int ec_foe_prepare_rrq_send(
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 @@ int ec_foe_prepare_send_ack(
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 @@ void ec_fsm_foe_state_data_check(
}
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 @@ void ec_fsm_foe_state_data_read(
)
{
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 @@ void ec_fsm_foe_state_data_read(
}
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 @@ void ec_fsm_foe_state_data_read(
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 @@ void ec_fsm_foe_state_data_read(
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;
}

View File

@ -246,6 +246,9 @@ void ec_fsm_master_state_start(
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 @@ int ec_fsm_master_action_process_sdo(
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) {

View File

@ -201,6 +201,18 @@ void ec_fsm_slave_state_ready(
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;

8
master/fsm_slave_config.c Normal file → Executable file
View File

@ -1399,8 +1399,12 @@ void ec_fsm_slave_config_state_dc_sync_check(
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);

6
master/globals.h Normal file → Executable file
View File

@ -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

62
master/ioctl.c Normal file → Executable file
View File

@ -544,7 +544,7 @@ static ATTRIBUTES int ec_ioctl_domain_fmmu(
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 @@ static ATTRIBUTES int ec_ioctl_slave_sdo_download(
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 @@ static ATTRIBUTES int ec_ioctl_send(
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 @@ out_return:
/*****************************************************************************/
/** 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 @@ long EC_IOCTL(
}
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;

View File

@ -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 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
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;
/*****************************************************************************/

View File

@ -981,7 +981,7 @@ void ec_master_queue_datagram_ext(
/** 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 @@ void ec_master_send_datagrams(
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 @@ void ec_master_send_datagrams(
// 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 @@ void ec_master_send_datagrams(
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 @@ void ec_master_send_datagrams(
(unsigned int) (cycles_end - cycles_start) * 1000 / cpu_khz);
}
#endif
return sent_bytes;
}
/*****************************************************************************/
@ -1535,9 +1539,7 @@ static int ec_master_idle_thread(void *priv_data)
{
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 @@ static int ec_master_idle_thread(void *priv_data)
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 @@ static int ec_master_idle_thread(void *priv_data)
#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 @@ void ec_master_attach_slave_configs(
/*****************************************************************************/
/** 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 @@ void ec_master_request_op(
}
}
#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_deactivate(ec_master_t *master)
/*****************************************************************************/
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 @@ void ecrt_master_send(ec_master_t *master)
}
// 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 @@ uint32_t ecrt_master_sync_monitor_process(ec_master_t *master)
/*****************************************************************************/
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(ec_master_t *master, uint16_t slave_position,
/*****************************************************************************/
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;

View File

@ -351,6 +351,7 @@ void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
// 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);

83
master/slave_config.c Normal file → Executable file
View File

@ -70,6 +70,7 @@ void ec_slave_config_init(
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 @@ int ec_slave_config_prepare_fmmu(
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 @@ int ec_slave_config_prepare_fmmu(
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 @@ void ec_slave_config_detach(
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 @@ ec_voe_handler_t *ec_slave_config_find_voe_handler(
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_watchdog(ec_slave_config_t *sc,
/*****************************************************************************/
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)
{

3
master/slave_config.h Normal file → Executable file
View File

@ -130,6 +130,8 @@ struct ec_slave_config {
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 @@ ec_reg_request_t *ec_slave_config_find_reg_request(ec_slave_config_t *,
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);

View File

@ -227,6 +227,7 @@ restart)
$0 stop || exit 1
sleep 1
$0 start
exit
;;
status)

View File

@ -173,16 +173,17 @@ void CommandDownload::execute(const StringVector &args)
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,35 +196,23 @@ void CommandDownload::execute(const StringVector &args)
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);
}
}
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) {

View File

@ -33,6 +33,7 @@
#include <iostream>
#endif
#include <string.h>
#include <iomanip>
#include <sstream>
using namespace std;
@ -106,6 +107,8 @@ size_t DataTypeHandler::interpretAsType(
stringstream str;
size_t dataSize = type->byteSize;
memset(target, 0, targetSize);
#if DEBUG
cerr << __func__ << "(targetSize=" << targetSize << ")" << endl;
#endif
@ -192,7 +195,7 @@ size_t DataTypeHandler::interpretAsType(
<< dataSize << " > " << targetSize << ")";
throw SizeException(err.str());
}
str >> (char *) target;
str.read((char *) target, dataSize);
break;
case 0x0011: // double
{