merge
This commit is contained in:
commit
4d70145d53
|
|
@ -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
|
||||
|
|
|
|||
29
configure.ac
29
configure.ac
|
|
@ -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
|
||||
#-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
31
lib/master.c
31
lib/master.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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() ) */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ restart)
|
|||
$0 stop || exit 1
|
||||
sleep 1
|
||||
$0 start
|
||||
exit
|
||||
;;
|
||||
|
||||
status)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue