# HG changeset patch
# User Gavin Lambert <gavinl@compacsort.com>
# Parent 0dc2082f5b987a3c70858d1f011083f5f36874b7
After a comms interruption, allow SAFEOP->OP directly instead of re-INIT.

If a slave was in SAFEOP+ERROR with an observed sync timeout, it was probably a
comms interruption and its current configuration should still be correct.

diff -r 0dc2082f5b98 master/fsm_change.c
--- a/master/fsm_change.c	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/fsm_change.c	Fri Mar 13 13:26:31 2015 +1300
@@ -425,8 +425,10 @@
         EC_SLAVE_WARN(fsm->slave, "Reception of AL status code"
                 " datagram failed: ");
         ec_datagram_print_wc_error(datagram);
+        fsm->slave->last_al_error = 0;
     } else {
         code = EC_READ_U16(datagram->data);
+        fsm->slave->last_al_error = code;
         for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
             if (al_msg->code != code) {
                 continue;
diff -r 0dc2082f5b98 master/fsm_master.c
--- a/master/fsm_master.c	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/fsm_master.c	Fri Mar 13 13:26:31 2015 +1300
@@ -680,7 +680,16 @@
 
         fsm->idle = 0;
         fsm->state = ec_fsm_master_state_configure_slave;
-        ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave);
+        if (!slave->force_config
+                && slave->current_state == EC_SLAVE_STATE_SAFEOP
+                && slave->requested_state == EC_SLAVE_STATE_OP
+                && slave->last_al_error == 0x001B) {
+            // last error was a sync watchdog timeout; assume a comms
+            // interruption and request a quick transition back to OP
+            ec_fsm_slave_config_quick_start(&fsm->fsm_slave_config, slave);
+        } else {
+            ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave);
+        }
         fsm->state(fsm); // execute immediately
         fsm->datagram->device_index = fsm->slave->device_index;
         return;
diff -r 0dc2082f5b98 master/fsm_slave_config.c
--- a/master/fsm_slave_config.c	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/fsm_slave_config.c	Fri Mar 13 13:26:31 2015 +1300
@@ -62,6 +62,7 @@
 /*****************************************************************************/
 
 void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *);
+void ec_fsm_slave_config_state_quick_start(ec_fsm_slave_config_t *);
 void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *);
 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 *);
@@ -164,6 +165,19 @@
 
 /*****************************************************************************/
 
+/** Start slave configuration state machine for "quick" SAFEOP->OP
+ */
+void ec_fsm_slave_config_quick_start(
+        ec_fsm_slave_config_t *fsm, /**< slave state machine */
+        ec_slave_t *slave /**< slave to configure */
+        )
+{
+    fsm->slave = slave;
+    fsm->state = ec_fsm_slave_config_state_quick_start;
+}
+
+/*****************************************************************************/
+
 /**
  * \return false, if state machine has terminated
  */
@@ -226,6 +240,18 @@
 
 /*****************************************************************************/
 
+/** Slave configuration state: QUICK START.
+ */
+void ec_fsm_slave_config_state_quick_start(
+        ec_fsm_slave_config_t *fsm /**< slave state machine */
+        )
+{
+    EC_SLAVE_DBG(fsm->slave, 1, "Configuring (quick)...\n");
+    ec_fsm_slave_config_enter_soe_conf_safeop(fsm);
+}
+
+/*****************************************************************************/
+
 /** Start state change to INIT.
  */
 void ec_fsm_slave_config_enter_init(
diff -r 0dc2082f5b98 master/fsm_slave_config.h
--- a/master/fsm_slave_config.h	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/fsm_slave_config.h	Fri Mar 13 13:26:31 2015 +1300
@@ -77,6 +77,7 @@
 void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *);
 
 void ec_fsm_slave_config_start(ec_fsm_slave_config_t *, ec_slave_t *);
+void ec_fsm_slave_config_quick_start(ec_fsm_slave_config_t *, ec_slave_t *);
 
 int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *);
 int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *);
diff -r 0dc2082f5b98 master/slave.c
--- a/master/slave.c	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/slave.c	Fri Mar 13 13:26:31 2015 +1300
@@ -83,6 +83,7 @@
     slave->config = NULL;
     slave->requested_state = EC_SLAVE_STATE_PREOP;
     slave->current_state = EC_SLAVE_STATE_UNKNOWN;
+    slave->last_al_error = 0;
     slave->error_flag = 0;
     slave->force_config = 0;
     slave->reboot = 0;
diff -r 0dc2082f5b98 master/slave.h
--- a/master/slave.h	Tue Mar 10 16:45:19 2015 +1300
+++ b/master/slave.h	Fri Mar 13 13:26:31 2015 +1300
@@ -209,6 +209,7 @@
     ec_slave_config_t *config; /**< Current configuration. */
     ec_slave_state_t requested_state; /**< Requested application state. */
     ec_slave_state_t current_state; /**< Current application state. */
+    uint16_t last_al_error; /**< Last AL state error code */
     unsigned int error_flag; /**< Stop processing after an error. */
     unsigned int force_config; /**< Force (re-)configuration. */
     unsigned int reboot; /**< Request reboot */
