mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-05 19:39:50 +08:00
AL state timeout lookup logic.
This commit is contained in:
@@ -2014,8 +2014,9 @@ EC_PUBLIC_API int ecrt_slave_config_eoe_hostname(
|
||||
*
|
||||
* Change the maximum allowed time for a slave to make an application-layer
|
||||
* state transition for the given state transition (for example from PREOP to
|
||||
* SAFEOP). The default timeout is 10 s. Some transitions of specific slaves
|
||||
* may take longer.
|
||||
* SAFEOP). The default values are defined in ETG.2000.
|
||||
*
|
||||
* A timeout value of zero ms will restore the default value.
|
||||
*
|
||||
* This method has to be called in non-realtime context before
|
||||
* ecrt_master_activate().
|
||||
|
||||
@@ -29,17 +29,11 @@
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "fsm_change.h"
|
||||
#include "slave_config.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Timeout while waiting for AL state change [s].
|
||||
*
|
||||
* ETG2000_S_R_V1i0i15 section 5.3.7.2 mentions 10 s as maximum AL state
|
||||
* change timeout.
|
||||
*/
|
||||
#define EC_AL_STATE_CHANGE_TIMEOUT 10
|
||||
|
||||
/****************************************************************************/
|
||||
unsigned int ec_fsm_change_timeout_ms(const ec_fsm_change_t *);
|
||||
|
||||
void ec_fsm_change_state_start(ec_fsm_change_t *);
|
||||
void ec_fsm_change_state_check(ec_fsm_change_t *);
|
||||
@@ -78,6 +72,50 @@ void ec_fsm_change_clear(ec_fsm_change_t *fsm /**< finite state machine */)
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Get timeout in ms.
|
||||
*
|
||||
* For defaults see ETG2000_S_R_V1i0i15 section 5.3.6.2.
|
||||
*/
|
||||
unsigned int ec_fsm_change_timeout_ms(
|
||||
const ec_fsm_change_t *fsm /**< finite state machine */
|
||||
)
|
||||
{
|
||||
ec_slave_state_t from = fsm->old_state;
|
||||
ec_slave_state_t to = fsm->requested_state;
|
||||
|
||||
/* Search for specified timeout in slave configuration */
|
||||
if (fsm->slave->config) {
|
||||
unsigned int timeout_ms =
|
||||
ec_slave_config_al_timeout(fsm->slave->config, from, to);
|
||||
if (timeout_ms) {
|
||||
return timeout_ms;
|
||||
}
|
||||
}
|
||||
|
||||
/* No specific timeout found. Use defaults from spec. */
|
||||
|
||||
if (from == EC_SLAVE_STATE_INIT &&
|
||||
(to == EC_SLAVE_STATE_PREOP || to == EC_SLAVE_STATE_BOOT)) {
|
||||
return 3000; // PreopTimeout
|
||||
}
|
||||
if ((from == EC_SLAVE_STATE_PREOP && to == EC_SLAVE_STATE_SAFEOP) ||
|
||||
(from == EC_SLAVE_STATE_SAFEOP && to == EC_SLAVE_STATE_OP)) {
|
||||
return 10000; // SafeopOpTimeout
|
||||
}
|
||||
if (to == EC_SLAVE_STATE_INIT ||
|
||||
((from == EC_SLAVE_STATE_OP || from == EC_SLAVE_STATE_SAFEOP)
|
||||
&& to == EC_SLAVE_STATE_PREOP)) {
|
||||
return 5000; // BackToInitTimeout
|
||||
}
|
||||
if (from == EC_SLAVE_STATE_OP && to == EC_SLAVE_STATE_SAFEOP) {
|
||||
return 200; // BackToSafeopTimeout
|
||||
}
|
||||
|
||||
return 10000; // default [ms]
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
Starts the change state machine.
|
||||
*/
|
||||
@@ -234,6 +272,7 @@ void ec_fsm_change_state_status(ec_fsm_change_t *fsm
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
unsigned int timeout_ms;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
return;
|
||||
@@ -297,13 +336,15 @@ void ec_fsm_change_state_status(ec_fsm_change_t *fsm
|
||||
|
||||
// still old state
|
||||
|
||||
timeout_ms = ec_fsm_change_timeout_ms(fsm);
|
||||
if (datagram->jiffies_received - fsm->jiffies_start >=
|
||||
EC_AL_STATE_CHANGE_TIMEOUT * HZ) {
|
||||
timeout_ms * HZ / 1000) {
|
||||
// timeout while checking
|
||||
char state_str[EC_STATE_STRING_SIZE];
|
||||
ec_state_string(fsm->requested_state, state_str, 0);
|
||||
fsm->state = ec_fsm_change_state_error;
|
||||
EC_SLAVE_ERR(slave, "Timeout while setting state %s.\n", state_str);
|
||||
EC_SLAVE_ERR(slave, "Timeout after %u ms while setting state %s.\n",
|
||||
timeout_ms, state_str);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -492,6 +533,7 @@ void ec_fsm_change_state_check_ack(ec_fsm_change_t *fsm
|
||||
{
|
||||
ec_datagram_t *datagram = fsm->datagram;
|
||||
ec_slave_t *slave = fsm->slave;
|
||||
unsigned int timeout_ms;
|
||||
|
||||
if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
|
||||
return;
|
||||
@@ -530,14 +572,15 @@ void ec_fsm_change_state_check_ack(ec_fsm_change_t *fsm
|
||||
return;
|
||||
}
|
||||
|
||||
timeout_ms = ec_fsm_change_timeout_ms(fsm);
|
||||
if (datagram->jiffies_received - fsm->jiffies_start >=
|
||||
EC_AL_STATE_CHANGE_TIMEOUT * HZ) {
|
||||
timeout_ms * HZ / 1000) {
|
||||
// timeout while checking
|
||||
char state_str[EC_STATE_STRING_SIZE];
|
||||
ec_state_string(slave->current_state, state_str, 0);
|
||||
fsm->state = ec_fsm_change_state_error;
|
||||
EC_SLAVE_ERR(slave, "Timeout while acknowledging state %s.\n",
|
||||
state_str);
|
||||
EC_SLAVE_ERR(slave, "Timeout after %u ms while acknowledging"
|
||||
" state %s.\n", timeout_ms, state_str);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,25 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// prototypes for private methods
|
||||
int ec_slave_config_prepare_fmmu(ec_slave_config_t *, ec_domain_t *, uint8_t,
|
||||
ec_direction_t);
|
||||
void ec_slave_config_load_default_mapping(const ec_slave_config_t *,
|
||||
ec_pdo_t *);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** EtherCAT application-layer transition timeout.
|
||||
*/
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
ec_slave_state_t from;
|
||||
ec_slave_state_t to;
|
||||
unsigned int timeout_ms;
|
||||
} ec_al_timeout_t;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Slave configuration constructor.
|
||||
*
|
||||
* See ecrt_master_slave_config() for the usage of the \a alias and \a
|
||||
@@ -89,6 +108,7 @@ void ec_slave_config_init(
|
||||
INIT_LIST_HEAD(&sc->voe_handlers);
|
||||
INIT_LIST_HEAD(&sc->soe_configs);
|
||||
INIT_LIST_HEAD(&sc->flags);
|
||||
INIT_LIST_HEAD(&sc->al_timeouts);
|
||||
|
||||
#ifdef EC_EOE
|
||||
ec_eoe_request_init(&sc->eoe_ip_param_request);
|
||||
@@ -113,6 +133,7 @@ void ec_slave_config_clear(
|
||||
ec_reg_request_t *reg, *next_reg;
|
||||
ec_soe_request_t *soe, *next_soe;
|
||||
ec_flag_t *flag, *next_flag;
|
||||
ec_al_timeout_t *timeout, *next_timeout;
|
||||
|
||||
ec_slave_config_detach(sc);
|
||||
|
||||
@@ -169,6 +190,12 @@ void ec_slave_config_clear(
|
||||
kfree(flag);
|
||||
}
|
||||
|
||||
// free all AL timeouts
|
||||
list_for_each_entry_safe(timeout, next_timeout, &sc->al_timeouts, list) {
|
||||
list_del(&timeout->list);
|
||||
kfree(timeout);
|
||||
}
|
||||
|
||||
ec_coe_emerg_ring_clear(&sc->emerg_ring);
|
||||
}
|
||||
|
||||
@@ -625,6 +652,26 @@ ec_flag_t *ec_slave_config_find_flag(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** Return an AL state timeout.
|
||||
*
|
||||
* \return Search result, or 0.
|
||||
*/
|
||||
unsigned int ec_slave_config_al_timeout(const ec_slave_config_t *sc,
|
||||
ec_slave_state_t from, ec_slave_state_t to)
|
||||
{
|
||||
ec_al_timeout_t *timeout;
|
||||
|
||||
list_for_each_entry(timeout, &sc->al_timeouts, list) {
|
||||
if (timeout->from == from && timeout->to == to) {
|
||||
return timeout->timeout_ms;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface
|
||||
****************************************************************************/
|
||||
@@ -1504,6 +1551,64 @@ int ecrt_slave_config_eoe_hostname(ec_slave_config_t *sc,
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int ecrt_slave_config_state_timeout(ec_slave_config_t *sc,
|
||||
ec_al_state_t from, ec_al_state_t to, unsigned int timeout_ms)
|
||||
{
|
||||
ec_al_timeout_t *timeout;
|
||||
ec_slave_state_t from_state, to_state;
|
||||
|
||||
if (from != EC_AL_STATE_INIT && from != EC_AL_STATE_PREOP &&
|
||||
from != EC_AL_STATE_SAFEOP && from != EC_AL_STATE_OP) {
|
||||
EC_CONFIG_ERR(sc, "Invalid from state %i.\n", from);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (to != EC_AL_STATE_INIT && to != EC_AL_STATE_PREOP &&
|
||||
to != EC_AL_STATE_SAFEOP && to != EC_AL_STATE_OP) {
|
||||
EC_CONFIG_ERR(sc, "Invalid to state %i.\n", to);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
from_state = (ec_slave_state_t) from;
|
||||
to_state = (ec_slave_state_t) to;
|
||||
|
||||
/* try to find an already configured timeout. */
|
||||
list_for_each_entry(timeout, &sc->al_timeouts, list) {
|
||||
if (timeout->from == from_state && timeout->to == to_state) {
|
||||
if (timeout_ms == 0) {
|
||||
// delete configured value
|
||||
list_del(&timeout->list);
|
||||
kfree(timeout);
|
||||
return 0;
|
||||
}
|
||||
timeout->timeout_ms = timeout_ms;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout_ms == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no timeout found. create one. */
|
||||
if (!(timeout = (ec_al_timeout_t *)
|
||||
kmalloc(sizeof(ec_al_timeout_t), GFP_KERNEL))) {
|
||||
EC_CONFIG_ERR(sc, "Failed to allocate memory for"
|
||||
" AL timeout configuration!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
timeout->from = from_state;
|
||||
timeout->to = to_state;
|
||||
timeout->timeout_ms = timeout_ms;
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
list_add_tail(&timeout->list, &sc->al_timeouts);
|
||||
up(&sc->master->master_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_slave_config_sync_manager);
|
||||
@@ -1540,6 +1645,7 @@ EXPORT_SYMBOL(ecrt_slave_config_eoe_default_gateway);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_eoe_dns_address);
|
||||
EXPORT_SYMBOL(ecrt_slave_config_eoe_hostname);
|
||||
#endif
|
||||
EXPORT_SYMBOL(ecrt_slave_config_state_timeout);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ struct ec_slave_config {
|
||||
struct list_head reg_requests; /**< List of register requests. */
|
||||
struct list_head soe_configs; /**< List of SoE configurations. */
|
||||
struct list_head flags; /**< List of feature flags. */
|
||||
struct list_head al_timeouts; /**< List of specific AL state timeouts. */
|
||||
|
||||
#ifdef EC_EOE
|
||||
ec_eoe_request_t eoe_ip_param_request; /**< EoE IP parameters. */
|
||||
@@ -187,6 +188,9 @@ ec_voe_handler_t *ecrt_slave_config_create_voe_handler_err(
|
||||
ec_reg_request_t *ecrt_slave_config_create_reg_request_err(
|
||||
ec_slave_config_t *, size_t);
|
||||
|
||||
unsigned int ec_slave_config_al_timeout(const ec_slave_config_t *,
|
||||
ec_slave_state_t, ec_slave_state_t);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user