diff -r 7273aa7deb3d -r 017fa8fd9ac1 master/master.c --- a/master/master.c Mon Nov 23 14:22:48 2009 +0100 +++ b/master/master.c Thu Nov 26 15:33:48 2009 +0100 @@ -151,6 +151,8 @@ INIT_LIST_HEAD(&master->ext_datagram_queue); sema_init(&master->ext_queue_sem, 1); + INIT_LIST_HEAD(&master->sdo_datagram_queue); + INIT_LIST_HEAD(&master->domains); master->debug_level = debug_level; @@ -684,6 +686,39 @@ master->phase = EC_IDLE; } + +/*****************************************************************************/ + +/** Injects sdo datagrams that fit into the datagram queue + */ +void ec_master_inject_sdo_datagrams( + ec_master_t *master /**< EtherCAT master */ + ) +{ + ec_datagram_t *sdo_datagram, *n; + list_for_each_entry_safe(sdo_datagram, n, &master->sdo_datagram_queue, queue) { + list_del_init(&sdo_datagram->queue); + if (master->debug_level) + EC_DBG("queuing SDO datagram %08x\n",(unsigned int)sdo_datagram); + ec_master_queue_datagram(master, sdo_datagram); + } +} + +/*****************************************************************************/ + +/** Places a sdo datagram in the sdo datagram queue. + */ +void ec_master_queue_sdo_datagram( + ec_master_t *master, /**< EtherCAT master */ + ec_datagram_t *datagram /**< datagram */ + ) +{ + down(&master->io_sem); + list_add_tail(&datagram->queue, &master->sdo_datagram_queue); + datagram->state = EC_DATAGRAM_QUEUED; + up(&master->io_sem); +} + /*****************************************************************************/ /** Places a datagram in the datagram queue. @@ -695,6 +730,8 @@ { ec_datagram_t *queued_datagram; + if (datagram->state == EC_DATAGRAM_SENT) + return; // check, if the datagram is already queued list_for_each_entry(queued_datagram, &master->datagram_queue, queue) { if (queued_datagram == datagram) { @@ -1001,7 +1038,8 @@ static int ec_master_idle_thread(void *priv_data) { ec_master_t *master = (ec_master_t *) priv_data; - + ec_slave_t *slave = NULL; + int fsm_exec; if (master->debug_level) EC_DBG("Idle thread running.\n"); @@ -1013,22 +1051,27 @@ ecrt_master_receive(master); up(&master->io_sem); - if (master->fsm_datagram.state == EC_DATAGRAM_SENT) - goto schedule; - - // execute master state machine + fsm_exec = 0; + // execute master & slave state machines if (down_interruptible(&master->master_sem)) break; - ec_fsm_master_exec(&master->fsm); + fsm_exec = ec_fsm_master_exec(&master->fsm); + for (slave = master->slaves; + slave < master->slaves + master->slave_count; + slave++) { + ec_fsm_slave_exec(&slave->fsm); + } up(&master->master_sem); // queue and send down(&master->io_sem); - ec_master_queue_datagram(master, &master->fsm_datagram); + if (fsm_exec) { + ec_master_queue_datagram(master, &master->fsm_datagram); + } + ec_master_inject_sdo_datagrams(master); ecrt_master_send(master); up(&master->io_sem); - -schedule: + if (ec_fsm_master_idle(&master->fsm)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); @@ -1045,35 +1088,38 @@ /*****************************************************************************/ -/** Master kernel thread function for IDLE phase. +/** Master kernel thread function for OPERATION phase. */ static int ec_master_operation_thread(void *priv_data) { ec_master_t *master = (ec_master_t *) priv_data; - + ec_slave_t *slave = NULL; + int fsm_exec; if (master->debug_level) EC_DBG("Operation thread running.\n"); while (!kthread_should_stop()) { ec_datagram_output_stats(&master->fsm_datagram); - if (master->injection_seq_rt != master->injection_seq_fsm || - master->fsm_datagram.state == EC_DATAGRAM_SENT || - master->fsm_datagram.state == EC_DATAGRAM_QUEUED) - goto schedule; - - // output statistics - ec_master_output_stats(master); - - // execute master state machine - if (down_interruptible(&master->master_sem)) - break; - ec_fsm_master_exec(&master->fsm); - up(&master->master_sem); - - // inject datagram - master->injection_seq_fsm++; - -schedule: + if (master->injection_seq_rt == master->injection_seq_fsm) { + // output statistics + ec_master_output_stats(master); + + fsm_exec = 0; + // execute master & slave state machines + if (down_interruptible(&master->master_sem)) + break; + fsm_exec += ec_fsm_master_exec(&master->fsm); + for (slave = master->slaves; + slave < master->slaves + master->slave_count; + slave++) { + ec_fsm_slave_exec(&slave->fsm); + } + up(&master->master_sem); + + // inject datagrams (let the rt thread queue them, see ecrt_master_send) + if (fsm_exec) + master->injection_seq_fsm++; + } if (ec_fsm_master_idle(&master->fsm)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); @@ -1797,10 +1843,11 @@ ec_datagram_t *datagram, *n; if (master->injection_seq_rt != master->injection_seq_fsm) { - // inject datagram produced by master FSM + // inject datagrams produced by master & slave FSMs ec_master_queue_datagram(master, &master->fsm_datagram); master->injection_seq_rt = master->injection_seq_fsm; } + ec_master_inject_sdo_datagrams(master); if (unlikely(!master->main_device.link_state)) { // link is down, no datagram can be sent