Improved master state machine.

This commit is contained in:
Florian Pose 2008-04-25 14:07:38 +00:00
parent 0b9015848b
commit ff5dd7fe1c
3 changed files with 246 additions and 253 deletions

12
TODO
View File

@ -20,10 +20,11 @@ Version 1.4.0:
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 @@ Version 1.4.0:
* 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 @@ Future issues:
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 @@ Smaller issues:
* 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 <state>_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:

View File

@ -6,62 +6,64 @@ digraph master {
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"]
}

View File

@ -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 @@ void ec_fsm_master_state_error(ec_fsm_master_t *);
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_init(ec_fsm_master_t *fsm, /**< master state machine */
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_clear(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 */)
/** 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 @@ int ec_fsm_master_exec(ec_fsm_master_t *fsm /**< master state machine */)
/**
* \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 @@ int ec_fsm_master_running(
/**
* \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 @@ void ec_fsm_master_state_start(ec_fsm_master_t *fsm)
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_state_broadcast(ec_fsm_master_t *fsm /**< master state machin
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;
fsm->state = ec_fsm_master_state_read_state;
}
}
/*****************************************************************************/
/**
* Check for pending SII write requests and process one.
/** 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 @@ int ec_fsm_master_action_process_sii(
/*****************************************************************************/
/**
* 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,79 +424,17 @@ int ec_fsm_master_action_process_sdo(
/*****************************************************************************/
/**
* Check for slaves that are not configured and configure them.
/** Master action: IDLE.
*
* Does secondary work.
*/
int ec_fsm_master_action_configure(
ec_fsm_master_t *fsm /**< master state machine */
void ec_fsm_master_action_idle(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
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))
return;
@ -538,40 +475,118 @@ void ec_fsm_master_action_process_states(ec_fsm_master_t *fsm
/*****************************************************************************/
/**
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;
fsm->state = ec_fsm_master_state_read_state;
return;
}
// all slave states read
ec_fsm_master_action_process_states(fsm);
// all slaves processed
ec_fsm_master_action_idle(fsm);
}
/*****************************************************************************/
/**
Master state: READ STATES.
Fetches the AL- and online state of a slave.
*/
/** 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;
void ec_fsm_master_state_read_states(ec_fsm_master_t *fsm /**< master state machine */)
// 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 @@ void ec_fsm_master_state_read_states(ec_fsm_master_t *fsm /**< master state mach
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 @@ void ec_fsm_master_state_read_states(ec_fsm_master_t *fsm /**< master state mach
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);
// 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 */)
/** 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);
ec_fsm_master_action_configure(fsm);
}
/*****************************************************************************/
/**
* Master state: CLEAR ADDRESSES.
/** 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 @@ void ec_fsm_master_state_clear_addresses(
// 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 @@ void ec_fsm_master_state_scan_slaves(
/*****************************************************************************/
/**
Master state: CONFIGURE SLAVES.
Starts configuring a slave.
*/
void ec_fsm_master_state_configure_slave(ec_fsm_master_t *fsm
/**< master state machine */
)
/** Master state: CONFIGURE SLAVE.
*
* 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
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;
fsm->idle = 1;
ec_fsm_master_action_next_slave_state(fsm);
}
/*****************************************************************************/
/**
Master state: WRITE SII.
*/
/** 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 @@ void ec_fsm_master_state_write_sii(
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_state_sdo_dictionary(
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_state_sdo_request(ec_fsm_master_t *fsm /**< master state mach
/*****************************************************************************/
/**
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 @@ void ec_fsm_master_state_error(
/*****************************************************************************/
/**
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;
}
/*****************************************************************************/