diff --git a/documentation/graphs/fsm_slave_scan.dot b/documentation/graphs/fsm_slave_scan.dot index 8c065792..ed29179c 100644 --- a/documentation/graphs/fsm_slave_scan.dot +++ b/documentation/graphs/fsm_slave_scan.dot @@ -14,7 +14,14 @@ digraph slavescan { state -> base [weight=10] base [fontname="Helvetica"] - base -> datalink [weight=10] + base -> dc_cap [weight=10] + base -> enter_datalink [fontname="Helvetica", label="DC not\nsupported"] + + dc_cap [fontname="Helvetica"] + dc_cap -> enter_datalink [weight=10] + + enter_datalink [shape=point, label=""] + enter_datalink -> datalink [weight=10] datalink [fontname="Helvetica"] datalink -> sii_size [weight=10] @@ -23,10 +30,21 @@ digraph slavescan { sii_size -> sii_data [weight=10] sii_data [fontname="Helvetica"] - sii_data -> preop [weight=10] + sii_data -> end [fontname="Helvetica", label="No category\ndata"] + sii_data -> enter_preop [weight=10] + + enter_preop [shape=point, label=""] + enter_preop -> preop [fontname="Helvetica", label="Not in\nPREOP"] + enter_preop -> sync [weight=10] preop [fontname="Helvetica"] - preop -> pdos [weight=10] + preop -> enter_pdos [weight=10] + + sync [fontname="Helvetica"] + sync -> enter_pdos [weight=10] + + enter_pdos [shape=point, label=""] + enter_pdos -> pdos [weight=10] pdos [fontname="Helvetica"] pdos -> end [weight=10] diff --git a/master/cdev.c b/master/cdev.c index 395ccdb2..b4f4163a 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -262,6 +262,7 @@ int ec_cdev_ioctl_slave( data.fmmu_bit = slave->base_fmmu_bit_operation; data.dc_supported = slave->base_dc_supported; data.dc_range = slave->base_dc_range; + data.has_dc_system_time = slave->has_dc_system_time; data.al_state = slave->current_state; data.error_flag = slave->error_flag; diff --git a/master/fsm_slave_config.c b/master/fsm_slave_config.c index aa862e75..415a9f5a 100644 --- a/master/fsm_slave_config.c +++ b/master/fsm_slave_config.c @@ -348,7 +348,7 @@ void ec_fsm_slave_config_enter_dc_clear_assign( ec_slave_t *slave = fsm->slave; ec_datagram_t *datagram = fsm->datagram; - if (!slave->base_dc_supported) { + if (!slave->base_dc_supported || !slave->has_dc_system_time) { ec_fsm_slave_config_enter_mbox_sync(fsm); return; } @@ -1035,7 +1035,7 @@ void ec_fsm_slave_config_enter_dc_cycle( } if (config->dc_assign_activate) { - if (!slave->base_dc_supported) { + if (!slave->base_dc_supported || !slave->has_dc_system_time) { EC_WARN("Slave %u seems not to support distributed clocks!\n", slave->ring_position); } diff --git a/master/fsm_slave_scan.c b/master/fsm_slave_scan.c index 00becefd..6198d093 100644 --- a/master/fsm_slave_scan.c +++ b/master/fsm_slave_scan.c @@ -47,6 +47,7 @@ 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 *); void ec_fsm_slave_scan_state_base(ec_fsm_slave_scan_t *); +void ec_fsm_slave_scan_state_dc_cap(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *); @@ -57,6 +58,7 @@ 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 *); void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *); void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *); @@ -316,6 +318,78 @@ void ec_fsm_slave_scan_state_base(ec_fsm_slave_scan_t *fsm /**< slave state mach slave->base_dc_supported = (octet >> 2) & 0x01; slave->base_dc_range = ((octet >> 3) & 0x01) ? EC_DC_64 : EC_DC_32; + if (slave->base_dc_supported) { + // read DC capabilities + ec_datagram_fprd(datagram, slave->station_address, 0x0910, + slave->base_dc_range == EC_DC_64 ? 8 : 4); + ec_datagram_zero(datagram); + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_slave_scan_state_dc_cap; + } else { + ec_fsm_slave_scan_enter_datalink(fsm); + } +} + +/*****************************************************************************/ + +/** + Slave scan state: DC CAPABILITIES. +*/ + +void ec_fsm_slave_scan_state_dc_cap( + ec_fsm_slave_scan_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) + return; + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_slave_scan_state_error; + EC_ERR("Failed to receive system time datagram for slave %u" + " (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter == 1) { + slave->has_dc_system_time = 1; + if (slave->master->debug_level) { + EC_DBG("Slave %u has the System Time register.\n", + slave->ring_position); + } + } else if (datagram->working_counter == 0) { + if (slave->master->debug_level) { + EC_DBG("Slave %u has no System Time register; delay " + "measurement only.\n", slave->ring_position); + } + } else { + fsm->slave->error_flag = 1; + fsm->state = ec_fsm_slave_scan_state_error; + EC_ERR("Failed to determine, if system time register is " + "supported by slave %u: ", slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + ec_fsm_slave_scan_enter_datalink(fsm); +} + +/*****************************************************************************/ + +/** + Slave scan entry function: DATALINK. +*/ + +void ec_fsm_slave_scan_enter_datalink( + ec_fsm_slave_scan_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; + // read data link status ec_datagram_fprd(datagram, slave->station_address, 0x0110, 2); ec_datagram_zero(datagram); diff --git a/master/ioctl.h b/master/ioctl.h index 431fe246..3df49f8a 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -169,6 +169,7 @@ typedef struct { uint8_t fmmu_bit; uint8_t dc_supported; ec_slave_dc_range_t dc_range; + uint8_t has_dc_system_time; uint8_t al_state; uint8_t error_flag; uint8_t sync_count; diff --git a/master/master.c b/master/master.c index 231b7a80..3b312d4d 100644 --- a/master/master.c +++ b/master/master.c @@ -1363,7 +1363,7 @@ void ec_master_find_dc_ref_clock( for (slave = master->slaves; slave < master->slaves + master->slave_count; slave++) { - if (slave->base_dc_supported) { + if (slave->base_dc_supported && slave->has_dc_system_time) { ref_clock_addr = slave->station_address; break; } diff --git a/master/slave.c b/master/slave.c index 222b12e1..0b5f19a1 100644 --- a/master/slave.c +++ b/master/slave.c @@ -100,6 +100,7 @@ void ec_slave_init( slave->base_fmmu_bit_operation = 0; slave->base_dc_supported = 0; slave->base_dc_range = EC_DC_32; + slave->has_dc_system_time = 0; slave->sii_words = NULL; slave->sii_nwords = 0; diff --git a/master/slave.h b/master/slave.h index ea522718..adcee7b1 100644 --- a/master/slave.h +++ b/master/slave.h @@ -133,6 +133,9 @@ struct ec_slave uint8_t base_fmmu_bit_operation; /**< FMMU bit operation is supported. */ uint8_t base_dc_supported; /**< Distributed clocks are supported. */ ec_slave_dc_range_t base_dc_range; /**< DC range. */ + uint8_t has_dc_system_time; /**< The slave supports the DC system time + register. Otherwise it can only be used for + delay measurement. */ // data link status ec_slave_port_t ports[EC_MAX_PORTS]; /**< Port link status. */ diff --git a/tool/CommandSlaves.cpp b/tool/CommandSlaves.cpp index 43ffd9db..eb74d378 100644 --- a/tool/CommandSlaves.cpp +++ b/tool/CommandSlaves.cpp @@ -268,18 +268,21 @@ void CommandSlaves::showSlaves( << (si->fmmu_bit ? "yes" : "no") << endl << " Distributed clocks: "; if (si->dc_supported) { - cout << "yes ("; - switch (si->dc_range) { - case EC_DC_32: - cout << "32 bit"; - break; - case EC_DC_64: - cout << "64 bit"; - break; - default: - cout << "???"; + if (si->has_dc_system_time) { + cout << "yes, "; + switch (si->dc_range) { + case EC_DC_32: + cout << "32 bit"; + break; + case EC_DC_64: + cout << "64 bit"; + break; + default: + cout << "???"; + } + } else { + cout << "yes, delay measurement only"; } - cout << ")"; } else { cout << "no"; }