External domain memory.
This commit is contained in:
parent
69f702dc92
commit
7db358b508
1
TODO
1
TODO
|
|
@ -10,7 +10,6 @@ Version 1.4.0:
|
|||
|
||||
* Realtime interface changes:
|
||||
- SDO access.
|
||||
- External memory for domains.
|
||||
* Mailbox handler
|
||||
* Read PDO mapping via CoE during bus scan.
|
||||
* SDO write access in sysfs.
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
//#define KBUS
|
||||
#define PDOS
|
||||
#define MAPPING
|
||||
#define EXTERNAL_MEMORY
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -74,19 +75,34 @@ const ec_pdo_entry_info_t el3162_channel2[] = {
|
|||
{0x3102, 2, 16} // value
|
||||
};
|
||||
|
||||
const ec_pdo_info_t mapping[] = {
|
||||
const ec_pdo_info_t el3162_mapping[] = {
|
||||
{EC_DIR_INPUT, 0x1A00, 2, el3162_channel1},
|
||||
{EC_DIR_INPUT, 0x1A01, 2, el3162_channel2},
|
||||
};
|
||||
|
||||
const ec_pdo_entry_info_t el2004_channels[] = {
|
||||
{0x3001, 1, 1}, // Value 1
|
||||
{0x3001, 2, 1}, // Value 2
|
||||
{0x3001, 3, 1}, // Value 3
|
||||
{0x3001, 4, 1} // Value 4
|
||||
};
|
||||
|
||||
const ec_pdo_info_t el2004_mapping[] = {
|
||||
{EC_DIR_OUTPUT, 0x1600, 1, &el2004_channels[0]},
|
||||
{EC_DIR_OUTPUT, 0x1601, 1, &el2004_channels[1]},
|
||||
{EC_DIR_OUTPUT, 0x1602, 1, &el2004_channels[2]},
|
||||
{EC_DIR_OUTPUT, 0x1603, 1, &el2004_channels[3]},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PDOS
|
||||
static uint8_t off_ana_in;
|
||||
//static uint8_t off_ana_out;
|
||||
static uint8_t *pd; /**< Process data. */
|
||||
static unsigned int off_ana_in;
|
||||
static unsigned int off_dig_out;
|
||||
|
||||
const static ec_pdo_entry_reg_t domain1_regs[] = {
|
||||
{0, 1, Beckhoff_EL3162, 0x3101, 2, &off_ana_in},
|
||||
//{0, 2, Beckhoff_EL4102, 0x3001, 1, &off_ana_out},
|
||||
{0, 3, Beckhoff_EL2004, 0x3001, 1, &off_dig_out},
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
|
@ -105,8 +121,7 @@ void run(unsigned long data)
|
|||
spin_unlock(&master_lock);
|
||||
|
||||
// process data
|
||||
// k_pos = EC_READ_U32(r_ssi);
|
||||
//EC_WRITE_U8(r_dig_out, blink ? 0x0F : 0x00);
|
||||
EC_WRITE_U8(pd + off_dig_out, blink ? 0x0F : 0x00);
|
||||
|
||||
if (counter) {
|
||||
counter--;
|
||||
|
|
@ -176,6 +191,9 @@ int __init init_mini_module(void)
|
|||
#ifdef MAPPING
|
||||
ec_slave_config_t *sc;
|
||||
#endif
|
||||
#ifdef EXTERNAL_MEMORY
|
||||
unsigned int size;
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Starting...\n");
|
||||
|
||||
|
|
@ -199,7 +217,17 @@ int __init init_mini_module(void)
|
|||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (ecrt_slave_config_mapping(sc, 2, mapping)) {
|
||||
if (ecrt_slave_config_mapping(sc, 2, el3162_mapping)) {
|
||||
printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (!(sc = ecrt_master_slave_config(master, 0, 3, Beckhoff_EL2004))) {
|
||||
printk(KERN_ERR PFX "Failed to get slave configuration.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
||||
if (ecrt_slave_config_mapping(sc, 4, el2004_mapping)) {
|
||||
printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
|
|
@ -213,12 +241,32 @@ int __init init_mini_module(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef EXTERNAL_MEMORY
|
||||
if ((size = ecrt_domain_size(domain1))) {
|
||||
if (!(pd = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
|
||||
printk(KERN_ERR PFX "Failed to allocate %u bytes of process data"
|
||||
" memory!\n", size);
|
||||
goto out_release_master;
|
||||
}
|
||||
ecrt_domain_external_memory(domain1, pd);
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Activating master...\n");
|
||||
if (ecrt_master_activate(master)) {
|
||||
printk(KERN_ERR PFX "Failed to activate master!\n");
|
||||
#ifdef EXTERNAL_MEMORY
|
||||
goto out_free_process_data;
|
||||
#else
|
||||
goto out_release_master;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef EXTERNAL_MEMORY
|
||||
// Get internal process data for domain
|
||||
pd = ecrt_domain_data(domain1);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Starting cyclic sample thread.\n");
|
||||
init_timer(&timer);
|
||||
timer.function = run;
|
||||
|
|
@ -228,10 +276,14 @@ int __init init_mini_module(void)
|
|||
printk(KERN_INFO PFX "Started.\n");
|
||||
return 0;
|
||||
|
||||
out_release_master:
|
||||
#ifdef EXTERNAL_MEMORY
|
||||
out_free_process_data:
|
||||
kfree(pd);
|
||||
#endif
|
||||
out_release_master:
|
||||
printk(KERN_ERR PFX "Releasing master...\n");
|
||||
ecrt_release_master(master);
|
||||
out_return:
|
||||
out_return:
|
||||
printk(KERN_ERR PFX "Failed to load. Aborting.\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -243,6 +295,11 @@ void __exit cleanup_mini_module(void)
|
|||
printk(KERN_INFO PFX "Stopping...\n");
|
||||
|
||||
del_timer_sync(&timer);
|
||||
|
||||
#ifdef EXTERNAL_MEMORY
|
||||
kfree(pd);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Releasing master...\n");
|
||||
ecrt_release_master(master);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,13 +55,14 @@
|
|||
* ecrt_slave_config_state().
|
||||
* - Process data memory for a domain can now be allocated externally. This
|
||||
* offers the possibility to use a shared-memory-region. Therefore,
|
||||
* added the domain methods ecrt_domain_size() and ecrt_domain_memory().
|
||||
* added the domain methods ecrt_domain_size() and
|
||||
* ecrt_domain_external_memory().
|
||||
* - Replaced the process data pointers in the Pdo entry registration
|
||||
* functions with a process data offset, that is now returned by
|
||||
* ecrt_slave_config_reg_pdo_entry(). This was necessary for the external
|
||||
* domain memory. An additional advantage is, that the returned offset value
|
||||
* is directly usable. The domain's process data offset can be retrieved
|
||||
* with ecrt_domain_data().
|
||||
* is directly usable. If the domain's process data is allocated internally,
|
||||
* the start address can be retrieved with ecrt_domain_data().
|
||||
* - Replaced ecrt_slave_pdo_mapping/add/clear() with
|
||||
* ecrt_slave_config_mapping() that is now able to specify Pdo mapping and
|
||||
* Pdo configuration. Pdo entries mapped in this way can now immediately be
|
||||
|
|
@ -241,7 +242,7 @@ typedef struct {
|
|||
uint32_t product_code; /**< Slave product code. */
|
||||
uint16_t index; /**< Pdo entry index. */
|
||||
uint8_t subindex; /**< Pdo entry subindex. */
|
||||
uint8_t *offset; /**< Pointer to a variable to store the Pdo's
|
||||
unsigned int *offset; /**< Pointer to a variable to store the Pdo's
|
||||
offset in the process data. */
|
||||
} ec_pdo_entry_reg_t;
|
||||
|
||||
|
|
@ -503,21 +504,32 @@ size_t ecrt_domain_size(
|
|||
ec_domain_t *domain /**< Domain. */
|
||||
);
|
||||
|
||||
/** Provide memory to store the domain's process data.
|
||||
/** Provide external memory to store the domain's process data.
|
||||
*
|
||||
* Call this after all Pdo entries have been registered. Since interface
|
||||
* version 1.4, you'll have to provide an external memory for the domain
|
||||
* process data.
|
||||
* Call this after all Pdo entries have been registered and before activating
|
||||
* the master.
|
||||
*
|
||||
* The size of the allocated memory must be at least the return value of
|
||||
* ecrt_domain_size(), after all Pdo entries have been registered.
|
||||
* The size of the allocated memory must be at least ecrt_domain_size(), after
|
||||
* all Pdo entries have been registered.
|
||||
*/
|
||||
void ecrt_domain_memory(
|
||||
void ecrt_domain_external_memory(
|
||||
ec_domain_t *domain, /**< Domain. */
|
||||
uint8_t *memory /**< Address of the memory to store the process
|
||||
data in. */
|
||||
);
|
||||
|
||||
/** Returns the domain's process data.
|
||||
*
|
||||
* If external memory was provided with ecrt_domain_external_memory(), the
|
||||
* returned pointer will contain the address of that memory. Otherwise it will
|
||||
* point to the internally allocated memory.
|
||||
*
|
||||
* \return Pointer to the process data memory.
|
||||
*/
|
||||
uint8_t *ecrt_domain_data(
|
||||
ec_domain_t *domain /**< Domain. */
|
||||
);
|
||||
|
||||
/** Processes received datagrams.
|
||||
*
|
||||
* \todo doc
|
||||
|
|
|
|||
|
|
@ -63,20 +63,19 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Datagram constructor.
|
||||
*/
|
||||
|
||||
/** Constructor.
|
||||
*/
|
||||
void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
|
||||
{
|
||||
INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
|
||||
datagram->type = EC_DATAGRAM_NONE;
|
||||
memset(datagram->address, 0x00, EC_ADDR_LEN);
|
||||
datagram->data = NULL;
|
||||
datagram->data_origin = EC_ORIG_INTERNAL;
|
||||
datagram->mem_size = 0;
|
||||
datagram->data_size = 0;
|
||||
datagram->index = 0x00;
|
||||
datagram->working_counter = 0x00;
|
||||
datagram->working_counter = 0x0000;
|
||||
datagram->state = EC_DATAGRAM_INIT;
|
||||
datagram->cycles_sent = 0;
|
||||
datagram->jiffies_sent = 0;
|
||||
|
|
@ -84,33 +83,37 @@ void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
|
|||
datagram->jiffies_received = 0;
|
||||
datagram->skip_count = 0;
|
||||
datagram->stats_output_jiffies = 0;
|
||||
datagram->name[0] = 0x00;
|
||||
memset(datagram->name, 0x00, EC_DATAGRAM_NAME_SIZE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Datagram destructor.
|
||||
*/
|
||||
|
||||
/** Destructor.
|
||||
*/
|
||||
void ec_datagram_clear(ec_datagram_t *datagram /**< EtherCAT datagram */)
|
||||
{
|
||||
if (datagram->data) kfree(datagram->data);
|
||||
if (datagram->data_origin == EC_ORIG_INTERNAL && datagram->data)
|
||||
kfree(datagram->data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Allocates datagram data memory.
|
||||
If the allocated memory is already larger than requested, nothing ist done.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Allocates internal payload memory.
|
||||
*
|
||||
* If the allocated memory is already larger than requested, nothing ist done.
|
||||
*
|
||||
* \attention If external payload memory has been provided, no range checking
|
||||
* is done!
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_prealloc(ec_datagram_t *datagram, /**< EtherCAT datagram */
|
||||
size_t size /**< New size in bytes */
|
||||
)
|
||||
size_t size /**< New size in bytes */
|
||||
)
|
||||
{
|
||||
if (size <= datagram->mem_size) return 0;
|
||||
if (datagram->data_origin == EC_ORIG_EXTERNAL
|
||||
|| size <= datagram->mem_size)
|
||||
return 0;
|
||||
|
||||
if (datagram->data) {
|
||||
kfree(datagram->data);
|
||||
|
|
@ -129,12 +132,12 @@ int ec_datagram_prealloc(ec_datagram_t *datagram, /**< EtherCAT datagram */
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT NPRD datagram.
|
||||
Node-adressed physical read.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT NPRD datagram.
|
||||
*
|
||||
* Node-adressed physical read.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_nprd(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t node_address,
|
||||
|
|
@ -157,12 +160,12 @@ int ec_datagram_nprd(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT NPWR datagram.
|
||||
Node-adressed physical write.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT NPWR datagram.
|
||||
*
|
||||
* Node-adressed physical write.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_npwr(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t node_address,
|
||||
|
|
@ -185,12 +188,12 @@ int ec_datagram_npwr(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT APRD datagram.
|
||||
Autoincrement physical read.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT APRD datagram.
|
||||
*
|
||||
* Autoincrement physical read.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_aprd(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t ring_position,
|
||||
|
|
@ -210,12 +213,12 @@ int ec_datagram_aprd(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT APWR datagram.
|
||||
Autoincrement physical write.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT APWR datagram.
|
||||
*
|
||||
* Autoincrement physical write.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_apwr(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t ring_position,
|
||||
|
|
@ -235,12 +238,12 @@ int ec_datagram_apwr(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT BRD datagram.
|
||||
Broadcast read.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT BRD datagram.
|
||||
*
|
||||
* Broadcast read.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_brd(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t offset,
|
||||
|
|
@ -258,12 +261,12 @@ int ec_datagram_brd(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT BWR datagram.
|
||||
Broadcast write.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
/** Initializes an EtherCAT BWR datagram.
|
||||
*
|
||||
* Broadcast write.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_bwr(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint16_t offset,
|
||||
|
|
@ -281,20 +284,24 @@ int ec_datagram_bwr(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Initializes an EtherCAT LRW datagram.
|
||||
Logical read write.
|
||||
\return 0 in case of success, else < 0
|
||||
*/
|
||||
|
||||
int ec_datagram_lrw(ec_datagram_t *datagram,
|
||||
/**< EtherCAT datagram */
|
||||
uint32_t offset,
|
||||
/**< logical address */
|
||||
size_t data_size
|
||||
/**< number of bytes to read/write */
|
||||
)
|
||||
/** Initializes an EtherCAT LRW datagram.
|
||||
*
|
||||
* Logical read write.
|
||||
*
|
||||
* \attention It is assumed, that the external memory is at least \a data_size
|
||||
* bytes large.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_datagram_lrw(
|
||||
ec_datagram_t *datagram, /**< EtherCAT datagram */
|
||||
uint32_t offset, /**< Logical address. */
|
||||
size_t data_size, /**< Number of bytes to read/write. */
|
||||
uint8_t *external_memory /**< Pointer to the memory to use. */
|
||||
)
|
||||
{
|
||||
datagram->data = external_memory;
|
||||
datagram->data_origin = EC_ORIG_EXTERNAL;
|
||||
EC_FUNC_HEADER;
|
||||
datagram->type = EC_DATAGRAM_LRW;
|
||||
EC_WRITE_U32(datagram->address, offset);
|
||||
|
|
@ -303,11 +310,10 @@ int ec_datagram_lrw(ec_datagram_t *datagram,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Evaluates the working counter of a single-cast datagram.
|
||||
/** Evaluates the working counter of a single-cast datagram.
|
||||
*
|
||||
* Outputs an error message.
|
||||
*/
|
||||
|
||||
void ec_datagram_print_wc_error(
|
||||
const ec_datagram_t *datagram /**< EtherCAT datagram */
|
||||
)
|
||||
|
|
@ -323,10 +329,8 @@ void ec_datagram_print_wc_error(
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Outputs datagram statistics at most every second.
|
||||
/** Outputs datagram statistics at most every second.
|
||||
*/
|
||||
|
||||
void ec_datagram_output_stats(
|
||||
ec_datagram_t *datagram
|
||||
)
|
||||
|
|
|
|||
|
|
@ -54,66 +54,58 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT datagram type.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EC_DATAGRAM_NONE = 0x00, /**< Dummy */
|
||||
EC_DATAGRAM_APRD = 0x01, /**< Auto-increment physical read */
|
||||
EC_DATAGRAM_APWR = 0x02, /**< Auto-increment physical write */
|
||||
EC_DATAGRAM_NPRD = 0x04, /**< Node-addressed physical read */
|
||||
EC_DATAGRAM_NPWR = 0x05, /**< Node-addressed physical write */
|
||||
EC_DATAGRAM_BRD = 0x07, /**< Broadcast read */
|
||||
EC_DATAGRAM_BWR = 0x08, /**< Broadcast write */
|
||||
EC_DATAGRAM_LRW = 0x0C /**< Logical read/write */
|
||||
}
|
||||
ec_datagram_type_t;
|
||||
|
||||
/**
|
||||
EtherCAT datagram state.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EC_DATAGRAM_INIT, /**< new datagram */
|
||||
EC_DATAGRAM_QUEUED, /**< datagram queued for sending */
|
||||
EC_DATAGRAM_SENT, /**< datagram has been sent (still in the queue) */
|
||||
EC_DATAGRAM_RECEIVED, /**< datagram has been received (dequeued) */
|
||||
EC_DATAGRAM_TIMED_OUT, /**< datagram timed out (dequeued) */
|
||||
EC_DATAGRAM_ERROR /**< error while sending/receiving (dequeued) */
|
||||
}
|
||||
ec_datagram_state_t;
|
||||
/** EtherCAT datagram type.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_DATAGRAM_NONE = 0x00, /**< Dummy. */
|
||||
EC_DATAGRAM_APRD = 0x01, /**< Auto-increment physical read. */
|
||||
EC_DATAGRAM_APWR = 0x02, /**< Auto-increment physical write. */
|
||||
EC_DATAGRAM_NPRD = 0x04, /**< Node-addressed physical read. */
|
||||
EC_DATAGRAM_NPWR = 0x05, /**< Node-addressed physical write. */
|
||||
EC_DATAGRAM_BRD = 0x07, /**< Broadcast read. */
|
||||
EC_DATAGRAM_BWR = 0x08, /**< Broadcast write. */
|
||||
EC_DATAGRAM_LRW = 0x0C /**< Logical read/write. */
|
||||
} ec_datagram_type_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
EtherCAT datagram.
|
||||
*/
|
||||
/** EtherCAT datagram state.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_DATAGRAM_INIT, /**< Initial state of a new datagram. */
|
||||
EC_DATAGRAM_QUEUED, /**< Queued for sending. */
|
||||
EC_DATAGRAM_SENT, /**< Sent (still in the queue). */
|
||||
EC_DATAGRAM_RECEIVED, /**< Received (dequeued). */
|
||||
EC_DATAGRAM_TIMED_OUT, /**< Timed out (dequeued). */
|
||||
EC_DATAGRAM_ERROR /**< Error while sending/receiving (dequeued). */
|
||||
} ec_datagram_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list; /**< needed by domain datagram lists */
|
||||
struct list_head queue; /**< master datagram queue item */
|
||||
struct list_head sent; /**< master list item for sent datagrams */
|
||||
ec_datagram_type_t type; /**< datagram type (APRD, BWR, etc) */
|
||||
uint8_t address[EC_ADDR_LEN]; /**< recipient address */
|
||||
uint8_t *data; /**< datagram data */
|
||||
size_t mem_size; /**< datagram \a data memory size */
|
||||
size_t data_size; /**< size of the data in \a data */
|
||||
uint8_t index; /**< datagram index (set by master) */
|
||||
uint16_t working_counter; /**< working counter */
|
||||
ec_datagram_state_t state; /**< datagram state */
|
||||
cycles_t cycles_sent; /**< time, the datagram was sent */
|
||||
unsigned long jiffies_sent; /**< jiffies, when the datagram was sent */
|
||||
cycles_t cycles_received; /**< time, when the datagram was received */
|
||||
unsigned long jiffies_received; /**< jiffies the datagram was received */
|
||||
unsigned int skip_count; /**< number of requeues when not yet received */
|
||||
unsigned long stats_output_jiffies; /**< last statistics output */
|
||||
char name[EC_DATAGRAM_NAME_SIZE]; /**< description of the datagram */
|
||||
}
|
||||
ec_datagram_t;
|
||||
/*****************************************************************************/
|
||||
|
||||
/** EtherCAT datagram.
|
||||
*/
|
||||
typedef struct {
|
||||
struct list_head list; /**< Needed by domain datagram lists. */
|
||||
struct list_head queue; /**< Master datagram queue item. */
|
||||
struct list_head sent; /**< Master list item for sent datagrams. */
|
||||
ec_datagram_type_t type; /**< Datagram type (APRD, BWR, etc.). */
|
||||
uint8_t address[EC_ADDR_LEN]; /**< Recipient address. */
|
||||
uint8_t *data; /**< Datagram payload. */
|
||||
ec_origin_t data_origin; /**< Origin of the \a data memory. */
|
||||
size_t mem_size; /**< Datagram \a data memory size. */
|
||||
size_t data_size; /**< Size of the data in \a data. */
|
||||
uint8_t index; /**< Index (set by master). */
|
||||
uint16_t working_counter; /**< Working counter. */
|
||||
ec_datagram_state_t state; /**< State. */
|
||||
cycles_t cycles_sent; /**< Time, when the datagram was sent. */
|
||||
unsigned long jiffies_sent; /**< Jiffies, when the datagram was sent. */
|
||||
cycles_t cycles_received; /**< Time, when the datagram was received. */
|
||||
unsigned long jiffies_received; /**< Jiffies, when the datagram was
|
||||
received. */
|
||||
unsigned int skip_count; /**< Number of requeues when not yet received. */
|
||||
unsigned long stats_output_jiffies; /**< Last statistics output. */
|
||||
char name[EC_DATAGRAM_NAME_SIZE]; /**< Description of the datagram. */
|
||||
} ec_datagram_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -127,7 +119,7 @@ int ec_datagram_aprd(ec_datagram_t *, uint16_t, uint16_t, size_t);
|
|||
int ec_datagram_apwr(ec_datagram_t *, uint16_t, uint16_t, size_t);
|
||||
int ec_datagram_brd(ec_datagram_t *, uint16_t, size_t);
|
||||
int ec_datagram_bwr(ec_datagram_t *, uint16_t, size_t);
|
||||
int ec_datagram_lrw(ec_datagram_t *, uint32_t, size_t);
|
||||
int ec_datagram_lrw(ec_datagram_t *, uint32_t, size_t, uint8_t *);
|
||||
|
||||
void ec_datagram_print_wc_error(const ec_datagram_t *);
|
||||
void ec_datagram_output_stats(ec_datagram_t *datagram);
|
||||
|
|
|
|||
112
master/domain.c
112
master/domain.c
|
|
@ -49,6 +49,7 @@
|
|||
/*****************************************************************************/
|
||||
|
||||
void ec_domain_clear(struct kobject *);
|
||||
void ec_domain_clear_data(ec_domain_t *);
|
||||
ssize_t ec_show_domain_attribute(struct kobject *, struct attribute *, char *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -90,7 +91,9 @@ int ec_domain_init(
|
|||
domain->master = master;
|
||||
domain->index = index;
|
||||
domain->data_size = 0;
|
||||
domain->base_address = 0;
|
||||
domain->data = NULL;
|
||||
domain->data_origin = EC_ORIG_INTERNAL;
|
||||
domain->logical_base_address = 0L;
|
||||
domain->working_counter = 0xFFFFFFFF;
|
||||
domain->notify_jiffies = 0;
|
||||
domain->working_counter_changes = 0;
|
||||
|
|
@ -158,19 +161,36 @@ void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */)
|
|||
kfree(datagram);
|
||||
}
|
||||
|
||||
ec_domain_clear_data(domain);
|
||||
|
||||
kfree(domain);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Frees internally allocated memory.
|
||||
*/
|
||||
void ec_domain_clear_data(
|
||||
ec_domain_t *domain /**< EtherCAT domain. */
|
||||
)
|
||||
{
|
||||
if (domain->data_origin == EC_ORIG_INTERNAL && domain->data)
|
||||
kfree(domain->data);
|
||||
domain->data = NULL;
|
||||
domain->data_origin = EC_ORIG_INTERNAL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Allocates a domain datagram and appends it to the list.
|
||||
*
|
||||
* \return 0 in case of success, else < 0
|
||||
*/
|
||||
int ec_domain_add_datagram(
|
||||
ec_domain_t *domain, /**< EtherCAT domain. */
|
||||
uint32_t offset, /**< Logical offset. */
|
||||
size_t data_size /**< Size of the data. */
|
||||
uint32_t logical_offset, /**< Logical offset. */
|
||||
size_t data_size, /**< Size of the data. */
|
||||
uint8_t *data /**< Process data. */
|
||||
)
|
||||
{
|
||||
ec_datagram_t *datagram;
|
||||
|
|
@ -182,9 +202,9 @@ int ec_domain_add_datagram(
|
|||
|
||||
ec_datagram_init(datagram);
|
||||
snprintf(datagram->name, EC_DATAGRAM_NAME_SIZE,
|
||||
"domain%u-%u", domain->index, offset);
|
||||
"domain%u-%u", domain->index, logical_offset);
|
||||
|
||||
if (ec_datagram_lrw(datagram, offset, data_size)) {
|
||||
if (ec_datagram_lrw(datagram, logical_offset, data_size, data)) {
|
||||
kfree(datagram);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -200,6 +220,8 @@ int ec_domain_add_datagram(
|
|||
* This allocates the necessary datagrams and writes the correct logical
|
||||
* addresses to every configured FMMU.
|
||||
*
|
||||
* \todo Check for FMMUs that do not fit into any datagram.
|
||||
*
|
||||
* \retval 0 in case of success
|
||||
* \retval <0 on failure.
|
||||
*/
|
||||
|
|
@ -209,17 +231,26 @@ int ec_domain_finish(
|
|||
)
|
||||
{
|
||||
uint32_t datagram_offset;
|
||||
size_t datagram_data_size;
|
||||
size_t datagram_size;
|
||||
unsigned int datagram_count, i;
|
||||
ec_slave_config_t *sc;
|
||||
ec_fmmu_config_t *fmmu;
|
||||
|
||||
domain->base_address = base_address;
|
||||
domain->logical_base_address = base_address;
|
||||
|
||||
// Cycle through all domain FMMUS, add the logical base address and assign
|
||||
// as many PDO entries as possible to the datagrams.
|
||||
datagram_offset = base_address;
|
||||
datagram_data_size = 0;
|
||||
if (domain->data_size && domain->data_origin == EC_ORIG_INTERNAL) {
|
||||
if (!(domain->data =
|
||||
(uint8_t *) kmalloc(domain->data_size, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate %u bytes internal memory for"
|
||||
" domain %u!\n", domain->data_size, domain->index);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Cycle through all domain FMMUS, correct the logical base addresses and
|
||||
// set up the datagrams to carry the process data.
|
||||
datagram_offset = 0;
|
||||
datagram_size = 0;
|
||||
datagram_count = 0;
|
||||
list_for_each_entry(sc, &domain->master->configs, list) {
|
||||
for (i = 0; i < sc->used_fmmus; i++) {
|
||||
|
|
@ -227,28 +258,36 @@ int ec_domain_finish(
|
|||
if (fmmu->domain != domain)
|
||||
continue;
|
||||
|
||||
// Correct logical FMMU address
|
||||
fmmu->logical_start_address += base_address;
|
||||
if (datagram_data_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
|
||||
if (ec_domain_add_datagram(domain, datagram_offset,
|
||||
datagram_data_size)) return -1;
|
||||
datagram_offset += datagram_data_size;
|
||||
datagram_data_size = 0;
|
||||
|
||||
// If the current FMMU's data do not fit in the current datagram,
|
||||
// allocate a new one.
|
||||
if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
|
||||
if (ec_domain_add_datagram(domain,
|
||||
domain->logical_base_address + datagram_offset,
|
||||
datagram_size, domain->data + datagram_offset))
|
||||
return -1;
|
||||
datagram_offset += datagram_size;
|
||||
datagram_size = 0;
|
||||
datagram_count++;
|
||||
}
|
||||
datagram_data_size += fmmu->data_size;
|
||||
|
||||
datagram_size += fmmu->data_size;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate last datagram
|
||||
if (datagram_data_size) {
|
||||
if (ec_domain_add_datagram(domain, datagram_offset,
|
||||
datagram_data_size))
|
||||
// allocate last datagram, if data are left
|
||||
if (datagram_size) {
|
||||
if (ec_domain_add_datagram(domain,
|
||||
domain->logical_base_address + datagram_offset,
|
||||
datagram_size, domain->data + datagram_offset))
|
||||
return -1;
|
||||
datagram_count++;
|
||||
}
|
||||
|
||||
EC_INFO("Domain %u with logical offset %u contains %u bytes in %u"
|
||||
" datagram%s.\n", domain->index, domain->base_address,
|
||||
" datagram%s.\n", domain->index, domain->logical_base_address,
|
||||
domain->data_size, datagram_count, datagram_count == 1 ? "" : "s");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -302,6 +341,30 @@ int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
size_t ecrt_domain_size(ec_domain_t *domain)
|
||||
{
|
||||
return domain->data_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
|
||||
{
|
||||
ec_domain_clear_data(domain);
|
||||
|
||||
domain->data = mem;
|
||||
domain->data_origin = EC_ORIG_EXTERNAL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_domain_data(ec_domain_t *domain)
|
||||
{
|
||||
return domain->data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_domain_process(ec_domain_t *domain)
|
||||
{
|
||||
unsigned int working_counter_sum;
|
||||
|
|
@ -364,8 +427,9 @@ void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
|
|||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry_list);
|
||||
//EXPORT_SYMBOL(ecrt_domain_size);
|
||||
//EXPORT_SYMBOL(ecrt_domain_memory);
|
||||
EXPORT_SYMBOL(ecrt_domain_size);
|
||||
EXPORT_SYMBOL(ecrt_domain_external_memory);
|
||||
EXPORT_SYMBOL(ecrt_domain_data);
|
||||
EXPORT_SYMBOL(ecrt_domain_process);
|
||||
EXPORT_SYMBOL(ecrt_domain_queue);
|
||||
EXPORT_SYMBOL(ecrt_domain_state);
|
||||
|
|
|
|||
|
|
@ -60,11 +60,14 @@ struct ec_domain
|
|||
{
|
||||
struct kobject kobj; /**< kobject. */
|
||||
struct list_head list; /**< List item. */
|
||||
unsigned int index; /**< Index (just a number). */
|
||||
ec_master_t *master; /**< EtherCAT master owning the domain. */
|
||||
unsigned int index; /**< Index (just a number). */
|
||||
size_t data_size; /**< Size of the process data. */
|
||||
uint8_t *data; /**< Memory for the process data. */
|
||||
ec_origin_t data_origin; /**< Origin of the \a data memory. */
|
||||
struct list_head datagrams; /**< Datagrams for process data exchange. */
|
||||
uint32_t base_address; /**< Logical offset address of the process data. */
|
||||
uint32_t logical_base_address; /**< Logical offset address of the
|
||||
process data. */
|
||||
unsigned int working_counter; /**< Last working counter value. */
|
||||
unsigned int state; /**< Error state. */
|
||||
unsigned int working_counter_changes; /**< Working counter changes
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ int ec_mac_is_zero(const uint8_t *);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Code - Message pair.
|
||||
/** Code/Message pair.
|
||||
*
|
||||
* Some EtherCAT datagrams support reading a status code to display a certain
|
||||
* message. This type allows to map a code to a message string.
|
||||
|
|
@ -187,8 +187,7 @@ int ec_mac_is_zero(const uint8_t *);
|
|||
typedef struct {
|
||||
uint32_t code; /**< Code. */
|
||||
const char *message; /**< Message belonging to \a code. */
|
||||
}
|
||||
ec_code_msg_t;
|
||||
} ec_code_msg_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -204,6 +203,15 @@ ec_request_state_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Origin type.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_ORIG_INTERNAL, /**< Internal. */
|
||||
EC_ORIG_EXTERNAL /**< External. */
|
||||
} ec_origin_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
|
||||
typedef struct ec_sdo ec_sdo_t; /**< \see ec_sdo */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue