Merge branch 'al-timeout-api' into 'devel-1.6'

Add interface to set AL state change timeouts

See merge request etherlab.org/ethercat!127
This commit is contained in:
Florian Pose 2024-05-22 11:07:10 +00:00
commit eb6e7bf41b
24 changed files with 461 additions and 113 deletions

View File

@ -56,6 +56,7 @@
int __init ec_gen_init_module(void);
void __exit ec_gen_cleanup_module(void);
void ec_gen_poll(struct net_device *);
/****************************************************************************/
@ -87,11 +88,18 @@ typedef struct {
uint8_t dev_addr[ETH_ALEN];
} ec_gen_interface_desc_t;
int ec_gen_device_init(ec_gen_device_t *);
void ec_gen_device_clear(ec_gen_device_t *);
int ec_gen_device_create_socket(ec_gen_device_t *, ec_gen_interface_desc_t *);
int ec_gen_device_offer(ec_gen_device_t *, ec_gen_interface_desc_t *);
int ec_gen_device_open(ec_gen_device_t *);
int ec_gen_device_stop(ec_gen_device_t *);
int ec_gen_device_start_xmit(ec_gen_device_t *, struct sk_buff *);
void ec_gen_device_poll(ec_gen_device_t *);
int offer_device(ec_gen_interface_desc_t *);
void clear_devices(void);
/****************************************************************************/
static int ec_gen_netdev_open(struct net_device *dev)

View File

@ -182,6 +182,21 @@ static ec_voe_handler_t *voe;
/****************************************************************************/
void check_domain1_state(void);
void check_master_state(void);
void check_slave_config_states(void);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
void cyclic_task(struct timer_list *);
#else
void cyclic_task(unsigned long);
#endif
void send_callback(void *);
void receive_callback(void *);
int init_mini_module(void);
void cleanup_mini_module(void);
/****************************************************************************/
void check_domain1_state(void)
{
ec_domain_state_t ds;

View File

@ -49,6 +49,9 @@
* ecrt_slave_config_eoe_dns_address(),
* ecrt_slave_config_eoe_hostname() and the EC_HAVE_SET_IP
* definition to check for its existence.
* - Added ecrt_slave_config_state_timeout() to set the application-layer
* state change timeout and EC_HAVE_STATE_TIMEOUT to check for its
* existence.
*
* Changes since version 1.5.2:
*
@ -252,6 +255,10 @@
*/
#define EC_HAVE_SET_IP
/** Defined, if the method ecrt_slave_config_state_timeout() is available.
*/
#define EC_HAVE_STATE_TIMEOUT
/****************************************************************************/
/** Symbol visibility control macro.
@ -2003,6 +2010,27 @@ EC_PUBLIC_API int ecrt_slave_config_eoe_hostname(
const char *name /**< Zero-terminated host name. */
);
/** Sets the application-layer state transition timeout in ms.
*
* 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 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().
*
* \retval 0 Success.
* \retval <0 Error code.
*/
EC_PUBLIC_API int ecrt_slave_config_state_timeout(
ec_slave_config_t *sc, /**< Slave configuration. */
ec_al_state_t from_state, /**< Initial state. */
ec_al_state_t to_state, /**< Target state. */
unsigned int timeout_ms /**< Timeout in [ms]. */
);
/*****************************************************************************
* Domain methods
****************************************************************************/

View File

@ -110,4 +110,5 @@ LIBETHERCAT_1.6 {
ecrt_slave_config_eoe_default_gateway;
ecrt_slave_config_eoe_dns_address;
ecrt_slave_config_eoe_hostname;
ecrt_slave_config_state_timeout;
} LIBETHERCAT_1.5.3;

View File

@ -1038,3 +1038,27 @@ int ecrt_slave_config_eoe_hostname(ec_slave_config_t *sc,
#endif // EC_EOE
/****************************************************************************/
int ecrt_slave_config_state_timeout(ec_slave_config_t *sc,
ec_al_state_t from_state, ec_al_state_t to_state,
unsigned int timeout_ms)
{
ec_ioctl_sc_state_timeout_t io = {};
int ret;
io.config_index = sc->index;
io.from_state = from_state;
io.to_state = to_state;
io.timeout_ms = timeout_ms;
ret = ioctl(sc->master->fd, EC_IOCTL_SC_STATE_TIMEOUT, &io);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to configure AL state timeout: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
return -EC_IOCTL_ERRNO(ret);
}
return 0;
}
/****************************************************************************/

View File

@ -41,7 +41,14 @@
/****************************************************************************/
// prototypes for private methods
void ec_domain_clear_data(ec_domain_t *);
int ec_domain_add_datagram_pair(ec_domain_t *, uint32_t, size_t, uint8_t *,
const unsigned int []);
int shall_count(const ec_fmmu_config_t *, const ec_fmmu_config_t *);
#if EC_MAX_NUM_DEVICES > 1
int data_changed(uint8_t *, const ec_datagram_t *, size_t, size_t);
#endif
/****************************************************************************/

View File

@ -70,7 +70,11 @@
/****************************************************************************/
// prototypes for private methods
void ec_eoe_flush(ec_eoe_t *);
int ec_eoe_send(ec_eoe_t *);
/****************************************************************************/
// state functions
void ec_eoe_state_rx_start(ec_eoe_t *);

View File

@ -42,6 +42,7 @@
/****************************************************************************/
// prototypes for private methods
void ec_foe_request_clear_data(ec_foe_request_t *);
/****************************************************************************/
@ -165,44 +166,6 @@ int ec_foe_request_timed_out(
/****************************************************************************/
/** Set the request timeout.
*/
void ec_foe_request_timeout(
ec_foe_request_t *req, /**< FoE request. */
uint32_t timeout /**< Timeout in ms. */
)
{
req->issue_timeout = timeout;
}
/****************************************************************************/
/** Returns a pointer to the request's data.
*
* \return Data pointer.
*/
uint8_t *ec_foe_request_data(
ec_foe_request_t *req /**< FoE request. */
)
{
return req->buffer;
}
/****************************************************************************/
/** Returns the data size.
*
* \return Data size.
*/
size_t ec_foe_request_data_size(
const ec_foe_request_t *req /**< FoE request. */
)
{
return req->data_size;
}
/****************************************************************************/
/** Prepares a read request (slave to master).
*/
void ec_foe_request_read(

View File

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

View File

@ -59,6 +59,19 @@
/****************************************************************************/
// prototypes for private methods
void ec_canopen_abort_msg(const ec_slave_t *, uint32_t);
int ec_fsm_coe_check_emergency(const ec_fsm_coe_t *, const uint8_t *, size_t);
int ec_fsm_coe_prepare_dict(ec_fsm_coe_t *, ec_datagram_t *);
int ec_fsm_coe_dict_prepare_desc(ec_fsm_coe_t *, ec_datagram_t *);
int ec_fsm_coe_dict_prepare_entry(ec_fsm_coe_t *, ec_datagram_t *);
int ec_fsm_coe_prepare_down_start(ec_fsm_coe_t *, ec_datagram_t *);
void ec_fsm_coe_down_prepare_segment_request(ec_fsm_coe_t *, ec_datagram_t *);
int ec_fsm_coe_prepare_up(ec_fsm_coe_t *, ec_datagram_t *);
void ec_fsm_coe_up_prepare_segment_request(ec_fsm_coe_t *, ec_datagram_t *);
/****************************************************************************/
void ec_fsm_coe_dict_start(ec_fsm_coe_t *, ec_datagram_t *);
void ec_fsm_coe_dict_request(ec_fsm_coe_t *, ec_datagram_t *);
void ec_fsm_coe_dict_check(ec_fsm_coe_t *, ec_datagram_t *);
@ -267,7 +280,7 @@ int ec_fsm_coe_success(
* \return The data were an emergency request.
*/
int ec_fsm_coe_check_emergency(
ec_fsm_coe_t *fsm, /**< Finite state machine */
const ec_fsm_coe_t *fsm, /**< Finite state machine */
const uint8_t *data, /**< CoE mailbox data. */
size_t size /**< CoE mailbox data size. */
)

View File

@ -33,6 +33,27 @@
/****************************************************************************/
/** Maximum time to wait for a set IP parameter response.
*/
#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
/****************************************************************************/
// prototypes for private functions
void memcpy_swap32(void *, const void *);
int ec_fsm_eoe_prepare_set(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *);
/****************************************************************************/
/** Host-architecture-independent 32-bit swap function.
*
* The internal storage of struct in_addr is always big-endian.
@ -51,22 +72,6 @@ void memcpy_swap32(void *dst, const void *src)
/****************************************************************************/
/** Maximum time to wait for a set IP parameter response.
*/
#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
/****************************************************************************/
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *);
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *);
/****************************************************************************/
/** Constructor.
*/
void ec_fsm_eoe_init(

View File

@ -44,6 +44,18 @@
/****************************************************************************/
// prototypes for private methods
void ec_fsm_master_restart(ec_fsm_master_t *);
int ec_fsm_master_action_process_sii(ec_fsm_master_t *);
int ec_fsm_master_action_process_int_request(ec_fsm_master_t *);
void ec_fsm_master_action_idle(ec_fsm_master_t *);
void ec_fsm_master_action_next_slave_state(ec_fsm_master_t *);
void ec_fsm_master_action_configure(ec_fsm_master_t *);
u64 ec_fsm_master_dc_offset32(ec_fsm_master_t *, u64, u64, unsigned long);
u64 ec_fsm_master_dc_offset64(ec_fsm_master_t *, u64, u64, unsigned long);
/****************************************************************************/
void ec_fsm_master_state_start(ec_fsm_master_t *);
void ec_fsm_master_state_broadcast(ec_fsm_master_t *);
void ec_fsm_master_state_read_state(ec_fsm_master_t *);

View File

@ -34,6 +34,14 @@
/****************************************************************************/
// prototypes for private methods
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 *);
/****************************************************************************/
void ec_fsm_pdo_read_state_start(ec_fsm_pdo_t *, ec_datagram_t *);
void ec_fsm_pdo_read_state_pdo_count(ec_fsm_pdo_t *, ec_datagram_t *);
void ec_fsm_pdo_read_state_pdo(ec_fsm_pdo_t *, ec_datagram_t *);
@ -94,7 +102,7 @@ void ec_fsm_pdo_clear(
/** Print the current and desired PDO assignment.
*/
void ec_fsm_pdo_print(
ec_fsm_pdo_t *fsm /**< PDO configuration state machine. */
const ec_fsm_pdo_t *fsm /**< PDO configuration state machine. */
)
{
printk(KERN_CONT "Currently assigned PDOs: ");

View File

@ -34,6 +34,14 @@
/****************************************************************************/
// prototypes for private methods
void ec_fsm_pdo_entry_print(const ec_fsm_pdo_entry_t *);
int ec_fsm_pdo_entry_running(const ec_fsm_pdo_entry_t *);
ec_pdo_entry_t *ec_fsm_pdo_entry_conf_next_entry(const ec_fsm_pdo_entry_t *,
const struct list_head *);
/****************************************************************************/
void ec_fsm_pdo_entry_read_state_start(ec_fsm_pdo_entry_t *, ec_datagram_t *);
void ec_fsm_pdo_entry_read_state_count(ec_fsm_pdo_entry_t *, ec_datagram_t *);
void ec_fsm_pdo_entry_read_state_entry(ec_fsm_pdo_entry_t *, ec_datagram_t *);
@ -82,7 +90,7 @@ void ec_fsm_pdo_entry_clear(
/** Print the current and desired PDO mapping.
*/
void ec_fsm_pdo_entry_print(
ec_fsm_pdo_entry_t *fsm /**< PDO mapping state machine. */
const ec_fsm_pdo_entry_t *fsm /**< PDO mapping state machine. */
)
{
printk(KERN_CONT "Currently mapped PDO entries: ");

View File

@ -52,6 +52,11 @@
/****************************************************************************/
// prototypes for private methods
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *);
/****************************************************************************/
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *);

View File

@ -35,6 +35,19 @@
/****************************************************************************/
// prototypes for private methods
int ec_fsm_slave_scan_running(const ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_sii_size(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_assign_sii(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_datalink(ec_fsm_slave_scan_t *);
#ifdef EC_REGALIAS
void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *);
#endif
void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *);
/****************************************************************************/
void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_address(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_state(ec_fsm_slave_scan_t *);
@ -57,13 +70,6 @@ void ec_fsm_slave_scan_state_pdos(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_end(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_state_error(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_datalink(ec_fsm_slave_scan_t *);
#ifdef EC_REGALIAS
void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *);
#endif
void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *);
void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *);
/****************************************************************************/
/** Constructor.
@ -115,7 +121,9 @@ void ec_fsm_slave_scan_start(
\return false, if state machine has terminated
*/
int ec_fsm_slave_scan_running(const ec_fsm_slave_scan_t *fsm /**< slave state machine */)
int ec_fsm_slave_scan_running(
const ec_fsm_slave_scan_t *fsm /**< slave state machine */
)
{
return fsm->state != ec_fsm_slave_scan_state_end
&& fsm->state != ec_fsm_slave_scan_state_error;

View File

@ -56,6 +56,14 @@ enum {
/****************************************************************************/
// prototypes for private methods
void ec_print_soe_error(const ec_slave_t *, uint16_t);
void ec_fsm_soe_print_error(ec_fsm_soe_t *);
int ec_fsm_soe_prepare_read(ec_fsm_soe_t *, ec_datagram_t *);
void ec_fsm_soe_write_next_fragment(ec_fsm_soe_t *, ec_datagram_t *);
/****************************************************************************/
void ec_fsm_soe_read_start(ec_fsm_soe_t *, ec_datagram_t *);
void ec_fsm_soe_read_request(ec_fsm_soe_t *, ec_datagram_t *);
void ec_fsm_soe_read_check(ec_fsm_soe_t *, ec_datagram_t *);

View File

@ -3332,6 +3332,46 @@ static ATTRIBUTES int ec_ioctl_sc_flag(
/****************************************************************************/
/** Sets an AL state transition timeout.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_sc_state_timeout(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_sc_state_timeout_t ioctl;
ec_slave_config_t *sc;
int ret;
if (unlikely(!ctx->requested)) {
return -EPERM;
}
if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) {
return -EFAULT;
}
if (down_interruptible(&master->master_sem)) {
return -EINTR;
}
if (!(sc = ec_master_get_config(master, ioctl.config_index))) {
up(&master->master_sem);
return -ENOENT;
}
up(&master->master_sem); /** \todo sc could be invalidated */
ret = ecrt_slave_config_state_timeout(sc, ioctl.from_state,
ioctl.to_state, ioctl.timeout_ms);
return ret;
}
/****************************************************************************/
#ifdef EC_EOE
/** Configures EoE IP parameters.
@ -5493,6 +5533,13 @@ static long ec_ioctl_nrt
}
ret = ec_ioctl_sc_flag(master, arg, ctx);
break;
case EC_IOCTL_SC_STATE_TIMEOUT:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_sc_state_timeout(master, arg, ctx);
break;
#ifdef EC_EOE
case EC_IOCTL_SC_EOE_IP_PARAM:
if (!ctx->writable) {

View File

@ -47,7 +47,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 36
#define EC_IOCTL_VERSION_MAGIC 37
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@ -131,35 +131,36 @@
#ifdef EC_EOE
#define EC_IOCTL_SC_EOE_IP_PARAM EC_IOW(0x48, ec_ioctl_eoe_ip_t)
#endif
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x49)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x4a)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x4b)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4c)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4d, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x50, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x51, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x52, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x53, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x54, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x55, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x56, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x57, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x58, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x59, ec_ioctl_soe_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x5a, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x5b, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5c, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5d, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5e, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x60, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x61, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x62, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x63, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x64, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x65, size_t)
#define EC_IOCTL_SC_STATE_TIMEOUT EC_IOW(0x49, ec_ioctl_sc_state_timeout_t)
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x4a)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x4b)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x4c)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4d)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4e, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x50, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x51, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x52, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x53, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x54, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x55, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x56, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x57, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x58, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x59, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x5a, ec_ioctl_soe_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x5b, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x5c, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5d, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5e, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x60, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x61, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x62, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x63, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x64, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x65, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x66, size_t)
/****************************************************************************/
@ -749,6 +750,16 @@ typedef struct {
/****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;
ec_al_state_t from_state;
ec_al_state_t to_state;
uint32_t timeout_ms;
} ec_ioctl_sc_state_timeout_t;
/****************************************************************************/
typedef struct {
// inputs
uint32_t domain_index;

View File

@ -97,8 +97,18 @@ const unsigned int rate_intervals[] = {
/****************************************************************************/
void ec_master_clear_config(ec_master_t *);
void ec_master_clear_slave_configs(ec_master_t *);
void ec_master_clear_domains(ec_master_t *);
int ec_master_thread_start(ec_master_t *, int (*)(void *), const char *);
void ec_master_thread_stop(ec_master_t *);
void ec_master_inject_external_datagrams(ec_master_t *);
ec_datagram_t *ec_master_get_external_datagram(ec_master_t *);
void ec_master_exec_slave_fsms(ec_master_t *);
void ec_master_send_datagrams(ec_master_t *, ec_device_index_t);
int ec_master_calc_topology_rec(ec_master_t *, ec_slave_t *, unsigned int *);
void ec_master_calc_topology(ec_master_t *);
void ec_master_calc_transmission_delays(ec_master_t *);
static int ec_master_idle_thread(void *);
static int ec_master_operation_thread(void *);
#ifdef EC_EOE

View File

@ -44,6 +44,10 @@ void __exit ec_cleanup_module(void);
static int ec_mac_parse(uint8_t *, const char *, int);
// prototypes for private functions
int ec_mac_equal(const uint8_t *, const uint8_t *);
int ec_mac_is_broadcast(const uint8_t *);
/****************************************************************************/
static char *main_devices[MAX_MASTERS]; /**< Main devices parameter. */

View File

@ -42,7 +42,13 @@ extern const ec_code_msg_t al_status_messages[];
/****************************************************************************/
char *ec_slave_sii_string(ec_slave_t *, unsigned int);
// prototypes for private methods
char *ec_slave_sii_string(const ec_slave_t *, unsigned int);
void ec_slave_find_names_for_pdo(ec_slave_t *, ec_pdo_t *);
unsigned int ec_slave_get_previous_port(const ec_slave_t *, unsigned int);
unsigned int ec_slave_get_next_port(const ec_slave_t *, unsigned int);
uint32_t ec_slave_calc_rtt_sum(const ec_slave_t *);
ec_slave_t *ec_slave_find_next_dc_slave(ec_slave_t *);
/****************************************************************************/
@ -570,7 +576,7 @@ int ec_slave_fetch_sii_pdos(
*/
char *ec_slave_sii_string(
ec_slave_t *slave, /**< EtherCAT slave */
const ec_slave_t *slave, /**< EtherCAT slave */
unsigned int index /**< string index */
)
{
@ -805,7 +811,7 @@ void ec_slave_attach_pdo_names(
* \return Port index.
*/
unsigned int ec_slave_get_previous_port(
ec_slave_t *slave, /**< EtherCAT slave. */
const ec_slave_t *slave, /**< EtherCAT slave. */
unsigned int port_index /**< Port index. */
)
{
@ -835,7 +841,7 @@ unsigned int ec_slave_get_previous_port(
* \return Port index.
*/
unsigned int ec_slave_get_next_port(
ec_slave_t *slave, /**< EtherCAT slave. */
const ec_slave_t *slave, /**< EtherCAT slave. */
unsigned int port_index /**< Port index. */
)
{
@ -865,7 +871,7 @@ unsigned int ec_slave_get_next_port(
* \return Round-trip-time in ns.
*/
uint32_t ec_slave_calc_rtt_sum(
ec_slave_t *slave /**< EtherCAT slave. */
const ec_slave_t *slave /**< EtherCAT slave. */
)
{
uint32_t rtt_sum = 0, rtt;

View File

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

View File

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