# HG changeset patch # User Florian Pose # Date 1209132458 0 # Node ID 570ae1c644656bba57b13f51c469b3af50531506 # Parent f95e3e33c0cf9c072f7b4032a28ccc5b38cc332c Improved master state machine. diff -r f95e3e33c0cf -r 570ae1c64465 TODO --- a/TODO Fri Apr 25 12:45:44 2008 +0000 +++ b/TODO Fri Apr 25 14:07:38 2008 +0000 @@ -20,10 +20,11 @@ portability. * Remove ecdb.h and let lsec output PDO information 'cut-and-pastable' for applications. +* Scanning of Sdo dictionary / writing EEPROM in OPERATION state. +* Remove the end state of the master state machine. * SDO write access in sysfs. * Update documentation. * Supply new ec_master_state_t. -* Scanning of Sdo dictionary / writing EEPROM in OPERATION state. * Adapt remaining examples. * READMEs for examples. * Separate Pdo and Pdo entry classes. @@ -31,12 +32,11 @@ * Wait for bus scanning, even when link is not up at ecrt_request_master(). * Implement ecrt_slave_config_state(). * Add something like lsec -n to show numeric vendor IDs. -* Remove the end state of the master state machine. -* Check the position of the acknowledge state. * Remove the xmldev files. * Separate CoE debugging. * Make ecrt_master_slave_config() return no error when slave is not present or invalid. +* Evaluate EEPROM contents after writing. Future issues: @@ -45,7 +45,6 @@ kernel threads to user space daemon with a TCP interface replacing the cdev). * Mailbox gateway. -* Slave-to-slave communication. * Redundancy with 2 network adapters. * Interface/buffers for asynchronous domain IO. @@ -54,14 +53,9 @@ * Evaluate SII Size field (0x003E) to determine maximum SII memory size. * Unite fsm_pdo_mapping, fsm_pdo_config and fsm_coe_map. * Clear sync managers in INIT. -* Simplify FSMs with _enter() functions. * Read out CRC counters. * Optimize alignment of process data. -* Evaluate EEPROM contents after writing. * Configure slave ports to automatically open on link detection. -* Interrupt master state machines state scan for other jobs. -* Master state machine, slave configuration: Do not check every slave on - a cycle. * Only execute one EoE handler per EoE cycle. Less important issues: diff -r f95e3e33c0cf -r 570ae1c64465 documentation/graphs/fsm_master.dot --- a/documentation/graphs/fsm_master.dot Fri Apr 25 12:45:44 2008 +0000 +++ b/documentation/graphs/fsm_master.dot Fri Apr 25 14:07:38 2008 +0000 @@ -6,62 +6,64 @@ center=1 ratio=fill - action_process_sii [shape=point,label=""] - action_process_sdo [shape=point,label=""] - action_configure [shape=point,label=""] - action_next_slave_state [shape=point,label=""] - action_process_states [shape=point,label=""] - + start [fontname="Helvetica"] start -> broadcast [weight=10] - //broadcast -> error + broadcast [fontname="Helvetica"] broadcast -> end broadcast -> clear_addresses - broadcast -> read_states [weight=10] + broadcast -> read_state [weight=10] + action_process_sii [shape=point,label=""] action_process_sii -> write_sii + action_process_sdo [shape=point,label=""] action_process_sdo -> sdo_request - action_configure -> configure_slave + action_idle [shape=point,label=""] + action_idle -> action_process_sdo + action_idle -> sdo_dictionary + action_idle -> action_process_sii + action_idle -> end - action_process_states -> action_configure - action_process_states -> action_process_sdo - action_process_states -> sdo_dictionary - action_process_states -> action_process_sii - action_process_states -> end + action_next_slave_state [shape=point,label=""] + action_next_slave_state -> read_state + action_next_slave_state -> action_idle [weight=10] + + action_configure [shape=point,label=""] + action_configure -> configure_slave [weight=10] + action_configure -> action_next_slave_state - action_next_slave_state -> read_states - action_next_slave_state -> action_process_states + action_acknowledge [shape=point,label=""] + action_acknowledge -> acknowledge [weight=10] + action_acknowledge -> action_configure + action_acknowledge -> action_next_slave_state - //read_states -> error - read_states -> action_next_slave_state - read_states -> acknowledge + read_state [fontname="Helvetica"] + read_state -> action_acknowledge [weight=10] - //acknowledge -> error - acknowledge -> action_next_slave_state + acknowledge [fontname="Helvetica"] + acknowledge -> action_configure [weight=10] - //clear_addresses -> error - clear_addresses -> scan_slaves + clear_addresses [fontname="Helvetica"] + clear_addresses -> scan_slave [weight=10] - scan_slaves -> scan_slaves - scan_slaves -> end + scan_slave [fontname="Helvetica"] + scan_slave -> end - configure_slave -> action_configure - configure_slave -> end + configure_slave [fontname="Helvetica"] + configure_slave -> action_next_slave_state [weight=10] - //write_sii -> error + write_sii [fontname="Helvetica"] write_sii -> action_process_sii write_sii -> end - //sdo_dictionary -> error + sdo_dictionary [fontname="Helvetica"] sdo_dictionary -> end - //sdo_request -> error + sdo_request [fontname="Helvetica"] sdo_request -> action_process_sdo sdo_request -> end - //error -> start - - //end -> start + end [fontname="Helvetica"] } diff -r f95e3e33c0cf -r 570ae1c64465 master/fsm_master.c --- a/master/fsm_master.c Fri Apr 25 12:45:44 2008 +0000 +++ b/master/fsm_master.c Fri Apr 25 14:07:38 2008 +0000 @@ -31,10 +31,9 @@ * *****************************************************************************/ -/** - \file - EtherCAT finite state machines. -*/ +/** \file + * EtherCAT master state machine. + */ /*****************************************************************************/ @@ -52,11 +51,11 @@ 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_states(ec_fsm_master_t *); +void ec_fsm_master_state_read_state(ec_fsm_master_t *); 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 *); -void ec_fsm_master_state_scan_slaves(ec_fsm_master_t *); +void ec_fsm_master_state_scan_slave(ec_fsm_master_t *); void ec_fsm_master_state_write_sii(ec_fsm_master_t *); void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *); void ec_fsm_master_state_sdo_request(ec_fsm_master_t *); @@ -65,13 +64,12 @@ /*****************************************************************************/ -/** - Constructor. -*/ - -void ec_fsm_master_init(ec_fsm_master_t *fsm, /**< master state machine */ - ec_master_t *master, /**< EtherCAT master */ - ec_datagram_t *datagram /**< datagram object to use */ +/** Constructor. + */ +void ec_fsm_master_init( + ec_fsm_master_t *fsm, /**< Master state machine. */ + ec_master_t *master, /**< EtherCAT master. */ + ec_datagram_t *datagram /**< Datagram object to use. */ ) { fsm->master = master; @@ -94,11 +92,11 @@ /*****************************************************************************/ -/** - Destructor. -*/ - -void ec_fsm_master_clear(ec_fsm_master_t *fsm /**< master state machine */) +/** Destructor. + */ +void ec_fsm_master_clear( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { // clear sub-state machines ec_fsm_slave_config_clear(&fsm->fsm_slave_config); @@ -111,14 +109,16 @@ /*****************************************************************************/ -/** - Executes the current state of the state machine. - If the state machine's datagram is not sent or received yet, the execution - of the state machine is delayed to the next cycle. - \return false, if state machine has terminated -*/ - -int ec_fsm_master_exec(ec_fsm_master_t *fsm /**< master state machine */) +/** Executes the current state of the state machine. + * + * If the state machine's datagram is not sent or received yet, the execution + * of the state machine is delayed to the next cycle. + * + * \return false, if state machine has terminated + */ +int ec_fsm_master_exec( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { if (fsm->datagram->state == EC_DATAGRAM_SENT || fsm->datagram->state == EC_DATAGRAM_QUEUED) { @@ -135,9 +135,8 @@ /** * \return false, if state machine has terminated */ - int ec_fsm_master_running( - const ec_fsm_master_t *fsm /**< master state machine */ + const ec_fsm_master_t *fsm /**< Master state machine. */ ) { return fsm->state != ec_fsm_master_state_end @@ -149,24 +148,24 @@ /** * \return true, if the state machine is in an idle phase */ - int ec_fsm_master_idle( - const ec_fsm_master_t *fsm /**< master state machine */ + const ec_fsm_master_t *fsm /**< Master state machine. */ ) { return fsm->idle; } /****************************************************************************** - * master state machine + * Master state machine *****************************************************************************/ -/** - Master state: START. - Starts with getting slave count and slave states. -*/ - -void ec_fsm_master_state_start(ec_fsm_master_t *fsm) +/** Master state: START. + * + * Starts with getting slave count and slave states. + */ +void ec_fsm_master_state_start( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { fsm->idle = 1; ec_datagram_brd(fsm->datagram, 0x0130, 2); @@ -175,12 +174,13 @@ /*****************************************************************************/ -/** - Master state: BROADCAST. - Processes the broadcast read slave count and slaves states. -*/ - -void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machine */) +/** Master state: BROADCAST. + * + * Processes the broadcast read slave count and slaves states. + */ +void ec_fsm_master_state_broadcast( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_datagram_t *datagram = fsm->datagram; unsigned int i; @@ -276,23 +276,23 @@ if (list_empty(&master->slaves)) { fsm->state = ec_fsm_master_state_end; } else { - // fetch state from each slave + // fetch state from first slave fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); - ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0130, 2); + ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, + 0x0130, 2); fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_read_states; - } -} - -/*****************************************************************************/ - -/** - * Check for pending SII write requests and process one. + fsm->state = ec_fsm_master_state_read_state; + } +} + +/*****************************************************************************/ + +/** Check for pending SII write requests and process one. + * * \return non-zero, if an SII write request is processed. */ - int ec_fsm_master_action_process_sii( - ec_fsm_master_t *fsm /**< master state machine */ + ec_fsm_master_t *fsm /**< Master state machine. */ ) { ec_master_t *master = fsm->master; @@ -330,13 +330,12 @@ /*****************************************************************************/ -/** - * Check for pending Sdo requests and process one. +/** Check for pending Sdo requests and process one. + * * \return non-zero, if an Sdo request is processed. */ - int ec_fsm_master_action_process_sdo( - ec_fsm_master_t *fsm /**< master state machine */ + ec_fsm_master_t *fsm /**< Master state machine. */ ) { ec_master_t *master = fsm->master; @@ -425,78 +424,16 @@ /*****************************************************************************/ -/** - * Check for slaves that are not configured and configure them. - */ - -int ec_fsm_master_action_configure( - ec_fsm_master_t *fsm /**< master state machine */ - ) -{ +/** Master action: IDLE. + * + * Does secondary work. + */ +void ec_fsm_master_action_idle( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; ec_slave_t *slave; - ec_master_t *master = fsm->master; - char old_state[EC_STATE_STRING_SIZE], new_state[EC_STATE_STRING_SIZE]; - - // check if any slaves are not in the state, they're supposed to be - // FIXME do not check all slaves in every cycle... - list_for_each_entry(slave, &master->slaves, list) { - if (slave->error_flag - || slave->requested_state == EC_SLAVE_STATE_UNKNOWN - || (slave->current_state == slave->requested_state - && slave->self_configured)) continue; - - if (master->debug_level) { - ec_state_string(slave->current_state, old_state); - if (slave->current_state != slave->requested_state) { - ec_state_string(slave->requested_state, new_state); - EC_DBG("Changing state of slave %i (%s -> %s).\n", - slave->ring_position, old_state, new_state); - } - else if (!slave->self_configured) { - EC_DBG("Reconfiguring slave %i (%s).\n", - slave->ring_position, old_state); - } - } - - fsm->idle = 0; - fsm->slave = slave; - fsm->state = ec_fsm_master_state_configure_slave; - ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave); - ec_fsm_slave_config_exec(&fsm->fsm_slave_config); // execute immediately - return 1; - } - - master->config_busy = 0; - wake_up_interruptible(&master->config_queue); - return 0; -} - -/*****************************************************************************/ - -/** - Master action: PROC_STATES. - Processes the slave states. -*/ - -void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm - /**< master state machine */ - ) -{ - ec_master_t *master = fsm->master; - ec_slave_t *slave; - - // Start slave configuration, if it is allowed. - down(&master->config_sem); - if (!master->allow_config) { - up(&master->config_sem); - } else { - master->config_busy = 1; - up(&master->config_sem); - - // check for pending slave configurations - if (ec_fsm_master_action_configure(fsm)) - return; - } // Check for pending Sdo requests if (ec_fsm_master_action_process_sdo(fsm)) @@ -538,40 +475,118 @@ /*****************************************************************************/ -/** - Master action: Get state of next slave. -*/ - -void ec_fsm_master_action_next_slave_state(ec_fsm_master_t *fsm - /**< master state machine */) +/** Master action: Get state of next slave. + */ +void ec_fsm_master_action_next_slave_state( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_master_t *master = fsm->master; ec_slave_t *slave = fsm->slave; // is there another slave to query? if (slave->list.next != &master->slaves) { - // process next slave + // fetch state from next slave fsm->idle = 1; fsm->slave = list_entry(slave->list.next, ec_slave_t, list); ec_datagram_fprd(fsm->datagram, fsm->slave->station_address, 0x0130, 2); fsm->retries = EC_FSM_RETRIES; - fsm->state = ec_fsm_master_state_read_states; - return; - } - - // all slave states read - ec_fsm_master_action_process_states(fsm); -} - -/*****************************************************************************/ - -/** - Master state: READ STATES. - Fetches the AL- and online state of a slave. -*/ - -void ec_fsm_master_state_read_states(ec_fsm_master_t *fsm /**< master state machine */) + fsm->state = ec_fsm_master_state_read_state; + return; + } + + // all slaves processed + ec_fsm_master_action_idle(fsm); +} + +/*****************************************************************************/ + +/** Master action: Configure. + */ +void ec_fsm_master_action_configure( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; + ec_slave_t *slave = fsm->slave; + + // Does the slave have to be configured? + if (!slave->error_flag + && (slave->current_state != slave->requested_state + || !slave->self_configured)) { + // Start slave configuration, if it is allowed. + down(&master->config_sem); + if (!master->allow_config) { + up(&master->config_sem); + } else { + master->config_busy = 1; + up(&master->config_sem); + + if (master->debug_level) { + char old_state[EC_STATE_STRING_SIZE]; + ec_state_string(slave->current_state, old_state); + if (slave->current_state != slave->requested_state) { + char new_state[EC_STATE_STRING_SIZE]; + ec_state_string(slave->requested_state, new_state); + EC_DBG("Changing state of slave %u (%s -> %s).\n", + slave->ring_position, old_state, new_state); + } else if (!slave->self_configured) { + EC_DBG("Reconfiguring slave %u (%s).\n", + slave->ring_position, old_state); + } + } + + fsm->idle = 0; + fsm->state = ec_fsm_master_state_configure_slave; + ec_fsm_slave_config_start(&fsm->fsm_slave_config, slave); + fsm->state(fsm); // execute immediately + return; + } + } + + // slave has error flag set; process next one + ec_fsm_master_action_next_slave_state(fsm); +} + +/*****************************************************************************/ + +/** Master action: Acknowledge. + */ +void ec_fsm_master_action_acknowledge( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (!slave->error_flag) { + // Check, if new slave state has to be acknowledged + if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) { + fsm->idle = 0; + fsm->state = ec_fsm_master_state_acknowledge; + ec_fsm_change_ack(&fsm->fsm_change, slave); + fsm->state(fsm); // execute immediately + return; + } + + // No acknowlegde necessary; check for configuration + ec_fsm_master_action_configure(fsm); + return; + } + + // slave has error flag set; process next one + ec_fsm_master_action_next_slave_state(fsm); +} + +/*****************************************************************************/ + +/** Master state: READ STATE. + * + * Fetches the AL state of a slave. + */ +void ec_fsm_master_state_read_state( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_slave_t *slave = fsm->slave; ec_datagram_t *datagram = fsm->datagram; @@ -580,7 +595,7 @@ return; if (datagram->state != EC_DATAGRAM_RECEIVED) { - EC_ERR("Failed to receive AL state datagram for slave %i" + EC_ERR("Failed to receive AL state datagram for slave %u" " (datagram state %i)\n", slave->ring_position, datagram->state); fsm->state = ec_fsm_master_state_error; @@ -600,52 +615,39 @@ return; } - // a single slave responded - ec_slave_set_state(slave, EC_READ_U8(datagram->data)); // set app state first - - // check, if new slave state has to be acknowledged - if (slave->current_state & EC_SLAVE_STATE_ACK_ERR && !slave->error_flag) { - fsm->idle = 0; - fsm->state = ec_fsm_master_state_acknowledge; - ec_fsm_change_ack(&fsm->fsm_change, slave); - ec_fsm_change_exec(&fsm->fsm_change); - return; - } - - ec_fsm_master_action_next_slave_state(fsm); -} - -/*****************************************************************************/ - -/** - Master state: ACKNOWLEDGE -*/ - -void ec_fsm_master_state_acknowledge(ec_fsm_master_t *fsm /**< master state machine */) + // A single slave responded + ec_slave_set_state(slave, EC_READ_U8(datagram->data)); + ec_fsm_master_action_acknowledge(fsm); +} + +/*****************************************************************************/ + +/** Master state: ACKNOWLEDGE. + */ +void ec_fsm_master_state_acknowledge( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_slave_t *slave = fsm->slave; - if (ec_fsm_change_exec(&fsm->fsm_change)) return; + if (ec_fsm_change_exec(&fsm->fsm_change)) + return; if (!ec_fsm_change_success(&fsm->fsm_change)) { fsm->slave->error_flag = 1; - EC_ERR("Failed to acknowledge state change on slave %i.\n", + EC_ERR("Failed to acknowledge state change on slave %u.\n", slave->ring_position); - fsm->state = ec_fsm_master_state_error; - return; - } - - ec_fsm_master_action_next_slave_state(fsm); -} - -/*****************************************************************************/ - -/** - * Master state: CLEAR ADDRESSES. - */ - + } + + ec_fsm_master_action_configure(fsm); +} + +/*****************************************************************************/ + +/** Master state: CLEAR ADDRESSES. + */ void ec_fsm_master_state_clear_addresses( - ec_fsm_master_t *fsm /**< master state machine */ + ec_fsm_master_t *fsm /**< Master state machine. */ ) { ec_master_t *master = fsm->master; @@ -672,26 +674,25 @@ // begin scanning of slaves fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); - fsm->state = ec_fsm_master_state_scan_slaves; + fsm->state = ec_fsm_master_state_scan_slave; ec_fsm_slave_scan_start(&fsm->fsm_slave_scan, fsm->slave); ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan); // execute immediately } /*****************************************************************************/ -/** - * Master state: SCAN SLAVES. +/** Master state: SCAN SLAVE. + * * Executes the sub-statemachine for the scanning of a slave. */ - -void ec_fsm_master_state_scan_slaves( - ec_fsm_master_t *fsm /**< master state machine */ +void ec_fsm_master_state_scan_slave( + ec_fsm_master_t *fsm /**< Master state machine. */ ) { ec_master_t *master = fsm->master; ec_slave_t *slave = fsm->slave; - if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) // execute slave state machine + if (ec_fsm_slave_scan_exec(&fsm->fsm_slave_scan)) return; #ifdef EC_EOE @@ -738,37 +739,38 @@ /*****************************************************************************/ -/** - Master state: CONFIGURE SLAVES. - Starts configuring a slave. -*/ - -void ec_fsm_master_state_configure_slave(ec_fsm_master_t *fsm - /**< master state machine */ - ) -{ - if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config)) // execute slave's state machine - return; +/** Master state: CONFIGURE SLAVE. + * + * Starts configuring a slave. + */ +void ec_fsm_master_state_configure_slave( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) +{ + ec_master_t *master = fsm->master; + + if (ec_fsm_slave_config_exec(&fsm->fsm_slave_config)) + return; + + // configuration finished + master->config_busy = 0; + wake_up_interruptible(&master->config_queue); if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) { // TODO: mark slave_config as failed. } - // configure next slave, if necessary - if (ec_fsm_master_action_configure(fsm)) - return; - - fsm->state = ec_fsm_master_state_end; -} - -/*****************************************************************************/ - -/** - Master state: WRITE SII. -*/ - + fsm->idle = 1; + ec_fsm_master_action_next_slave_state(fsm); +} + +/*****************************************************************************/ + +/** Master state: WRITE SII. + */ void ec_fsm_master_state_write_sii( - ec_fsm_master_t *fsm /**< master state machine */) + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_master_t *master = fsm->master; ec_sii_write_request_t *request = fsm->sii_request; @@ -814,12 +816,10 @@ /*****************************************************************************/ -/** - Master state: SdoDICT. -*/ - +/** Master state: SDO DICTIONARY. + */ void ec_fsm_master_state_sdo_dictionary( - ec_fsm_master_t *fsm /**< master state machine */ + ec_fsm_master_t *fsm /**< Master state machine. */ ) { ec_slave_t *slave = fsm->slave; @@ -846,11 +846,11 @@ /*****************************************************************************/ -/** - Master state: SDO REQUEST. -*/ - -void ec_fsm_master_state_sdo_request(ec_fsm_master_t *fsm /**< master state machine */) +/** Master state: SDO REQUEST. + */ +void ec_fsm_master_state_sdo_request( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { ec_master_t *master = fsm->master; ec_sdo_request_t *request = fsm->sdo_request; @@ -883,12 +883,10 @@ /*****************************************************************************/ -/** - State: ERROR. -*/ - +/** State: ERROR. + */ void ec_fsm_master_state_error( - ec_fsm_master_t *fsm /**< master state machine */ + ec_fsm_master_t *fsm /**< Master state machine. */ ) { fsm->state = ec_fsm_master_state_start; @@ -896,14 +894,13 @@ /*****************************************************************************/ -/** - State: END. -*/ - -void ec_fsm_master_state_end(ec_fsm_master_t *fsm /**< master state machine */) +/** State: END. + */ +void ec_fsm_master_state_end( + ec_fsm_master_t *fsm /**< Master state machine. */ + ) { fsm->state = ec_fsm_master_state_start; } /*****************************************************************************/ -