Added --enable-loop-control to make use of the loop control registers.
--- 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
--- 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
}
/*****************************************************************************/
--- 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);
--- 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 */
)
{
--- 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);