Improved the callback mechanism.
This commit is contained in:
parent
9e937eb4fc
commit
a3c32e8b67
4
NEWS
4
NEWS
|
|
@ -12,6 +12,10 @@ Changes since 1.4.0:
|
|||
library is licensed under LGPLv2.
|
||||
* Added distributed clocks support.
|
||||
* Added VoE mailbox protocol support.
|
||||
* Improved the callback mechanism. ecrt_master_callbacks() now takes two
|
||||
callback functions for sending and receiving datagrams.
|
||||
ecrt_master_send_ext() is used to execute the sending of non-application
|
||||
datagrams.
|
||||
* Separated datagram initialization from filling the payload with zeros.
|
||||
Introduced new method ec_datagram_zero() for that.
|
||||
* Added phy_read and phy_write commands to ethercat tool.
|
||||
|
|
|
|||
3
TODO
3
TODO
|
|
@ -24,8 +24,6 @@ Version 1.5.0:
|
|||
* Remove byte-swapping functions from user space.
|
||||
* EoE:
|
||||
- Only execute one EoE handler per cycle.
|
||||
- Replace locking callbacks.
|
||||
- Allow EoE with userspace application.
|
||||
* Implement 'ethercat foe_read --output-file ...'.
|
||||
* Fix unloading problem of ec_e100 driver.
|
||||
* Use ec_datagram_zero() where possible.
|
||||
|
|
@ -41,7 +39,6 @@ Version 1.5.0:
|
|||
* Remove ecrt_domain_state()?
|
||||
* Check force_config flag before error.
|
||||
* Remove allow_scanning flag.
|
||||
* Implement ecrt_master_slave() in kernel space.
|
||||
* Check for ioctl() interface version.
|
||||
* Improve application-triggered SDO transfers by moving the state machine into
|
||||
the SDO handlers.
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@
|
|||
// EtherCAT
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_master_state_t master_state = {};
|
||||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
static ec_domain_state_t domain1_state = {};
|
||||
|
|
@ -125,9 +124,9 @@ void check_domain1_state(void)
|
|||
{
|
||||
ec_domain_state_t ds;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_domain_state(domain1, &ds);
|
||||
spin_unlock(&master_lock);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (ds.working_counter != domain1_state.working_counter)
|
||||
printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
|
||||
|
|
@ -143,9 +142,9 @@ void check_master_state(void)
|
|||
{
|
||||
ec_master_state_t ms;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_state(master, &ms);
|
||||
spin_unlock(&master_lock);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (ms.slaves_responding != master_state.slaves_responding)
|
||||
printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
|
||||
|
|
@ -239,21 +238,26 @@ void run(long data)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int request_lock(void *data)
|
||||
void send_callback(ec_master_t *master)
|
||||
{
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle > t_critical) return -1;
|
||||
|
||||
// allow access
|
||||
rt_sem_wait(&master_sem);
|
||||
return 0;
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void release_lock(void *data)
|
||||
void receive_callback(ec_master_t *master)
|
||||
{
|
||||
rt_sem_signal(&master_sem);
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -277,7 +281,7 @@ int __init init_mod(void)
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
// EtherCAT
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_master_state_t master_state = {};
|
||||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
struct semaphore master_sem;
|
||||
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
static ec_domain_state_t domain1_state = {};
|
||||
|
|
@ -192,9 +192,9 @@ void check_domain1_state(void)
|
|||
{
|
||||
ec_domain_state_t ds;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_domain_state(domain1, &ds);
|
||||
spin_unlock(&master_lock);
|
||||
up(&master_sem);
|
||||
|
||||
if (ds.working_counter != domain1_state.working_counter)
|
||||
printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
|
||||
|
|
@ -210,9 +210,9 @@ void check_master_state(void)
|
|||
{
|
||||
ec_master_state_t ms;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_master_state(master, &ms);
|
||||
spin_unlock(&master_lock);
|
||||
up(&master_sem);
|
||||
|
||||
if (ms.slaves_responding != master_state.slaves_responding)
|
||||
printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
|
||||
|
|
@ -230,9 +230,9 @@ void check_slave_config_states(void)
|
|||
{
|
||||
ec_slave_config_state_t s;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_slave_config_state(sc_ana_in, &s);
|
||||
spin_unlock(&master_lock);
|
||||
up(&master_sem);
|
||||
|
||||
if (s.al_state != sc_ana_in_state.al_state)
|
||||
printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
|
||||
|
|
@ -300,10 +300,10 @@ void read_voe(void)
|
|||
void cyclic_task(unsigned long data)
|
||||
{
|
||||
// receive process data
|
||||
spin_lock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
ecrt_domain_process(domain1);
|
||||
spin_unlock(&master_lock);
|
||||
up(&master_sem);
|
||||
|
||||
// check process data state (optional)
|
||||
check_domain1_state();
|
||||
|
|
@ -336,10 +336,10 @@ void cyclic_task(unsigned long data)
|
|||
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
|
||||
|
||||
// send process data
|
||||
spin_lock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_domain_queue(domain1);
|
||||
ecrt_master_send(master);
|
||||
spin_unlock(&master_lock);
|
||||
up(&master_sem);
|
||||
|
||||
// restart timer
|
||||
timer.expires += HZ / FREQUENCY;
|
||||
|
|
@ -348,17 +348,20 @@ void cyclic_task(unsigned long data)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int request_lock(void *data)
|
||||
void send_callback(ec_master_t *master)
|
||||
{
|
||||
spin_lock(&master_lock);
|
||||
return 0; // access allowed
|
||||
down(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
up(&master_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void release_lock(void *data)
|
||||
void receive_callback(ec_master_t *master)
|
||||
{
|
||||
spin_unlock(&master_lock);
|
||||
down(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
up(&master_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -382,7 +385,8 @@ int __init init_mini_module(void)
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
init_MUTEX(&master_sem);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@
|
|||
// EtherCAT
|
||||
static ec_master_t *master = NULL;
|
||||
static ec_master_state_t master_state = {};
|
||||
spinlock_t master_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static ec_domain_t *domain1 = NULL;
|
||||
static ec_domain_state_t domain1_state = {};
|
||||
|
|
@ -146,9 +145,9 @@ void check_domain1_state(void)
|
|||
{
|
||||
ec_domain_state_t ds;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_domain_state(domain1, &ds);
|
||||
spin_unlock(&master_lock);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (ds.working_counter != domain1_state.working_counter)
|
||||
printk(KERN_INFO PFX "Domain1: WC %u.\n", ds.working_counter);
|
||||
|
|
@ -164,9 +163,9 @@ void check_master_state(void)
|
|||
{
|
||||
ec_master_state_t ms;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_state(master, &ms);
|
||||
spin_unlock(&master_lock);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (ms.slaves_responding != master_state.slaves_responding)
|
||||
printk(KERN_INFO PFX "%u slave(s).\n", ms.slaves_responding);
|
||||
|
|
@ -184,9 +183,9 @@ void check_slave_config_states(void)
|
|||
{
|
||||
ec_slave_config_state_t s;
|
||||
|
||||
spin_lock(&master_lock);
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_slave_config_state(sc_ana_in, &s);
|
||||
spin_unlock(&master_lock);
|
||||
rt_sem_signal(&master_sem);
|
||||
|
||||
if (s.al_state != sc_ana_in_state.al_state)
|
||||
printk(KERN_INFO PFX "AnaIn: State 0x%02X.\n", s.al_state);
|
||||
|
|
@ -244,21 +243,26 @@ void run(long data)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int request_lock(void *data)
|
||||
void send_callback(ec_master_t *master)
|
||||
{
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle > t_critical) return -1;
|
||||
|
||||
// allow access
|
||||
rt_sem_wait(&master_sem);
|
||||
return 0;
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_send_ext(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void release_lock(void *data)
|
||||
void receive_callback(ec_master_t *master)
|
||||
{
|
||||
rt_sem_signal(&master_sem);
|
||||
// too close to the next real time cycle: deny access...
|
||||
if (get_cycles() - t_last_cycle <= t_critical) {
|
||||
rt_sem_wait(&master_sem);
|
||||
ecrt_master_receive(master);
|
||||
rt_sem_signal(&master_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -277,7 +281,6 @@ int __init init_mod(void)
|
|||
|
||||
t_critical = cpu_khz * 1000 / FREQUENCY - cpu_khz * INHIBIT_TIME / 1000;
|
||||
|
||||
|
||||
master = ecrt_request_master(0);
|
||||
if (IS_ERR(master)) {
|
||||
ret = PTR_ERR(master);
|
||||
|
|
@ -285,7 +288,7 @@ int __init init_mod(void)
|
|||
goto out_return;
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, request_lock, release_lock, NULL);
|
||||
ecrt_master_callbacks(master, send_callback, receive_callback);
|
||||
|
||||
printk(KERN_INFO PFX "Registering domain...\n");
|
||||
if (!(domain1 = ecrt_master_create_domain(master))) {
|
||||
|
|
|
|||
|
|
@ -42,24 +42,27 @@
|
|||
* Changes in version 1.5:
|
||||
*
|
||||
* - Added the distributed clocks feature and the respective method
|
||||
* ecrt_slave_config_dc() to configure a slave for cyclic
|
||||
* operation, and ecrt_master_application_time(),
|
||||
* ecrt_master_sync_reference_clock() and ecrt_master_sync_slave_clocks()
|
||||
* for offset and drift compensation. The EC_TIMEVAL2NANO() macro can be
|
||||
* used for epoch time conversion.
|
||||
* ecrt_slave_config_dc() to configure a slave for cyclic operation, and
|
||||
* ecrt_master_application_time(), ecrt_master_sync_reference_clock() and
|
||||
* ecrt_master_sync_slave_clocks() for offset and drift compensation. The
|
||||
* EC_TIMEVAL2NANO() macro can be used for epoch time conversion.
|
||||
* - Improved the callback mechanism. ecrt_master_callbacks() now takes two
|
||||
* callback functions for sending and receiving datagrams.
|
||||
* ecrt_master_send_ext() is used to execute the sending of non-application
|
||||
* datagrams.
|
||||
* - Added ecrt_open_master() and ecrt_master_reserve() separation for
|
||||
* userspace.
|
||||
* - Added ecrt_master() userspace interface, to get information about a
|
||||
* master.
|
||||
* - Added ecrt_master_slave() to get information about a certain slave.
|
||||
* - Added ecrt_slave_sdo_upload() and ecrt_slave_sdo_download() methods to
|
||||
* let an application transfer SDOs before activating the master.
|
||||
* - Changed the meaning of the negative return values of
|
||||
* ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
|
||||
* - Imlemented the Vendor-specific over EtherCAT mailbox protocol. See
|
||||
* ecrt_slave_config_create_voe_handler().
|
||||
* - Renamed ec_sdo_request_state_t to ec_request_state_t, because it is also
|
||||
* used by VoE handlers.
|
||||
* - Added ecrt_master_slave() to get information about a certain slave.
|
||||
* - Added ecrt_slave_sdo_upload() and ecrt_slave_sdo_download() methods to
|
||||
* let an application transfer SDOs before activating the master.
|
||||
* - Removed 'const' from argument of ecrt_sdo_request_state(), because the
|
||||
* userspace library has to modify object internals.
|
||||
* - Added 64-bit data access macros.
|
||||
|
|
@ -442,21 +445,23 @@ int ecrt_master_reserve(
|
|||
|
||||
/** Sets the locking callbacks.
|
||||
*
|
||||
* For concurrent master access, the application has to provide a locking
|
||||
* mechanism (see section FIXME in the docs). The method takes two function
|
||||
* pointers and a data value as its parameters. The arbitrary \a cb_data value
|
||||
* will be passed as argument on every callback. Asynchronous master access
|
||||
* (like EoE processing) is only possible if the callbacks have been set.
|
||||
* For concurrent master access, i. e. if other instances than the application
|
||||
* want to send and receive datagrams on the bus, the application has to
|
||||
* provide a callback mechanism. This method takes two function pointers as
|
||||
* its parameters. Asynchronous master access (like EoE processing) is only
|
||||
* possible if the callbacks have been set.
|
||||
*
|
||||
* The request_cb function must return zero, to allow another instance
|
||||
* (an EoE process for example) to access the master. Non-zero means,
|
||||
* that access is currently forbidden.
|
||||
* The task of the send callback (\a request_cb) is to decide, if the bus is
|
||||
* currently accessible. In this case, it can call the ecrt_master_send_ext()
|
||||
* method.
|
||||
*
|
||||
* The task of the receive callback (\a receive_cb) is to decide, if a call to
|
||||
* ecrt_master_receive() is allowed and to execute it respectively.
|
||||
*/
|
||||
void ecrt_master_callbacks(
|
||||
ec_master_t *master, /**< EtherCAT master */
|
||||
int (*request_cb)(void *), /**< Lock request function. */
|
||||
void (*release_cb)(void *), /**< Lock release function. */
|
||||
void *cb_data /**< Arbitrary user data. */
|
||||
void (*send_cb)(ec_master_t *), /**< Datagram sending callback. */
|
||||
void (*receive_cb)(ec_master_t *) /**< Receive callback. */
|
||||
);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
@ -591,6 +596,15 @@ void ecrt_master_receive(
|
|||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Sends non-application datagrams.
|
||||
*
|
||||
* This method has to be called in the send callback function passed via
|
||||
* ecrt_master_callbacks() to allow the sending of non-application datagrams.
|
||||
*/
|
||||
void ecrt_master_send_ext(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
);
|
||||
|
||||
/** Reads the current master state.
|
||||
*
|
||||
* Stores the master state information in the given \a state structure.
|
||||
|
|
|
|||
|
|
@ -1621,6 +1621,9 @@ int ec_cdev_ioctl_activate(
|
|||
}
|
||||
}
|
||||
|
||||
ecrt_master_callbacks(master, ec_master_internal_send_cb,
|
||||
ec_master_internal_receive_cb);
|
||||
|
||||
ret = ecrt_master_activate(master);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ void ec_eoe_run(ec_eoe_t *eoe /**< EoE handler */)
|
|||
void ec_eoe_queue(ec_eoe_t *eoe /**< EoE handler */)
|
||||
{
|
||||
if (eoe->queue_datagram) {
|
||||
ec_master_queue_datagram(eoe->slave->master, &eoe->datagram);
|
||||
ec_master_queue_datagram_ext(eoe->slave->master, &eoe->datagram);
|
||||
eoe->queue_datagram = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
122
master/master.c
122
master/master.c
|
|
@ -146,6 +146,9 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
INIT_LIST_HEAD(&master->datagram_queue);
|
||||
master->datagram_index = 0;
|
||||
|
||||
INIT_LIST_HEAD(&master->ext_datagram_queue);
|
||||
init_MUTEX(&master->ext_queue_sem);
|
||||
|
||||
INIT_LIST_HEAD(&master->domains);
|
||||
|
||||
master->debug_level = debug_level;
|
||||
|
|
@ -163,9 +166,10 @@ int ec_master_init(ec_master_t *master, /**< EtherCAT master */
|
|||
#endif
|
||||
|
||||
init_MUTEX(&master->io_sem);
|
||||
master->request_cb = NULL;
|
||||
master->release_cb = NULL;
|
||||
master->cb_data = NULL;
|
||||
master->send_cb = NULL;
|
||||
master->receive_cb = NULL;
|
||||
master->app_send_cb = NULL;
|
||||
master->app_receive_cb = NULL;
|
||||
|
||||
INIT_LIST_HEAD(&master->sii_requests);
|
||||
init_waitqueue_head(&master->sii_queue);
|
||||
|
|
@ -375,22 +379,27 @@ void ec_master_clear_domains(ec_master_t *master)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Internal locking callback.
|
||||
/** Internal sending callback.
|
||||
*/
|
||||
int ec_master_request_cb(void *data /**< callback data */)
|
||||
void ec_master_internal_send_cb(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = (ec_master_t *) data;
|
||||
down(&master->io_sem);
|
||||
return 0;
|
||||
ecrt_master_send_ext(master);
|
||||
up(&master->io_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Internal unlocking callback.
|
||||
/** Internal receiving callback.
|
||||
*/
|
||||
void ec_master_release_cb(void *data /**< callback data */)
|
||||
void ec_master_internal_receive_cb(
|
||||
ec_master_t *master /**< EtherCAT master. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = (ec_master_t *) data;
|
||||
down(&master->io_sem);
|
||||
ecrt_master_receive(master);
|
||||
up(&master->io_sem);
|
||||
}
|
||||
|
||||
|
|
@ -462,9 +471,8 @@ int ec_master_enter_idle_phase(
|
|||
if (master->debug_level)
|
||||
EC_DBG("ORPHANED -> IDLE.\n");
|
||||
|
||||
master->request_cb = ec_master_request_cb;
|
||||
master->release_cb = ec_master_release_cb;
|
||||
master->cb_data = master;
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
|
||||
master->phase = EC_IDLE;
|
||||
ret = ec_master_thread_start(master, ec_master_idle_thread,
|
||||
|
|
@ -564,9 +572,8 @@ int ec_master_enter_operation_phase(ec_master_t *master /**< EtherCAT master */)
|
|||
#endif
|
||||
|
||||
master->phase = EC_OPERATION;
|
||||
master->ext_request_cb = NULL;
|
||||
master->ext_release_cb = NULL;
|
||||
master->ext_cb_data = NULL;
|
||||
master->app_send_cb = NULL;
|
||||
master->app_receive_cb = NULL;
|
||||
return ret;
|
||||
|
||||
out_allow:
|
||||
|
|
@ -597,9 +604,8 @@ void ec_master_leave_operation_phase(ec_master_t *master
|
|||
#endif
|
||||
ec_master_thread_stop(master);
|
||||
|
||||
master->request_cb = ec_master_request_cb;
|
||||
master->release_cb = ec_master_release_cb;
|
||||
master->cb_data = master;
|
||||
master->send_cb = ec_master_internal_send_cb;
|
||||
master->receive_cb = ec_master_internal_receive_cb;
|
||||
|
||||
down(&master->master_sem);
|
||||
ec_master_clear_domains(master);
|
||||
|
|
@ -646,9 +652,10 @@ void ec_master_leave_operation_phase(ec_master_t *master
|
|||
|
||||
/** Places a datagram in the datagram queue.
|
||||
*/
|
||||
void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
void ec_master_queue_datagram(
|
||||
ec_master_t *master, /**< EtherCAT master */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
ec_datagram_t *queued_datagram;
|
||||
|
||||
|
|
@ -669,6 +676,20 @@ void ec_master_queue_datagram(ec_master_t *master, /**< EtherCAT master */
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Places a datagram in the non-application datagram queue.
|
||||
*/
|
||||
void ec_master_queue_datagram_ext(
|
||||
ec_master_t *master, /**< EtherCAT master */
|
||||
ec_datagram_t *datagram /**< datagram */
|
||||
)
|
||||
{
|
||||
down(&master->ext_queue_sem);
|
||||
list_add_tail(&datagram->queue, &master->ext_datagram_queue);
|
||||
up(&master->ext_queue_sem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sends the datagrams in the queue.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
|
|
@ -1048,8 +1069,8 @@ void ec_master_eoe_start(ec_master_t *master /**< EtherCAT master */)
|
|||
if (list_empty(&master->eoe_handlers))
|
||||
return;
|
||||
|
||||
if (!master->request_cb || !master->release_cb) {
|
||||
EC_WARN("No EoE processing because of missing locking callbacks!\n");
|
||||
if (!master->send_cb || !master->receive_cb) {
|
||||
EC_WARN("No EoE processing because of missing callbacks!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1109,11 +1130,7 @@ static int ec_master_eoe_thread(void *priv_data)
|
|||
goto schedule;
|
||||
|
||||
// receive datagrams
|
||||
if (master->request_cb(master->cb_data))
|
||||
goto schedule;
|
||||
|
||||
ecrt_master_receive(master);
|
||||
master->release_cb(master->cb_data);
|
||||
master->receive_cb(master);
|
||||
|
||||
// actual EoE processing
|
||||
sth_to_send = 0;
|
||||
|
|
@ -1128,15 +1145,13 @@ static int ec_master_eoe_thread(void *priv_data)
|
|||
}
|
||||
|
||||
if (sth_to_send) {
|
||||
// send datagrams
|
||||
if (master->request_cb(master->cb_data)) {
|
||||
goto schedule;
|
||||
}
|
||||
list_for_each_entry(eoe, &master->eoe_handlers, list) {
|
||||
ec_eoe_queue(eoe);
|
||||
}
|
||||
ecrt_master_send(master);
|
||||
master->release_cb(master->cb_data);
|
||||
// (try to) send datagrams
|
||||
down(&master->ext_queue_sem);
|
||||
master->send_cb(master);
|
||||
up(&master->ext_queue_sem);
|
||||
}
|
||||
|
||||
schedule:
|
||||
|
|
@ -1641,9 +1656,9 @@ int ecrt_master_activate(ec_master_t *master)
|
|||
|
||||
master->injection_seq_fsm = 0;
|
||||
master->injection_seq_rt = 0;
|
||||
master->request_cb = master->ext_request_cb;
|
||||
master->release_cb = master->ext_release_cb;
|
||||
master->cb_data = master->ext_cb_data;
|
||||
|
||||
master->send_cb = master->app_send_cb;
|
||||
master->receive_cb = master->app_receive_cb;
|
||||
|
||||
ret = ec_master_thread_start(master, ec_master_operation_thread,
|
||||
"EtherCAT-OP");
|
||||
|
|
@ -1735,6 +1750,21 @@ void ecrt_master_receive(ec_master_t *master)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_send_ext(ec_master_t *master)
|
||||
{
|
||||
ec_datagram_t *datagram, *next;
|
||||
|
||||
list_for_each_entry_safe(datagram, next, &master->ext_datagram_queue,
|
||||
queue) {
|
||||
list_del(&datagram->queue);
|
||||
ec_master_queue_datagram(master, datagram);
|
||||
}
|
||||
|
||||
ecrt_master_send(master);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Same as ecrt_master_slave_config(), but with ERR_PTR() return value.
|
||||
*/
|
||||
ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *master,
|
||||
|
|
@ -1805,17 +1835,16 @@ ec_slave_config_t *ecrt_master_slave_config(ec_master_t *master,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_master_callbacks(ec_master_t *master, int (*request_cb)(void *),
|
||||
void (*release_cb)(void *), void *cb_data)
|
||||
void ecrt_master_callbacks(ec_master_t *master,
|
||||
void (*send_cb)(ec_master_t *), void (*receive_cb)(ec_master_t *))
|
||||
{
|
||||
if (master->debug_level)
|
||||
EC_DBG("ecrt_master_callbacks(master = 0x%x, request_cb = 0x%x, "
|
||||
" release_cb = 0x%x, cb_data = 0x%x)\n", (u32) master,
|
||||
(u32) request_cb, (u32) release_cb, (u32) cb_data);
|
||||
EC_DBG("ecrt_master_callbacks(master = 0x%x, send_cb = 0x%x, "
|
||||
" receive_cb = 0x%x)\n", (u32) master, (u32) send_cb,
|
||||
(u32) receive_cb);
|
||||
|
||||
master->ext_request_cb = request_cb;
|
||||
master->ext_release_cb = release_cb;
|
||||
master->ext_cb_data = cb_data;
|
||||
master->app_send_cb = send_cb;
|
||||
master->app_receive_cb = receive_cb;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1862,6 +1891,7 @@ void ecrt_master_sync_slave_clocks(ec_master_t *master)
|
|||
EXPORT_SYMBOL(ecrt_master_create_domain);
|
||||
EXPORT_SYMBOL(ecrt_master_activate);
|
||||
EXPORT_SYMBOL(ecrt_master_send);
|
||||
EXPORT_SYMBOL(ecrt_master_send_ext);
|
||||
EXPORT_SYMBOL(ecrt_master_receive);
|
||||
EXPORT_SYMBOL(ecrt_master_callbacks);
|
||||
EXPORT_SYMBOL(ecrt_master_slave_config);
|
||||
|
|
|
|||
|
|
@ -145,6 +145,11 @@ struct ec_master {
|
|||
struct list_head datagram_queue; /**< Datagram queue. */
|
||||
uint8_t datagram_index; /**< Current datagram index. */
|
||||
|
||||
struct list_head ext_datagram_queue; /**< Queue for non-application
|
||||
datagrams. */
|
||||
struct semaphore ext_queue_sem; /**< Semaphore protecting the \a
|
||||
ext_datagram_queue. */
|
||||
|
||||
struct list_head domains; /**< List of domains. */
|
||||
|
||||
unsigned int debug_level; /**< Master debug level. */
|
||||
|
|
@ -160,12 +165,13 @@ struct ec_master {
|
|||
#endif
|
||||
|
||||
struct semaphore io_sem; /**< Semaphore used in \a IDLE phase. */
|
||||
int (*request_cb)(void *); /**< Lock request callback. */
|
||||
void (*release_cb)(void *); /**< Lock release callback. */
|
||||
void *cb_data; /**< Data parameter of locking callbacks. */
|
||||
int (*ext_request_cb)(void *); /**< External lock request callback. */
|
||||
void (*ext_release_cb)(void *); /**< External lock release callback. */
|
||||
void *ext_cb_data; /**< Data parameter of external locking callbacks. */
|
||||
|
||||
void (*send_cb)(ec_master_t *); /**< Current send datagrams callback. */
|
||||
void (*receive_cb)(ec_master_t *); /**< Current receive datagrams callback. */
|
||||
void (*app_send_cb)(ec_master_t *); /**< Application's send datagrams
|
||||
callback. */
|
||||
void (*app_receive_cb)(ec_master_t *); /**< Application's receive datagrams
|
||||
callback. */
|
||||
|
||||
struct list_head sii_requests; /**< SII write requests. */
|
||||
wait_queue_head_t sii_queue; /**< Wait queue for SII
|
||||
|
|
@ -208,6 +214,7 @@ void ec_master_eoe_stop(ec_master_t *);
|
|||
// datagram IO
|
||||
void ec_master_receive_datagrams(ec_master_t *, const uint8_t *, size_t);
|
||||
void ec_master_queue_datagram(ec_master_t *, ec_datagram_t *);
|
||||
void ec_master_queue_datagram_ext(ec_master_t *, ec_datagram_t *);
|
||||
|
||||
// misc.
|
||||
void ec_master_attach_slave_configs(ec_master_t *);
|
||||
|
|
@ -240,6 +247,9 @@ ec_slave_config_t *ecrt_master_slave_config_err(ec_master_t *, uint16_t,
|
|||
|
||||
void ec_master_calc_dc(ec_master_t *);
|
||||
|
||||
void ec_master_internal_send_cb(ec_master_t *);
|
||||
void ec_master_internal_receive_cb(ec_master_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue