# HG changeset patch # User Florian Pose # Date 1424444783 -3600 # Node ID 1a969896d52eb64fdf6b0c706f039d3cb04efede # Parent 19ff84bbbcb3e63832f5970f6134bffafee09b12 Added --enable-loop-control to make use of the loop control registers. diff -r 19ff84bbbcb3 -r 1a969896d52e configure.ac --- a/configure.ac Thu Feb 19 15:19:29 2015 +0100 +++ b/configure.ac Fri Feb 20 16:06:23 2015 +0100 @@ -1031,6 +1031,35 @@ fi #------------------------------------------------------------------------------ +# use loop control registers to open slave ports +#------------------------------------------------------------------------------ + +AC_MSG_CHECKING([whether to use loop control registers]) + +AC_ARG_ENABLE([loop-control], + AS_HELP_STRING([--enable-loop-control], + [Use loop control registers (default: no)]), + [ + case "${enableval}" in + yes) loopctl=1 + ;; + no) loopctl=0 + ;; + *) AC_MSG_ERROR([Invalid value for --enable-loop-control]) + ;; + esac + ], + [loopctl=0] +) + +if test "x${loopctl}" = "x1"; then + AC_DEFINE([EC_LOOP_CONTROL], [1], [Use loop control registers]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +#------------------------------------------------------------------------------ AC_CONFIG_FILES([ Doxyfile diff -r 19ff84bbbcb3 -r 1a969896d52e master/fsm_master.c --- a/master/fsm_master.c Thu Feb 19 15:19:29 2015 +0100 +++ b/master/fsm_master.c Fri Feb 20 16:06:23 2015 +0100 @@ -54,10 +54,17 @@ 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 *); +void ec_fsm_master_state_read_al_status(ec_fsm_master_t *); +#ifdef EC_LOOP_CONTROL +void ec_fsm_master_state_read_dl_status(ec_fsm_master_t *); +void ec_fsm_master_state_open_port(ec_fsm_master_t *); +#endif void ec_fsm_master_state_acknowledge(ec_fsm_master_t *); void ec_fsm_master_state_configure_slave(ec_fsm_master_t *); void ec_fsm_master_state_clear_addresses(ec_fsm_master_t *); +#ifdef EC_LOOP_CONTROL +void ec_fsm_master_state_loop_control(ec_fsm_master_t *); +#endif void ec_fsm_master_state_dc_measure_delays(ec_fsm_master_t *); void ec_fsm_master_state_scan_slave(ec_fsm_master_t *); void ec_fsm_master_state_dc_read_offset(ec_fsm_master_t *); @@ -415,7 +422,7 @@ ec_datagram_zero(datagram); fsm->datagram->device_index = fsm->slave->device_index; fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_read_state; + fsm->state = ec_fsm_master_state_read_al_status; } } else { ec_fsm_master_restart(fsm); @@ -594,7 +601,7 @@ ec_datagram_zero(fsm->datagram); fsm->datagram->device_index = fsm->slave->device_index; fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_read_state; + fsm->state = ec_fsm_master_state_read_al_status; return; } @@ -604,6 +611,151 @@ /*****************************************************************************/ +#ifdef EC_LOOP_CONTROL + +/** Master action: Read DL status of current slave. + */ +void ec_fsm_master_action_read_dl_status( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0110, 2); + ec_datagram_zero(fsm->datagram); + fsm->datagram->device_index = fsm->slave->device_index; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_master_state_read_dl_status; +} + +/*****************************************************************************/ + +/** Master action: Open slave port. + */ +void ec_fsm_master_action_open_port( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + EC_SLAVE_INFO(fsm->slave, "Opening ports.\n"); + + ec_datagram_fpwr(fsm->datagram, fsm->slave->station_address, 0x0101, 1); + EC_WRITE_U8(fsm->datagram->data, 0x54); // port 0 auto, 1-3 auto-close + fsm->datagram->device_index = fsm->slave->device_index; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_master_state_open_port; +} + +/*****************************************************************************/ + +/** Master state: READ DL STATUS. + * + * Fetches the DL state of a slave. + */ +void ec_fsm_master_state_read_dl_status( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_datagram_t *datagram = fsm->datagram; + unsigned int i; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + return; + } + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: "); + ec_datagram_print_state(datagram); + ec_fsm_master_restart(fsm); + return; + } + + // did the slave not respond to its station address? + if (datagram->working_counter != 1) { + // try again next time + ec_fsm_master_action_next_slave_state(fsm); + return; + } + + ec_slave_set_dl_status(slave, EC_READ_U16(datagram->data)); + + // process port state machines + for (i = 0; i < EC_MAX_PORTS; i++) { + ec_slave_port_t *port = &slave->ports[i]; + + switch (port->state) { + case EC_SLAVE_PORT_DOWN: + if (port->link.loop_closed) { + if (port->link.link_up) { + port->link_detection_jiffies = jiffies; + port->state = EC_SLAVE_PORT_WAIT; + } + } + else { // loop open + port->state = EC_SLAVE_PORT_UP; + } + break; + case EC_SLAVE_PORT_WAIT: + if (port->link.link_up) { + if (jiffies - port->link_detection_jiffies > + HZ * EC_PORT_WAIT_MS / 1000) { + port->state = EC_SLAVE_PORT_UP; + ec_fsm_master_action_open_port(fsm); + return; + } + } + else { // link down + port->state = EC_SLAVE_PORT_DOWN; + } + break; + default: // EC_SLAVE_PORT_UP + if (!port->link.link_up) { + port->state = EC_SLAVE_PORT_DOWN; + } + break; + } + } + + // process next slave + ec_fsm_master_action_next_slave_state(fsm); +} + +/*****************************************************************************/ + +/** Master state: OPEN_PORT. + * + * Opens slave ports. + */ +void ec_fsm_master_state_open_port( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_slave_t *slave = fsm->slave; + ec_datagram_t *datagram = fsm->datagram; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + return; + } + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + EC_SLAVE_ERR(slave, "Failed to receive port open datagram: "); + ec_datagram_print_state(datagram); + ec_fsm_master_restart(fsm); + return; + } + + // did the slave not respond to its station address? + if (datagram->working_counter != 1) { + EC_SLAVE_ERR(slave, "Did not respond to port open command!\n"); + return; + } + + // process next slave + ec_fsm_master_action_next_slave_state(fsm); +} + +#endif + +/*****************************************************************************/ + /** Master action: Configure. */ void ec_fsm_master_action_configure( @@ -654,17 +806,22 @@ return; } +#ifdef EC_LOOP_CONTROL + // read DL status + ec_fsm_master_action_read_dl_status(fsm); +#else // process next slave ec_fsm_master_action_next_slave_state(fsm); -} - -/*****************************************************************************/ - -/** Master state: READ STATE. +#endif +} + +/*****************************************************************************/ + +/** Master state: READ AL STATUS. * * Fetches the AL state of a slave. */ -void ec_fsm_master_state_read_state( +void ec_fsm_master_state_read_al_status( ec_fsm_master_t *fsm /**< Master state machine. */ ) { @@ -694,7 +851,7 @@ } // A single slave responded - ec_slave_set_state(slave, EC_READ_U8(datagram->data)); + ec_slave_set_al_status(slave, EC_READ_U8(datagram->data)); if (!slave->error_flag) { // Check, if new slave state has to be acknowledged @@ -711,8 +868,13 @@ return; } - // slave has error flag set; process next one +#ifdef EC_LOOP_CONTROL + // read DL status + ec_fsm_master_action_read_dl_status(fsm); +#else + // process next slave ec_fsm_master_action_next_slave_state(fsm); +#endif } /*****************************************************************************/ @@ -755,6 +917,73 @@ /*****************************************************************************/ +/** Start measuring DC delays. + */ +void ec_fsm_master_enter_dc_measure_delays( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + EC_MASTER_DBG(fsm->master, 1, "Sending broadcast-write" + " to measure transmission delays on %s link.\n", + ec_device_names[fsm->dev_idx != 0]); + + ec_datagram_bwr(fsm->datagram, 0x0900, 1); + ec_datagram_zero(fsm->datagram); + fsm->datagram->device_index = fsm->dev_idx; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_master_state_dc_measure_delays; +} + +/*****************************************************************************/ + +#ifdef EC_LOOP_CONTROL + +/** Start writing loop control registers. + */ +void ec_fsm_master_enter_loop_control( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + EC_MASTER_DBG(fsm->master, 1, "Broadcast-writing" + " loop control registers on %s link.\n", + ec_device_names[fsm->dev_idx != 0]); + + ec_datagram_bwr(fsm->datagram, 0x0101, 1); + EC_WRITE_U8(fsm->datagram->data, 0x54); // port 0 auto, 1-3 auto-close + fsm->datagram->device_index = fsm->dev_idx; + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_master_state_loop_control; +} + +/*****************************************************************************/ + +/** Master state: LOOP CONTROL. + */ +void ec_fsm_master_state_loop_control( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; + ec_datagram_t *datagram = fsm->datagram; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { + return; + } + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + EC_MASTER_ERR(master, "Failed to receive loop control" + " datagram on %s link: ", + ec_device_names[fsm->dev_idx != 0]); + ec_datagram_print_state(datagram); + } + + ec_fsm_master_enter_dc_measure_delays(fsm); +} + +#endif + +/*****************************************************************************/ + /** Master state: CLEAR ADDRESSES. */ void ec_fsm_master_state_clear_addresses( @@ -786,15 +1015,11 @@ fsm->slaves_responding[fsm->dev_idx]); } - EC_MASTER_DBG(master, 1, "Sending broadcast-write" - " to measure transmission delays on %s link.\n", - ec_device_names[fsm->dev_idx != 0]); - - ec_datagram_bwr(datagram, 0x0900, 1); - ec_datagram_zero(datagram); - fsm->datagram->device_index = fsm->dev_idx; - fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_dc_measure_delays; +#ifdef EC_LOOP_CONTROL + ec_fsm_master_enter_loop_control(fsm); +#else + ec_fsm_master_enter_dc_measure_delays(fsm); +#endif } /*****************************************************************************/ @@ -947,7 +1172,14 @@ } fsm->idle = 1; + +#ifdef EC_LOOP_CONTROL + // read DL status + ec_fsm_master_action_read_dl_status(fsm); +#else + // process next slave ec_fsm_master_action_next_slave_state(fsm); +#endif } /*****************************************************************************/ diff -r 19ff84bbbcb3 -r 1a969896d52e master/fsm_slave_scan.c --- a/master/fsm_slave_scan.c Thu Feb 19 15:19:29 2015 +0100 +++ b/master/fsm_slave_scan.c Fri Feb 20 16:06:23 2015 +0100 @@ -493,8 +493,6 @@ { ec_datagram_t *datagram = fsm->datagram; ec_slave_t *slave = fsm->slave; - uint16_t dl_status; - unsigned int i; if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) return; @@ -514,15 +512,7 @@ return; } - dl_status = EC_READ_U16(datagram->data); - for (i = 0; i < EC_MAX_PORTS; i++) { - slave->ports[i].link.link_up = - dl_status & (1 << (4 + i)) ? 1 : 0; - slave->ports[i].link.loop_closed = - dl_status & (1 << (8 + i * 2)) ? 1 : 0; - slave->ports[i].link.signal_detected = - dl_status & (1 << (9 + i * 2)) ? 1 : 0; - } + ec_slave_set_dl_status(slave, EC_READ_U16(datagram->data)); #ifdef EC_SII_ASSIGN ec_fsm_slave_scan_enter_assign_sii(fsm); diff -r 19ff84bbbcb3 -r 1a969896d52e master/slave.c --- a/master/slave.c Thu Feb 19 15:19:29 2015 +0100 +++ b/master/slave.c Fri Feb 20 16:06:23 2015 +0100 @@ -95,7 +95,7 @@ slave->ports[i].desc = EC_PORT_NOT_IMPLEMENTED; slave->ports[i].link.link_up = 0; - slave->ports[i].link.loop_closed = 0; + slave->ports[i].link.loop_closed = 1; slave->ports[i].link.signal_detected = 0; slave->sii.physical_layer[i] = 0xFF; @@ -103,6 +103,11 @@ slave->ports[i].next_slave = NULL; slave->ports[i].delay_to_next_dc = 0U; + +#ifdef EC_LOOP_CONTROL + slave->ports[i].state = EC_SLAVE_PORT_DOWN; + slave->ports[i].link_detection_jiffies = 0; +#endif } slave->base_fmmu_bit_operation = 0; @@ -278,10 +283,50 @@ /*****************************************************************************/ /** + * Sets the data-link state of a slave. + */ + +void ec_slave_set_dl_status(ec_slave_t *slave, /**< EtherCAT slave */ + uint16_t new_state /**< content of registers 0x0110-0x0111. */ + ) +{ + unsigned int i; + uint8_t state; + + for (i = 0; i < EC_MAX_PORTS; i++) { + // link status + state = new_state & (1 << (4 + i)) ? 1 : 0; + if (slave->ports[i].link.link_up != state) { + EC_SLAVE_DBG(slave, 1, "Port %u link status changed to %s.\n", + i, state ? "up" : "down"); + slave->ports[i].link.link_up = state; + } + + // loop status + state = new_state & (1 << (8 + i * 2)) ? 1 : 0; + if (slave->ports[i].link.loop_closed != state) { + EC_SLAVE_DBG(slave, 1, "Port %u loop status changed to %s.\n", + i, state ? "closed" : "open"); + slave->ports[i].link.loop_closed = state; + } + + // signal detection + state = new_state & (1 << (9 + i * 2)) ? 1 : 0; + if (slave->ports[i].link.signal_detected != state) { + EC_SLAVE_DBG(slave, 1, "Port %u signal status changed to %s.\n", + i, state ? "yes" : "no"); + slave->ports[i].link.signal_detected = state; + } + } +} + +/*****************************************************************************/ + +/** * Sets the application state of a slave. */ -void ec_slave_set_state(ec_slave_t *slave, /**< EtherCAT slave */ +void ec_slave_set_al_status(ec_slave_t *slave, /**< EtherCAT slave */ ec_slave_state_t new_state /**< new application state */ ) { diff -r 19ff84bbbcb3 -r 1a969896d52e master/slave.h --- a/master/slave.h Thu Feb 19 15:19:29 2015 +0100 +++ b/master/slave.h Fri Feb 20 16:06:23 2015 +0100 @@ -113,6 +113,24 @@ /*****************************************************************************/ +#ifdef EC_LOOP_CONTROL + +/** Slave port state. + */ +typedef enum { + EC_SLAVE_PORT_DOWN, + EC_SLAVE_PORT_WAIT, + EC_SLAVE_PORT_UP +} ec_slave_port_state_t; + +/** Wait time in [ms] from detecting a link to opening a port. + */ +#define EC_PORT_WAIT_MS 2000 + +#endif + +/*****************************************************************************/ + /** Slave port. */ typedef struct { @@ -123,6 +141,10 @@ measurement. */ uint32_t delay_to_next_dc; /**< Delay to next slave with DC support behind this port [ns]. */ +#ifdef EC_LOOP_CONTROL + ec_slave_port_state_t state; /**< Port state for loop control. */ + unsigned long link_detection_jiffies; /**< Time of link detection. */ +#endif } ec_slave_port_t; /*****************************************************************************/ @@ -245,7 +267,8 @@ void ec_slave_clear_sync_managers(ec_slave_t *); void ec_slave_request_state(ec_slave_t *, ec_slave_state_t); -void ec_slave_set_state(ec_slave_t *, ec_slave_state_t); +void ec_slave_set_dl_status(ec_slave_t *, uint16_t); +void ec_slave_set_al_status(ec_slave_t *, ec_slave_state_t); // SII categories int ec_slave_fetch_sii_strings(ec_slave_t *, const uint8_t *, size_t);