mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-08-17 16:51:44 +08:00
Implemented ecrt_slave_config_pdo_mode() interface.
This commit is contained in:
@@ -14,4 +14,5 @@ filter=-whitespace/comments
|
||||
filter=-whitespace/empty_loop_body
|
||||
filter=-whitespace/indent
|
||||
filter=-whitespace/newline
|
||||
filter=-whitespace/parens
|
||||
linelength=78
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
## Version 1.7.0
|
||||
|
||||
- Added `ecrt_slave_config_pdo_mode()` to select whether a slave's PDO
|
||||
assignment and PDO configuration are read from resp. written to it via
|
||||
CoE, for slaves with a fixed or otherwise well-known PDO layout.
|
||||
- Added SII caching functionality with
|
||||
- the kernel module parameter `sii_caching`,
|
||||
- the configuration variable `SII_CACHING`,
|
||||
|
||||
@@ -639,6 +639,15 @@ int ecrt_slave_config_watchdog(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecrt_slave_config_pdo_mode(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
ec_pdo_mode_t assign_mode, /**< Mode for the PDO assignment. */
|
||||
ec_pdo_mode_t config_mode /**< Mode for the PDO configuration. */
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecrt_slave_config_pdo_assign_add(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
uint8_t sync_index, /**< Sync manager index. Must be less
|
||||
|
||||
+97
-1
@@ -36,6 +36,9 @@
|
||||
* - Added ecrt_master_sii_caching() to set the SII caching method and added
|
||||
* the feature flag EC_HAVE_SII_CACHING and the enum type
|
||||
* ec_sii_caching_fields_t.
|
||||
* - Added ecrt_slave_config_pdo_mode() to select whether a slave's PDO
|
||||
* assignment and PDO configuration are read from resp. written to it via
|
||||
* CoE, the enum type ec_pdo_mode_t and the feature flag EC_HAVE_PDO_MODE.
|
||||
*
|
||||
* Changes in version 1.6.0:
|
||||
*
|
||||
@@ -252,6 +255,11 @@
|
||||
*/
|
||||
#define EC_HAVE_SII_CACHING
|
||||
|
||||
/** Defined, if the method ecrt_slave_config_pdo_mode() and the enum type
|
||||
* ec_pdo_mode_t are available.
|
||||
*/
|
||||
#define EC_HAVE_PDO_MODE
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Symbol visibility control macro.
|
||||
@@ -394,7 +402,7 @@ typedef struct {
|
||||
- 8: \a OP
|
||||
|
||||
Note that each state is coded in a different
|
||||
bit! */
|
||||
bit. */
|
||||
} ec_slave_config_state_t;
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -532,6 +540,42 @@ typedef enum {
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** PDO handling mode.
|
||||
*
|
||||
* Used for the \a assign_mode and \a config_mode parameters of
|
||||
* ecrt_slave_config_pdo_mode() to select whether a slave's PDO assignment
|
||||
* (which PDOs are mapped into a sync manager, CoE objects 0x1C10-0x1C13)
|
||||
* resp. its PDO configuration (the entries mapped into an assigned PDO) are
|
||||
* read from resp. written to the slave via CoE.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_PDO_MODE_FIXED, /**< Neither read nor write via CoE. Trust that the
|
||||
slave already matches the layout given via
|
||||
ecrt_slave_config_pdos() and friends. */
|
||||
EC_PDO_MODE_WRITE, /**< Write the configured state via CoE every time
|
||||
the slave is configured, without reading the
|
||||
current state first ("blind write"). */
|
||||
EC_PDO_MODE_READ_WRITE, /**< Read the current state via CoE while
|
||||
scanning the slave, and unconditionally
|
||||
(re-)write it every time the slave is
|
||||
configured. This is the default. */
|
||||
EC_PDO_MODE_WRITE_IF_DIFFERENT, /**< Read the current state via CoE
|
||||
while scanning the slave, and write
|
||||
it back only if it differs from the
|
||||
configured state. */
|
||||
} ec_pdo_mode_t;
|
||||
|
||||
/** Default PDO handling mode: read via CoE while scanning, and
|
||||
* unconditionally (re-)write via CoE every time the slave is configured.
|
||||
* This is the behavior in effect if ecrt_slave_config_pdo_mode() is never
|
||||
* called.
|
||||
*
|
||||
* \see ec_pdo_mode_t
|
||||
*/
|
||||
#define EC_PDO_MODE_DEFAULT EC_PDO_MODE_READ_WRITE
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** PDO entry configuration information.
|
||||
*
|
||||
* This is the data type of the \a entries field in ec_pdo_info_t.
|
||||
@@ -1444,6 +1488,58 @@ EC_PUBLIC_API int ecrt_slave_config_watchdog(
|
||||
so the default is used. */
|
||||
);
|
||||
|
||||
/** Selects how a slave's PDO assignment and PDO configuration are read
|
||||
* from resp. written to it via CoE.
|
||||
*
|
||||
* By default (i. e. if this method is not called), a slave's PDO
|
||||
* assignment and PDO configuration are both read via CoE while the bus is
|
||||
* scanned, and are both unconditionally (re-)written via CoE every time
|
||||
* the slave is configured (e. g. after a state change or reconnect). For
|
||||
* slaves with a fixed or otherwise well-known PDO structure, this can be
|
||||
* relaxed independently for the assignment and the configuration, to save
|
||||
* mailbox round trips during bus scanning and/or slave configuration.
|
||||
*
|
||||
* If \a assign_mode resp. \a config_mode is EC_PDO_MODE_FIXED or
|
||||
* EC_PDO_MODE_WRITE, the corresponding aspect is not read from the slave
|
||||
* while scanning; the master then relies solely on the PDO configuration
|
||||
* made available through ecrt_slave_config_pdos(),
|
||||
* ecrt_slave_config_sync_manager(), ecrt_slave_config_pdo_assign_add()
|
||||
* and ecrt_slave_config_pdo_mapping_add(). The application is responsible
|
||||
* for making sure this matches the slave's actual capabilities in that
|
||||
* case.
|
||||
*
|
||||
* \note Reading the PDO configuration requires first discovering the PDO
|
||||
* assignment (which PDOs exist), since the master must know a PDO's index
|
||||
* before it can query its entries. Therefore, whenever \a config_mode is
|
||||
* EC_PDO_MODE_READ_WRITE or EC_PDO_MODE_WRITE_IF_DIFFERENT, the PDO
|
||||
* assignment is read while scanning the bus as well, regardless of \a
|
||||
* assign_mode. This is harmless, but means that the mailbox traffic saved
|
||||
* by choosing EC_PDO_MODE_FIXED or EC_PDO_MODE_WRITE for \a assign_mode is
|
||||
* not realized in that particular combination.
|
||||
*
|
||||
* \attention Because bus scanning happens before slave configurations are
|
||||
* attached to their slaves, a non-default \a assign_mode or \a
|
||||
* config_mode is only guaranteed to take effect for the scanning of a
|
||||
* slave if this method is called (i. e. the slave configuration is
|
||||
* created via ecrt_master_slave_config()) before that slave is scanned
|
||||
* for the first time. Otherwise, the scan falls back to the default
|
||||
* (reading) behavior for that particular scan; a subsequent bus rescan
|
||||
* (e. g. via the "ethercat rescan" command) will pick up the configured
|
||||
* mode.
|
||||
*
|
||||
* This method has to be called in non-realtime context before
|
||||
* ecrt_master_activate().
|
||||
*
|
||||
* \apiusage{master_idle,blocking}
|
||||
*
|
||||
* \return 0 on success, otherwise negative error code.
|
||||
*/
|
||||
EC_PUBLIC_API int ecrt_slave_config_pdo_mode(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
ec_pdo_mode_t assign_mode, /**< Mode for the PDO assignment. */
|
||||
ec_pdo_mode_t config_mode /**< Mode for the PDO configuration. */
|
||||
);
|
||||
|
||||
/** Add a PDO to a sync manager's PDO assignment.
|
||||
*
|
||||
* This method has to be called in non-realtime context before
|
||||
|
||||
@@ -119,4 +119,5 @@ LIBETHERCAT_1.6 {
|
||||
LIBETHERCAT_1.7 {
|
||||
global:
|
||||
ecrt_master_sii_caching;
|
||||
ecrt_slave_config_pdo_mode;
|
||||
} LIBETHERCAT_1.6;
|
||||
|
||||
+24
-2
@@ -139,6 +139,28 @@ int ecrt_slave_config_watchdog(ec_slave_config_t *sc,
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_mode(ec_slave_config_t *sc,
|
||||
ec_pdo_mode_t assign_mode, ec_pdo_mode_t config_mode)
|
||||
{
|
||||
ec_ioctl_config_t data;
|
||||
int ret;
|
||||
|
||||
memset(&data, 0x00, sizeof(ec_ioctl_config_t));
|
||||
data.config_index = sc->index;
|
||||
data.pdo_assign_mode = assign_mode;
|
||||
data.pdo_config_mode = config_mode;
|
||||
|
||||
ret = ioctl(sc->master->fd, EC_IOCTL_SC_PDO_MODE, &data);
|
||||
if (EC_IOCTL_IS_ERROR(ret)) {
|
||||
fprintf(stderr, "Failed to set PDO mode: %s\n",
|
||||
strerror(EC_IOCTL_ERRNO(ret)));
|
||||
return -EC_IOCTL_ERRNO(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
|
||||
uint8_t sync_index, uint16_t pdo_index)
|
||||
{
|
||||
@@ -258,7 +280,6 @@ int ecrt_slave_config_pdos(ec_slave_config_t *sc,
|
||||
ecrt_slave_config_pdo_assign_clear(sc, sync_info->index);
|
||||
|
||||
if (sync_info->n_pdos && sync_info->pdos) {
|
||||
|
||||
for (j = 0; j < sync_info->n_pdos; j++) {
|
||||
pdo_info = &sync_info->pdos[j];
|
||||
|
||||
@@ -846,7 +867,8 @@ int ecrt_slave_config_state(const ec_slave_config_t *sc,
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_idn(ec_slave_config_t *sc, uint8_t drive_no,
|
||||
uint16_t idn, ec_al_state_t al_state, const uint8_t *data, size_t size)
|
||||
uint16_t idn, ec_al_state_t al_state, const uint8_t *data,
|
||||
size_t size)
|
||||
{
|
||||
ec_ioctl_sc_idn_t io;
|
||||
int ret;
|
||||
|
||||
+66
-4
@@ -39,6 +39,7 @@ void ec_fsm_pdo_print(const ec_fsm_pdo_t *);
|
||||
int ec_fsm_pdo_running(const ec_fsm_pdo_t *);
|
||||
ec_pdo_t *ec_fsm_pdo_conf_action_next_pdo(const ec_fsm_pdo_t *,
|
||||
const struct list_head *);
|
||||
static int ec_pdo_mode_reads(ec_pdo_mode_t);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -118,10 +119,16 @@ void ec_fsm_pdo_print(
|
||||
*/
|
||||
void ec_fsm_pdo_start_reading(
|
||||
ec_fsm_pdo_t *fsm, /**< PDO configuration state machine. */
|
||||
ec_slave_t *slave /**< slave to configure */
|
||||
ec_slave_t *slave, /**< slave to configure */
|
||||
ec_pdo_mode_t assign_mode, /**< Whether/how to read the PDO
|
||||
assignment. */
|
||||
ec_pdo_mode_t config_mode /**< Whether/how to read the PDO
|
||||
configuration. */
|
||||
)
|
||||
{
|
||||
fsm->slave = slave;
|
||||
fsm->assign_mode = assign_mode;
|
||||
fsm->config_mode = config_mode;
|
||||
fsm->state = ec_fsm_pdo_read_state_start;
|
||||
}
|
||||
|
||||
@@ -184,6 +191,18 @@ int ec_fsm_pdo_success(
|
||||
return fsm->state == ec_fsm_pdo_state_end;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Returns, if the given PDO handling mode implies reading via CoE.
|
||||
*/
|
||||
static int ec_pdo_mode_reads(
|
||||
ec_pdo_mode_t mode /**< PDO handling mode. */
|
||||
)
|
||||
{
|
||||
return mode == EC_PDO_MODE_READ_WRITE
|
||||
|| mode == EC_PDO_MODE_WRITE_IF_DIFFERENT;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Reading state funtions.
|
||||
****************************************************************************/
|
||||
@@ -217,6 +236,13 @@ void ec_fsm_pdo_read_action_next_sync(
|
||||
if (!(fsm->sync = ec_slave_get_sync(slave, fsm->sync_index)))
|
||||
continue;
|
||||
|
||||
// reading the PDO configuration requires first discovering the PDO
|
||||
// assignment, so a read is done if either aspect is to be read
|
||||
if (!ec_pdo_mode_reads(fsm->assign_mode)
|
||||
&& !ec_pdo_mode_reads(fsm->config_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Reading PDO assignment of SM%u.\n",
|
||||
fsm->sync_index);
|
||||
|
||||
@@ -344,6 +370,14 @@ void ec_fsm_pdo_read_state_pdo(
|
||||
|
||||
list_add_tail(&fsm->pdo->list, &fsm->pdos.list);
|
||||
|
||||
if (!ec_pdo_mode_reads(fsm->config_mode)) {
|
||||
// PDO assignment only; the entries mapped into this PDO are not
|
||||
// to be read
|
||||
fsm->pdo_pos++;
|
||||
ec_fsm_pdo_read_action_next_pdo(fsm, datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
fsm->state = ec_fsm_pdo_read_state_pdo_entries;
|
||||
ec_fsm_pdo_entry_start_reading(&fsm->fsm_pdo_entry, fsm->slave, fsm->pdo);
|
||||
fsm->state(fsm, datagram); // execute immediately
|
||||
@@ -429,6 +463,9 @@ void ec_fsm_pdo_conf_action_next_sync(
|
||||
return;
|
||||
}
|
||||
|
||||
fsm->assign_mode = fsm->slave->config->pdo_assign_mode;
|
||||
fsm->config_mode = fsm->slave->config->pdo_config_mode;
|
||||
|
||||
if (ec_pdo_list_copy(&fsm->pdos,
|
||||
&fsm->slave->config->sync_configs[fsm->sync_index].pdos))
|
||||
{
|
||||
@@ -479,7 +516,8 @@ void ec_fsm_pdo_conf_action_pdo_mapping(
|
||||
ec_pdo_clear_entries(&fsm->slave_pdo);
|
||||
}
|
||||
|
||||
if (list_empty(&fsm->slave_pdo.entries)) {
|
||||
if (list_empty(&fsm->slave_pdo.entries)
|
||||
&& ec_pdo_mode_reads(fsm->config_mode)) {
|
||||
EC_SLAVE_DBG(fsm->slave, 1, "Reading mapping of PDO 0x%04X.\n",
|
||||
fsm->pdo->index);
|
||||
|
||||
@@ -528,12 +566,24 @@ void ec_fsm_pdo_conf_action_check_mapping(
|
||||
ec_datagram_t *datagram /**< Datagram to use. */
|
||||
)
|
||||
{
|
||||
if (fsm->config_mode == EC_PDO_MODE_FIXED) {
|
||||
// PDO configuration is trusted to already match; do not touch it
|
||||
ec_fsm_pdo_conf_action_next_pdo_mapping(fsm, datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
// check, if slave supports PDO configuration
|
||||
if ((fsm->slave->sii.mailbox_protocols & EC_MBOX_COE)
|
||||
&& fsm->slave->sii.has_general
|
||||
&& fsm->slave->sii.coe_details.enable_pdo_configuration) {
|
||||
if (fsm->config_mode == EC_PDO_MODE_WRITE_IF_DIFFERENT
|
||||
&& ec_pdo_equal_entries(fsm->pdo, &fsm->slave_pdo)) {
|
||||
// mapping already matches the desired configuration
|
||||
ec_fsm_pdo_conf_action_next_pdo_mapping(fsm, datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
// always write PDO mapping
|
||||
// write PDO mapping
|
||||
ec_fsm_pdo_entry_start_configuration(&fsm->fsm_pdo_entry, fsm->slave,
|
||||
fsm->pdo, &fsm->slave_pdo);
|
||||
fsm->state = ec_fsm_pdo_conf_state_mapping;
|
||||
@@ -603,11 +653,23 @@ void ec_fsm_pdo_conf_action_check_assignment(
|
||||
ec_datagram_t *datagram /**< Datagram to use. */
|
||||
)
|
||||
{
|
||||
if (fsm->assign_mode == EC_PDO_MODE_FIXED) {
|
||||
// PDO assignment is trusted to already match; do not touch it
|
||||
ec_fsm_pdo_conf_action_next_sync(fsm, datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((fsm->slave->sii.mailbox_protocols & EC_MBOX_COE)
|
||||
&& fsm->slave->sii.has_general
|
||||
&& fsm->slave->sii.coe_details.enable_pdo_assign) {
|
||||
if (fsm->assign_mode == EC_PDO_MODE_WRITE_IF_DIFFERENT
|
||||
&& ec_pdo_list_equal(&fsm->sync->pdos, &fsm->pdos)) {
|
||||
// assignment already matches the desired configuration
|
||||
ec_fsm_pdo_conf_action_next_sync(fsm, datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
// always write PDO assignment
|
||||
// write PDO assignment
|
||||
if (fsm->slave->master->debug_level) {
|
||||
EC_SLAVE_DBG(fsm->slave, 1, "Setting PDO assignment of SM%u:\n",
|
||||
fsm->sync_index);
|
||||
|
||||
+10
-1
@@ -58,6 +58,14 @@ struct ec_fsm_pdo
|
||||
ec_pdo_t *pdo; /**< Current PDO. */
|
||||
unsigned int pdo_pos; /**< Assignment position of current PDOs. */
|
||||
unsigned int pdo_count; /**< Number of assigned PDOs. */
|
||||
|
||||
ec_pdo_mode_t assign_mode; /**< Whether/how to read resp. write the PDO
|
||||
assignment. Set once by
|
||||
ec_fsm_pdo_start_reading() for reading, or
|
||||
refreshed from fsm->slave->config for each
|
||||
sync manager while writing. */
|
||||
ec_pdo_mode_t config_mode; /**< Whether/how to read resp. write the PDO
|
||||
configuration. See \a assign_mode. */
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -65,7 +73,8 @@ struct ec_fsm_pdo
|
||||
void ec_fsm_pdo_init(ec_fsm_pdo_t *, ec_fsm_coe_t *);
|
||||
void ec_fsm_pdo_clear(ec_fsm_pdo_t *);
|
||||
|
||||
void ec_fsm_pdo_start_reading(ec_fsm_pdo_t *, ec_slave_t *);
|
||||
void ec_fsm_pdo_start_reading(ec_fsm_pdo_t *, ec_slave_t *,
|
||||
ec_pdo_mode_t, ec_pdo_mode_t);
|
||||
void ec_fsm_pdo_start_configuration(ec_fsm_pdo_t *, ec_slave_t *);
|
||||
|
||||
int ec_fsm_pdo_exec(ec_fsm_pdo_t *, ec_datagram_t *);
|
||||
|
||||
+23
-1
@@ -1056,10 +1056,32 @@ void ec_fsm_slave_scan_enter_pdos(
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
ec_pdo_mode_t assign_mode = EC_PDO_MODE_DEFAULT;
|
||||
ec_pdo_mode_t config_mode = EC_PDO_MODE_DEFAULT;
|
||||
const ec_slave_config_t *sc;
|
||||
|
||||
// Look up a not-yet-attached configuration for this slave (attaching
|
||||
// only happens after the whole bus has been scanned) to find out if
|
||||
// the application requested non-default PDO scanning behavior.
|
||||
if ((sc = ec_master_find_config_for_slave(slave->master, slave))) {
|
||||
assign_mode = sc->pdo_assign_mode;
|
||||
config_mode = sc->pdo_config_mode;
|
||||
}
|
||||
|
||||
if (assign_mode == EC_PDO_MODE_FIXED
|
||||
|| assign_mode == EC_PDO_MODE_WRITE) {
|
||||
if (config_mode == EC_PDO_MODE_FIXED
|
||||
|| config_mode == EC_PDO_MODE_WRITE) {
|
||||
EC_SLAVE_DBG(slave, 1, "Skipping PDO scanning"
|
||||
" (fixed PDO assignment/configuration).\n");
|
||||
fsm->state = ec_fsm_slave_scan_state_end;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Scanning PDO assignment and mapping.\n");
|
||||
fsm->state = ec_fsm_slave_scan_state_pdos;
|
||||
ec_fsm_pdo_start_reading(fsm->fsm_pdo, slave);
|
||||
ec_fsm_pdo_start_reading(fsm->fsm_pdo, slave, assign_mode, config_mode);
|
||||
ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram); // execute immediately
|
||||
}
|
||||
|
||||
|
||||
+63
-5
@@ -63,7 +63,8 @@
|
||||
# define ec_ioctl_lock(lock) rt_mutex_lock(lock)
|
||||
# define ec_ioctl_unlock(lock) rt_mutex_unlock(lock)
|
||||
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) || \
|
||||
(defined(CONFIG_PREEMPT_RT_FULL) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
|
||||
(defined(CONFIG_PREEMPT_RT_FULL) && \
|
||||
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
|
||||
# define ec_ioctl_lock_interruptible(lock) \
|
||||
rt_mutex_lock_interruptible(lock)
|
||||
# else
|
||||
@@ -650,7 +651,7 @@ static ATTRIBUTES int ec_ioctl_master_rescan(
|
||||
)
|
||||
{
|
||||
EC_MASTER_DBG(master, 1, "Got rescan command via ioctl()."
|
||||
" Re-scanning on next possibility.\n");
|
||||
" Re-scanning on next possibility.\n");
|
||||
master->fsm.rescan_required = 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -896,8 +897,9 @@ static ATTRIBUTES int ec_ioctl_slave_sdo_download(
|
||||
}
|
||||
|
||||
if (data.complete_access) {
|
||||
retval = ecrt_master_sdo_download_complete(master, data.slave_position,
|
||||
data.sdo_index, sdo_data, data.data_size, &data.abort_code);
|
||||
retval = ecrt_master_sdo_download_complete(master,
|
||||
data.slave_position, data.sdo_index, sdo_data, data.data_size,
|
||||
&data.abort_code);
|
||||
} else {
|
||||
retval = ecrt_master_sdo_download(master, data.slave_position,
|
||||
data.sdo_index, data.sdo_entry_subindex, sdo_data,
|
||||
@@ -1262,6 +1264,8 @@ static ATTRIBUTES int ec_ioctl_config(
|
||||
}
|
||||
data.watchdog_divider = sc->watchdog_divider;
|
||||
data.watchdog_intervals = sc->watchdog_intervals;
|
||||
data.pdo_assign_mode = sc->pdo_assign_mode;
|
||||
data.pdo_config_mode = sc->pdo_config_mode;
|
||||
data.sdo_count = ec_slave_config_sdo_count(sc);
|
||||
data.idn_count = ec_slave_config_idn_count(sc);
|
||||
data.flag_count = ec_slave_config_flag_count(sc);
|
||||
@@ -1716,6 +1720,7 @@ static ATTRIBUTES int ec_ioctl_eoe_handler(
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef EC_EOE
|
||||
|
||||
/** Request EoE IP parameter setting.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
@@ -1796,9 +1801,10 @@ static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param(
|
||||
|
||||
return req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/** Request the master from userspace.
|
||||
*
|
||||
@@ -2505,6 +2511,51 @@ out_return:
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Configure a slave's PDO handling mode.
|
||||
*
|
||||
* \return Zero on success, otherwise a negative error code.
|
||||
*/
|
||||
static ATTRIBUTES int ec_ioctl_sc_pdo_mode(
|
||||
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;
|
||||
}
|
||||
|
||||
ret = ecrt_slave_config_pdo_mode(sc,
|
||||
data.pdo_assign_mode, data.pdo_config_mode);
|
||||
|
||||
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.
|
||||
@@ -5453,6 +5504,13 @@ static long ec_ioctl_nrt
|
||||
}
|
||||
ret = ec_ioctl_sc_watchdog(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_PDO_MODE:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
ret = ec_ioctl_sc_pdo_mode(master, arg, ctx);
|
||||
break;
|
||||
case EC_IOCTL_SC_ADD_PDO:
|
||||
if (!ctx->writable) {
|
||||
ret = -EPERM;
|
||||
|
||||
+6
-3
@@ -162,6 +162,7 @@
|
||||
#define EC_IOCTL_VOE_DATA EC_IOWR(0x65, ec_ioctl_voe_t)
|
||||
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x66, size_t)
|
||||
#define EC_IOCTL_SII_CACHING EC_IOW(0x67, uint32_t)
|
||||
#define EC_IOCTL_SC_PDO_MODE EC_IOW(0x68, ec_ioctl_config_t)
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -501,6 +502,8 @@ typedef struct {
|
||||
} syncs[EC_MAX_SYNC_MANAGERS];
|
||||
uint16_t watchdog_divider;
|
||||
uint16_t watchdog_intervals;
|
||||
ec_pdo_mode_t pdo_assign_mode;
|
||||
ec_pdo_mode_t pdo_config_mode;
|
||||
uint32_t sdo_count;
|
||||
uint32_t idn_count;
|
||||
uint32_t flag_count;
|
||||
@@ -645,11 +648,11 @@ typedef struct {
|
||||
struct in_addr dns;
|
||||
char name[EC_MAX_HOSTNAME_SIZE];
|
||||
|
||||
// output
|
||||
uint16_t result;
|
||||
// output
|
||||
uint16_t result;
|
||||
} ec_ioctl_eoe_ip_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
// outputs
|
||||
|
||||
@@ -1884,6 +1884,46 @@ const ec_slave_t *ec_master_find_slave_const(
|
||||
EC_FIND_SLAVE;
|
||||
}
|
||||
|
||||
/** Finds the slave configuration that will be attached to the given slave.
|
||||
*
|
||||
* Unlike ec_slave_config_attach(), this does not actually attach the
|
||||
* configuration; it just looks one up by alias/position (and, if given,
|
||||
* matching vendor ID/product code), which also works before the bus scan
|
||||
* has completed and configurations have been attached to their slaves.
|
||||
*
|
||||
* \return The matching slave configuration, or \a NULL, if none matches.
|
||||
*/
|
||||
ec_slave_config_t *ec_master_find_config_for_slave(
|
||||
ec_master_t *master, /**< EtherCAT master. */
|
||||
const ec_slave_t *slave /**< Slave to find a configuration for. */
|
||||
)
|
||||
{
|
||||
ec_slave_config_t *sc;
|
||||
|
||||
list_for_each_entry(sc, &master->configs, list) {
|
||||
if (ec_master_find_slave(master, sc->alias, sc->position) != slave)
|
||||
continue;
|
||||
|
||||
#ifdef EC_IDENT_WILDCARDS
|
||||
if (sc->vendor_id != 0xffffffff
|
||||
&& slave->sii.vendor_id != sc->vendor_id)
|
||||
continue;
|
||||
if (sc->product_code != 0xffffffff
|
||||
&& slave->sii.product_code != sc->product_code)
|
||||
continue;
|
||||
#else
|
||||
if (slave->sii.vendor_id != sc->vendor_id)
|
||||
continue;
|
||||
if (slave->sii.product_code != sc->product_code)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Get the number of slave configurations provided by the application.
|
||||
|
||||
+5
-2
@@ -202,7 +202,7 @@ struct ec_master {
|
||||
#if EC_MAX_NUM_DEVICES > 1
|
||||
unsigned int num_devices; /**< Number of devices. Access this always via
|
||||
ec_master_num_devices(), because it may be
|
||||
optimized! */
|
||||
optimized. */
|
||||
#endif
|
||||
struct semaphore device_sem; /**< Device semaphore. */
|
||||
ec_device_stats_t device_stats; /**< Device statistics. */
|
||||
@@ -352,6 +352,8 @@ void ec_master_attach_slave_configs(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);
|
||||
ec_slave_config_t *ec_master_find_config_for_slave(ec_master_t *,
|
||||
const ec_slave_t *);
|
||||
void ec_master_output_stats(ec_master_t *);
|
||||
#ifdef EC_EOE
|
||||
void ec_master_clear_eoe_handlers(ec_master_t *);
|
||||
@@ -369,7 +371,8 @@ const ec_domain_t *ec_master_find_domain_const(const ec_master_t *,
|
||||
unsigned int);
|
||||
#ifdef EC_EOE
|
||||
uint16_t ec_master_eoe_handler_count(const ec_master_t *);
|
||||
const ec_eoe_t *ec_master_get_eoe_handler_const(const ec_master_t *, uint16_t);
|
||||
const ec_eoe_t *ec_master_get_eoe_handler_const(const ec_master_t *,
|
||||
uint16_t);
|
||||
#endif
|
||||
|
||||
int ec_master_debug_level(ec_master_t *, unsigned int);
|
||||
|
||||
@@ -89,6 +89,9 @@ void ec_slave_config_init(
|
||||
sc->watchdog_divider = 0; // use default
|
||||
sc->watchdog_intervals = 0; // use default
|
||||
|
||||
sc->pdo_assign_mode = EC_PDO_MODE_DEFAULT;
|
||||
sc->pdo_config_mode = EC_PDO_MODE_DEFAULT;
|
||||
|
||||
sc->slave = NULL;
|
||||
|
||||
for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++)
|
||||
@@ -716,6 +719,30 @@ int ecrt_slave_config_watchdog(ec_slave_config_t *sc,
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_mode(ec_slave_config_t *sc,
|
||||
ec_pdo_mode_t assign_mode, ec_pdo_mode_t config_mode)
|
||||
{
|
||||
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, assign_mode = %u,"
|
||||
" config_mode = %u)\n", __func__, sc, assign_mode, config_mode);
|
||||
|
||||
if (assign_mode > EC_PDO_MODE_WRITE_IF_DIFFERENT) {
|
||||
EC_CONFIG_ERR(sc, "Invalid PDO assignment mode %u!\n", assign_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (config_mode > EC_PDO_MODE_WRITE_IF_DIFFERENT) {
|
||||
EC_CONFIG_ERR(sc, "Invalid PDO configuration mode %u!\n",
|
||||
config_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc->pdo_assign_mode = assign_mode;
|
||||
sc->pdo_config_mode = config_mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
|
||||
uint8_t sync_index, uint16_t pdo_index)
|
||||
{
|
||||
@@ -1612,6 +1639,7 @@ int ecrt_slave_config_state_timeout(ec_slave_config_t *sc,
|
||||
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sync_manager);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_watchdog);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_mode);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_add);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_assign_clear);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_pdo_mapping_add);
|
||||
|
||||
@@ -123,6 +123,13 @@ struct ec_slave_config {
|
||||
uint16_t watchdog_intervals; /**< Process data watchdog intervals (see
|
||||
spec. reg. 0x0420). */
|
||||
|
||||
ec_pdo_mode_t pdo_assign_mode; /**< Whether/how to read resp. write the
|
||||
PDO assignment via CoE. \see
|
||||
ecrt_slave_config_pdo_mode(). */
|
||||
ec_pdo_mode_t pdo_config_mode; /**< Whether/how to read resp. write the
|
||||
PDO configuration via CoE. \see
|
||||
ecrt_slave_config_pdo_mode(). */
|
||||
|
||||
ec_slave_t *slave; /**< Slave pointer. This is \a NULL, if the slave is
|
||||
offline. */
|
||||
|
||||
|
||||
@@ -46,6 +46,21 @@ using std::left;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Returns a human-readable string for a PDO handling mode.
|
||||
*/
|
||||
static string pdoModeString(ec_pdo_mode_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case EC_PDO_MODE_FIXED: return "Fixed";
|
||||
case EC_PDO_MODE_WRITE: return "Write";
|
||||
case EC_PDO_MODE_READ_WRITE: return "Read+Write";
|
||||
case EC_PDO_MODE_WRITE_IF_DIFFERENT: return "Write if different";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
CommandConfig::CommandConfig():
|
||||
Command("config", "Show slave configurations.")
|
||||
{
|
||||
@@ -205,6 +220,11 @@ void CommandConfig::showDetailedConfigs(
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
cout << indent << "PDO assignment mode: "
|
||||
<< pdoModeString(configIter->pdo_assign_mode) << endl
|
||||
<< indent << "PDO configuration mode: "
|
||||
<< pdoModeString(configIter->pdo_config_mode) << endl;
|
||||
|
||||
for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
|
||||
if (configIter->syncs[j].pdo_count) {
|
||||
cout << indent << "SM" << dec << j << ", Dir: "
|
||||
|
||||
Reference in New Issue
Block a user