diff -r ea38efeeb7b3 -r 6aa393418fb3 master/fsm_slave_config.c --- a/master/fsm_slave_config.c Fri May 07 15:26:26 2010 +0200 +++ b/master/fsm_slave_config.c Tue May 11 13:57:58 2010 +0200 @@ -44,9 +44,20 @@ /*****************************************************************************/ -/** Time difference [ns] to tolerate without setting a new system time offset. - */ -#define EC_SYSTEM_TIME_TOLERANCE_NS 100000000 +/** Maximum clock difference (in ns) before going to SAFEOP. + * + * Wait for DC time difference to drop under this absolute value before + * requesting SAFEOP. + */ +#define EC_DC_MAX_SYNC_DIFF_NS 5000 + +/** Maximum time (in ms) to wait for clock discipline. + */ +#define EC_DC_SYNC_WAIT_MS 5000 + +/** Time offset (in ns), that is added to cyclic start time. + */ +#define EC_DC_START_OFFSET 100000000ULL /*****************************************************************************/ @@ -55,8 +66,6 @@ void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *); -void ec_fsm_slave_config_state_dc_read_offset(ec_fsm_slave_config_t *); -void ec_fsm_slave_config_state_dc_write_offset(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *); @@ -67,6 +76,7 @@ void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *); @@ -196,10 +206,7 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - if (fsm->slave->master->debug_level) { - EC_DBG("Configuring slave %u...\n", fsm->slave->ring_position); - } - + EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n"); ec_fsm_slave_config_enter_init(fsm); } @@ -224,7 +231,6 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - ec_master_t *master = fsm->slave->master; ec_slave_t *slave = fsm->slave; ec_datagram_t *datagram = fsm->datagram; @@ -237,18 +243,14 @@ return; } - if (master->debug_level) { - EC_DBG("Slave %u is now in INIT.\n", slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Now in INIT.\n"); if (!slave->base_fmmu_count) { // skip FMMU configuration ec_fsm_slave_config_enter_clear_sync(fsm); return; } - if (master->debug_level) - EC_DBG("Clearing FMMU configurations of slave %u...\n", - slave->ring_position); + EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n"); // clear FMMU configurations ec_datagram_fpwr(datagram, slave->station_address, @@ -273,16 +275,14 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed receive FMMU clearing datagram for slave %u.\n", - fsm->slave->ring_position); + EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n"); return; } if (datagram->working_counter != 1) { fsm->slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to clear FMMUs of slave %u: ", - fsm->slave->ring_position); + EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: "); ec_datagram_print_wc_error(datagram); return; } @@ -308,9 +308,7 @@ return; } - if (slave->master->debug_level) - EC_DBG("Clearing sync manager configurations of slave %u...\n", - slave->ring_position); + EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n"); sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count; @@ -336,16 +334,16 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed receive sync manager clearing datagram" - " for slave %u.\n", fsm->slave->ring_position); + EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager" + " clearing datagram.\n"); return; } if (datagram->working_counter != 1) { fsm->slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to clear sync manager configurations of slave %u: ", - fsm->slave->ring_position); + EC_SLAVE_ERR(fsm->slave, + "Failed to clear sync manager configurations: "); ec_datagram_print_wc_error(datagram); return; } @@ -369,9 +367,7 @@ return; } - if (slave->master->debug_level) - EC_DBG("Clearing DC assignment of slave %u...\n", - slave->ring_position); + EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n"); ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2); ec_datagram_zero(datagram); @@ -394,202 +390,17 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed receive DC assignment clearing datagram" - " for slave %u.\n", fsm->slave->ring_position); - return; - } - - if (fsm->slave->master->debug_level && datagram->working_counter != 1) { + EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment" + " clearing datagram.\n"); + return; + } + + if (datagram->working_counter != 1) { // clearing the DC assignment does not succeed on simple slaves - EC_DBG("Failed to clear DC assignment of slave %u: ", - fsm->slave->ring_position); + EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: "); ec_datagram_print_wc_error(datagram); } - // read DC system time (0x0910, 64 bit) - // gap (64 bit) - // and time offset (0x0920, 64 bit) - ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0910, 24); - fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_slave_config_state_dc_read_offset; -} - -/*****************************************************************************/ - -/** Configure 32 bit time offset. - */ -u64 ec_fsm_slave_config_dc_offset32( - ec_fsm_slave_config_t *fsm, /**< slave state machine */ - u64 system_time, /**< System time register. */ - u64 old_offset, /**< Time offset register. */ - u64 correction /**< Correction. */ - ) -{ - ec_slave_t *slave = fsm->slave; - u32 correction32, system_time32, old_offset32, new_offset; - s32 time_diff; - - system_time32 = (u32) system_time; - old_offset32 = (u32) old_offset; - - // correct read system time by elapsed time since read operation - correction32 = (u32)correction; - system_time32 -= correction32; - time_diff = (u32) slave->master->app_time - system_time32; - - if (slave->master->debug_level) - EC_DBG("Slave %u: system_time=%u (corrected with %u)," - " app_time=%u, diff=%i\n", - slave->ring_position, system_time32, correction32, - (u32) slave->master->app_time, time_diff); - - if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) { - new_offset = time_diff + old_offset32; - if (slave->master->debug_level) - EC_DBG("Slave %u: Setting time offset to %u (was %u)\n", - slave->ring_position, new_offset, old_offset32); - return (u64) new_offset; - } else { - if (slave->master->debug_level) - EC_DBG("Slave %u: Not touching time offset.\n", - slave->ring_position); - return old_offset; - } -} - -/*****************************************************************************/ - -/** Configure 64 bit time offset. - */ -u64 ec_fsm_slave_config_dc_offset64( - ec_fsm_slave_config_t *fsm, /**< slave state machine */ - u64 system_time, /**< System time register. */ - u64 old_offset, /**< Time offset register. */ - u64 correction /**< Correction. */ - ) -{ - ec_slave_t *slave = fsm->slave; - u64 new_offset; - s64 time_diff; - - system_time -= correction; - time_diff = fsm->slave->master->app_time - system_time; - - if (slave->master->debug_level) - EC_DBG("Slave %u: system_time=%llu (corrected with %llu)," - " app_time=%llu, diff=%lli\n", - slave->ring_position, system_time, correction, - slave->master->app_time, time_diff); - - - if (EC_ABS(time_diff) > EC_SYSTEM_TIME_TOLERANCE_NS) { - new_offset = time_diff + old_offset; - if (slave->master->debug_level) - EC_DBG("Slave %u: Setting time offset to %llu (was %llu)\n", - slave->ring_position, new_offset, old_offset); - } else { - new_offset = old_offset; - if (slave->master->debug_level) - EC_DBG("Slave %u: Not touching time offset.\n", - slave->ring_position); - } - - return new_offset; -} - -/*****************************************************************************/ - -/** Slave configuration state: DC READ OFFSET. - */ -void ec_fsm_slave_config_state_dc_read_offset( - ec_fsm_slave_config_t *fsm /**< slave state machine */ - ) -{ - ec_datagram_t *datagram = fsm->datagram; - ec_slave_t *slave = fsm->slave; - u64 system_time, old_offset, new_offset, correction; - if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) - return; - - if (datagram->state != EC_DATAGRAM_RECEIVED) { - fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive DC times datagram for slave %u: ", - slave->ring_position); - ec_datagram_print_state(datagram); - return; - } - - if (datagram->working_counter != 1) { - slave->error_flag = 1; - fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to get DC times of slave %u: ", - slave->ring_position); - ec_datagram_print_wc_error(datagram); - return; - } - - system_time = EC_READ_U64(datagram->data); // 0x0910 - old_offset = EC_READ_U64(datagram->data + 16); // 0x0920 - /* correct read system time by elapsed time since read operation - and the app_time set time */ -#ifdef EC_HAVE_CYCLES - correction = - (datagram->cycles_sent - slave->master->dc_cycles_app_time) - * 1000000LL; - do_div(correction,cpu_khz); -#else - correction = - (u64) ((datagram->jiffies_sent-slave->master->dc_jiffies_app_time) * 1000 / HZ) - * 1000000; -#endif - - if (slave->base_dc_range == EC_DC_32) { - new_offset = ec_fsm_slave_config_dc_offset32(fsm, - system_time, old_offset, correction); - } else { - new_offset = ec_fsm_slave_config_dc_offset64(fsm, - system_time, old_offset, correction); - } - - // set DC system time offset and transmission delay - ec_datagram_fpwr(datagram, slave->station_address, 0x0920, 12); - EC_WRITE_U64(datagram->data, new_offset); - EC_WRITE_U32(datagram->data + 8, slave->transmission_delay); - fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_slave_config_state_dc_write_offset; -} - -/*****************************************************************************/ - -/** Slave configuration state: DC WRITE OFFSET. - */ -void ec_fsm_slave_config_state_dc_write_offset( - ec_fsm_slave_config_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_config_state_error; - EC_ERR("Failed to receive DC system time offset datagram for" - " slave %u: ", slave->ring_position); - ec_datagram_print_state(datagram); - return; - } - - if (datagram->working_counter != 1) { - slave->error_flag = 1; - fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set DC system time offset of slave %u: ", - slave->ring_position); - ec_datagram_print_wc_error(datagram); - return; - } - ec_fsm_slave_config_enter_mbox_sync(fsm); } @@ -601,7 +412,6 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - ec_master_t *master = fsm->slave->master; ec_slave_t *slave = fsm->slave; ec_datagram_t *datagram = fsm->datagram; unsigned int i; @@ -609,26 +419,19 @@ // slave is now in INIT if (slave->current_state == slave->requested_state) { fsm->state = ec_fsm_slave_config_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %u.\n", - slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Finished configuration.\n"); return; } if (!slave->sii.mailbox_protocols) { // no mailbox protocols supported - if (master->debug_level) - EC_DBG("Slave %u does not support mailbox communication.\n", - slave->ring_position); + EC_SLAVE_DBG(slave, 1, "Slave does not support" + " mailbox communication.\n"); ec_fsm_slave_config_enter_boot_preop(fsm); return; } - if (master->debug_level) { - EC_DBG("Configuring mailbox sync managers of slave %u.\n", - slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n"); if (slave->requested_state == EC_SLAVE_STATE_BOOT) { ec_sync_t sync; @@ -684,10 +487,8 @@ } else { // no mailbox sync manager configurations provided ec_sync_t sync; - if (master->debug_level) - EC_DBG("Slave %u does not provide" - " mailbox sync manager configurations.\n", - slave->ring_position); + EC_SLAVE_DBG(slave, 1, "Slave does not provide" + " mailbox sync manager configurations.\n"); ec_datagram_fpwr(datagram, slave->station_address, 0x0800, EC_SYNC_PAGE_SIZE * 2); @@ -742,8 +543,8 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive sync manager configuration datagram for" - " slave %u: ", slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive sync manager" + " configuration datagram: "); ec_datagram_print_state(datagram); return; } @@ -764,12 +565,11 @@ if (diff >= HZ) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Timeout while configuring mailbox sync managers of" - " slave %u.\n", slave->ring_position); + EC_SLAVE_ERR(slave, "Timeout while configuring" + " mailbox sync managers.\n"); return; - } - else if (slave->master->debug_level) { - EC_DBG("Resending after %u ms...\n", + } else { + EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n", (unsigned int) diff * 1000 / HZ); } @@ -780,8 +580,7 @@ else if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set sync managers of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to set sync managers: "); ec_datagram_print_wc_error(datagram); return; } @@ -817,7 +616,6 @@ ) { ec_slave_t *slave = fsm->slave; - ec_master_t *master = fsm->slave->master; if (ec_fsm_change_exec(fsm->fsm_change)) return; @@ -831,18 +629,12 @@ // slave is now in BOOT or PREOP slave->jiffies_preop = fsm->datagram->jiffies_received; - if (master->debug_level) { - EC_DBG("Slave %u is now in %s.\n", slave->ring_position, - slave->requested_state != EC_SLAVE_STATE_BOOT - ? "PREOP" : "BOOT"); - } + EC_SLAVE_DBG(slave, 1, "Now in %s.\n", + slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT"); if (slave->current_state == slave->requested_state) { fsm->state = ec_fsm_slave_config_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %u.\n", - slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Finished configuration.\n"); return; } @@ -891,8 +683,7 @@ if (ec_fsm_coe_exec(fsm->fsm_coe)) return; if (!ec_fsm_coe_success(fsm->fsm_coe)) { - EC_ERR("SDO configuration failed for slave %u.\n", - fsm->slave->ring_position); + EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n"); fsm->slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; return; @@ -968,8 +759,7 @@ } if (!ec_fsm_soe_success(fsm_soe)) { - EC_ERR("SoE configuration failed for slave %u.\n", - fsm->slave->ring_position); + EC_SLAVE_ERR(slave, "SoE configuration failed.\n"); fsm->slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; return; @@ -1029,8 +819,7 @@ } if (!ec_fsm_pdo_success(fsm->fsm_pdo)) { - EC_WARN("PDO configuration failed on slave %u.\n", - fsm->slave->ring_position); + EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n"); } ec_fsm_slave_config_enter_watchdog_divider(fsm); @@ -1046,13 +835,11 @@ { ec_slave_t *slave = fsm->slave; ec_datagram_t *datagram = fsm->datagram; - ec_master_t *master = slave->master; ec_slave_config_t *config = slave->config; if (config && config->watchdog_divider) { - if (master->debug_level) - EC_DBG("Setting watchdog divider to %u.\n", - config->watchdog_divider); + EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n", + config->watchdog_divider); ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2); EC_WRITE_U16(datagram->data, config->watchdog_divider); @@ -1079,16 +866,15 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive watchdog divider configuration datagram for" - " slave %u: ", slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive watchdog divider" + " configuration datagram: "); ec_datagram_print_state(datagram); return; } if (datagram->working_counter != 1) { slave->error_flag = 1; - EC_WARN("Failed to set watchdog divider of slave %u: ", - slave->ring_position); + EC_SLAVE_WARN(slave, "Failed to set watchdog divider: "); ec_datagram_print_wc_error(datagram); return; } @@ -1109,9 +895,8 @@ ec_slave_config_t *config = slave->config; if (config && config->watchdog_intervals) { - if (slave->master->debug_level) - EC_DBG("Setting process data watchdog intervals to %u.\n", - config->watchdog_intervals); + EC_SLAVE_DBG(slave, 1, "Setting process data" + " watchdog intervals to %u.\n", config->watchdog_intervals); ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2); EC_WRITE_U16(datagram->data, config->watchdog_intervals); @@ -1140,15 +925,15 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive sync manager watchdog configuration " - "datagram for slave %u: ", slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive sync manager" + " watchdog configuration datagram: "); ec_datagram_print_state(datagram); return; } if (datagram->working_counter != 1) { - EC_WARN("Failed to set process data watchdog intervals of slave %u: ", - slave->ring_position); + EC_SLAVE_WARN(slave, "Failed to set process data" + " watchdog intervals: "); ec_datagram_print_wc_error(datagram); } @@ -1227,8 +1012,8 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive process data sync manager configuration" - " datagram for slave %u: ", slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive process data sync" + " manager configuration datagram: "); ec_datagram_print_state(datagram); return; } @@ -1236,8 +1021,7 @@ if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set process data sync managers of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to set process data sync managers: "); ec_datagram_print_wc_error(datagram); return; } @@ -1267,8 +1051,8 @@ if (slave->base_fmmu_count < slave->config->used_fmmus) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Slave %u has less FMMUs (%u) than requested (%u).\n", - slave->ring_position, slave->base_fmmu_count, + EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)" + " than requested (%u).\n", slave->base_fmmu_count, slave->config->used_fmmus); return; } @@ -1287,8 +1071,8 @@ if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to determine PDO sync manager for FMMU on slave" - " %u!\n", slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager" + " for FMMU!\n"); return; } ec_fmmu_config_page(fmmu, sync, @@ -1315,8 +1099,7 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive FMMUs datagram for slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: "); ec_datagram_print_state(datagram); return; } @@ -1324,8 +1107,7 @@ if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set FMMUs of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to set FMMUs: "); ec_datagram_print_wc_error(datagram); return; } @@ -1352,15 +1134,12 @@ if (config->dc_assign_activate) { if (!slave->base_dc_supported || !slave->has_dc_system_time) { - EC_WARN("Slave %u seems not to support distributed clocks!\n", - slave->ring_position); + EC_SLAVE_WARN(slave, "Slave seems not to support" + " distributed clocks!\n"); } - if (slave->master->debug_level) - EC_DBG("Slave %u: Setting DC cycle times to %u / %u.\n", - slave->ring_position, - config->dc_sync[0].cycle_time, - config->dc_sync[1].cycle_time); + EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n", + config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time); // set DC cycle times ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8); @@ -1384,8 +1163,53 @@ { ec_datagram_t *datagram = fsm->datagram; ec_slave_t *slave = fsm->slave; + ec_slave_config_t *config = slave->config; + + if (!config) { // config removed in the meantime + ec_fsm_slave_config_reconfigure(fsm); + return; + } + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) + return; + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + fsm->state = ec_fsm_slave_config_state_error; + EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: "); + ec_datagram_print_state(datagram); + return; + } + + if (datagram->working_counter != 1) { + slave->error_flag = 1; + fsm->state = ec_fsm_slave_config_state_error; + EC_SLAVE_ERR(slave, "Failed to set DC cycle times: "); + ec_datagram_print_wc_error(datagram); + return; + } + + EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n"); + + fsm->jiffies_start = jiffies; + ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4); + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_slave_config_state_dc_sync_check; +} + +/*****************************************************************************/ + +/** Slave configuration state: DC SYNC CHECK. + */ +void ec_fsm_slave_config_state_dc_sync_check( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_datagram_t *datagram = fsm->datagram; + ec_slave_t *slave = fsm->slave; ec_master_t *master = slave->master; ec_slave_config_t *config = slave->config; + uint32_t abs_sync_diff; + unsigned long diff_ms; ec_sync_signal_t *sync0 = &config->dc_sync[0]; u64 start_time; @@ -1399,8 +1223,7 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive DC cycle times datagram for slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: "); ec_datagram_print_state(datagram); return; } @@ -1408,19 +1231,40 @@ if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set DC cycle times of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to check DC synchrony: "); ec_datagram_print_wc_error(datagram); return; } + abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff; + diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ; + + if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) { + + if (diff_ms >= EC_DC_SYNC_WAIT_MS) { + EC_SLAVE_WARN(slave, "Slave did not sync after %u ms.\n", + (u32) diff_ms); + } else { + EC_SLAVE_DBG(slave, 1, "Sync after %4u ms: %10u ns\n", + (u32) diff_ms, abs_sync_diff); + + // check synchrony again + ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4); + fsm->retries = EC_FSM_RETRIES; + return; + } + } else { + EC_SLAVE_DBG(slave, 1, "%u ns difference after %u ms.\n", + abs_sync_diff, (u32) diff_ms); + } + // set DC start time - start_time = master->app_time + 100000000ULL; // now + X ns + start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns // FIXME use slave's local system time here? if (sync0->cycle_time) { // find correct phase - if (master->has_start_time) { + if (master->has_app_time) { u64 diff, start; u32 remainder; @@ -1430,24 +1274,22 @@ start = start_time + sync0->cycle_time - remainder + sync0->shift_time; - if (master->debug_level) { - EC_DBG("app_start_time=%llu\n", master->app_start_time); - EC_DBG(" start_time=%llu\n", start_time); - EC_DBG(" cycle_time=%u\n", sync0->cycle_time); - EC_DBG(" shift_time=%u\n", sync0->shift_time); - EC_DBG(" remainder=%u\n", remainder); - EC_DBG(" start=%llu\n", start); - } + EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n", + master->app_start_time); + EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time); + EC_SLAVE_DBG(slave, 1, " cycle_time=%u\n", sync0->cycle_time); + EC_SLAVE_DBG(slave, 1, " shift_time=%u\n", sync0->shift_time); + EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder); + EC_SLAVE_DBG(slave, 1, " start=%llu\n", start); start_time = start; } else { - EC_WARN("No application time supplied. Cyclic start time will " - "not be in phase for slave %u.\n", slave->ring_position); + EC_SLAVE_WARN(slave, "No application time supplied." + " Cyclic start time will not be in phase.\n"); } } - if (master->debug_level) - EC_DBG("Slave %u: Setting DC cyclic operation start time to %llu.\n", - slave->ring_position, start_time); + EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation" + " start time to %llu.\n", start_time); ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8); EC_WRITE_U64(datagram->data, start_time); @@ -1477,8 +1319,7 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive DC start time datagram for slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: "); ec_datagram_print_state(datagram); return; } @@ -1486,15 +1327,13 @@ if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set DC start time of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to set DC start time: "); ec_datagram_print_wc_error(datagram); return; } - if (slave->master->debug_level) - EC_DBG("Slave %u: Setting DC AssignActivate to 0x%04x.\n", - slave->ring_position, config->dc_assign_activate); + EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n", + config->dc_assign_activate); // assign sync unit to EtherCAT or PDI ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2); @@ -1519,8 +1358,7 @@ if (datagram->state != EC_DATAGRAM_RECEIVED) { fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to receive DC activation datagram for slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: "); ec_datagram_print_state(datagram); return; } @@ -1528,8 +1366,7 @@ if (datagram->working_counter != 1) { slave->error_flag = 1; fsm->state = ec_fsm_slave_config_state_error; - EC_ERR("Failed to set DC cyclic operation state of slave %u: ", - slave->ring_position); + EC_SLAVE_ERR(slave, "Failed to activate DC: "); ec_datagram_print_wc_error(datagram); return; } @@ -1558,7 +1395,6 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - ec_master_t *master = fsm->slave->master; ec_slave_t *slave = fsm->slave; if (ec_fsm_change_exec(fsm->fsm_change)) return; @@ -1572,16 +1408,11 @@ // slave is now in SAFEOP - if (master->debug_level) { - EC_DBG("Slave %u is now in SAFEOP.\n", slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n"); if (fsm->slave->current_state == fsm->slave->requested_state) { fsm->state = ec_fsm_slave_config_state_end; // successful - if (master->debug_level) { - EC_DBG("Finished configuration of slave %u.\n", - slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Finished configuration.\n"); return; } @@ -1599,7 +1430,6 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - ec_master_t *master = fsm->slave->master; ec_slave_t *slave = fsm->slave; if (ec_fsm_change_exec(fsm->fsm_change)) return; @@ -1613,10 +1443,7 @@ // slave is now in OP - if (master->debug_level) { - EC_DBG("Slave %u is now in OP.\n", slave->ring_position); - EC_DBG("Finished configuration of slave %u.\n", slave->ring_position); - } + EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n"); fsm->state = ec_fsm_slave_config_state_end; // successful } @@ -1629,10 +1456,8 @@ ec_fsm_slave_config_t *fsm /**< slave state machine */ ) { - if (fsm->slave->master->debug_level) { - EC_DBG("Slave configuration for slave %u detached during " - "configuration. Reconfiguring.", fsm->slave->ring_position); - } + EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during " + "configuration. Reconfiguring."); ec_fsm_slave_config_enter_init(fsm); // reconfigure }