Added --enable-loop-control to make use of the loop control registers.
This commit is contained in:
parent
b4d4a98287
commit
c81f24e68b
29
configure.ac
29
configure.ac
|
|
@ -1030,6 +1030,35 @@ else
|
|||
AC_MSG_RESULT([no])
|
||||
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([
|
||||
|
|
|
|||
|
|
@ -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 @@ void ec_fsm_master_state_broadcast(
|
|||
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 @@ void ec_fsm_master_action_next_slave_state(
|
|||
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 @@ void ec_fsm_master_action_next_slave_state(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#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 @@ void ec_fsm_master_action_configure(
|
|||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state: READ STATE.
|
||||
/** 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 @@ void ec_fsm_master_state_read_state(
|
|||
}
|
||||
|
||||
// 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 @@ void ec_fsm_master_state_read_state(
|
|||
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 @@ void ec_fsm_master_enter_clear_addresses(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** 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 @@ void ec_fsm_master_state_clear_addresses(
|
|||
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 @@ void ec_fsm_master_state_configure_slave(
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -493,8 +493,6 @@ void ec_fsm_slave_scan_state_datalink(
|
|||
{
|
||||
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 @@ void ec_fsm_slave_scan_state_datalink(
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ void ec_slave_init(
|
|||
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 @@ void ec_slave_init(
|
|||
|
||||
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;
|
||||
|
|
@ -277,11 +282,51 @@ void ec_slave_clear_sync_managers(ec_slave_t *slave /**< EtherCAT slave. */)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 @@ typedef struct {
|
|||
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(ec_slave_t *);
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue