Skip to content
Snippets Groups Projects
Commit c4f3890d authored by Florian Pose's avatar Florian Pose
Browse files

Added ecrt_slave_config_pdo() and ecrt_slave_config_pdo_entry().

parent c762a034
No related branches found
No related tags found
No related merge requests found
......@@ -17,7 +17,7 @@ Changes in version 1.4.0:
- Added ec_slave_config_state_t for the new method
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,
offers the possibility to use a shared-memory region. Therefore,
added the domain methods ecrt_domain_size() and
ecrt_domain_external_memory().
- Replaced the process data pointers in the Pdo entry registration
......@@ -27,10 +27,11 @@ Changes in version 1.4.0:
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
registered. The Pdo mapping and the configuration are described with the
new data types ec_pdo_info_t and ec_pdo_entry_info_t.
ecrt_slave_config_pdo() to add a Pdo to the mapping and
ecrt_slave_config_pdo_entry() to add a Pdo entry to a Pdo configuration.
ecrt_slave_config_mapping() is a convenience function for
both, that uses the new data types ec_pdo_info_t and ec_pdo_entry_info_t.
Mapped Pdo entries can now immediately be registered.
- Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
ecrt_master_state(), for consistency reasons.
......
......@@ -54,7 +54,7 @@
* - Added ec_slave_config_state_t for the new method
* 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,
* offers the possibility to use a shared-memory region. Therefore,
* added the domain methods ecrt_domain_size() and
* ecrt_domain_external_memory().
* - Replaced the process data pointers in the Pdo entry registration
......@@ -64,10 +64,11 @@
* 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
* registered. The Pdo mapping and the configuration are described with the
* new data types ec_pdo_info_t and ec_pdo_entry_info_t.
* ecrt_slave_config_pdo() to add a Pdo to the mapping and
* ecrt_slave_config_pdo_entry() to add a Pdo entry to a Pdo configuration.
* ecrt_slave_config_mapping() is a convenience function for
* both, that uses the new data types ec_pdo_info_t and ec_pdo_entry_info_t.
* Mapped Pdo entries can now immediately be registered.
* - Renamed ec_bus_status_t, ec_master_status_t to ec_bus_state_t and
* ec_master_state_t, respectively. Renamed ecrt_master_get_status() to
* ecrt_master_state(), for consistency reasons.
......@@ -370,7 +371,43 @@ void ecrt_master_state(
* Slave configuration methods
*****************************************************************************/
/** Add a Pdo to the slave's Pdo mapping for the given direction.
*
* The first call of this function for a given \a dir will clear the default
* mapping.
*
* \see ecrt_slave_config_mapping()
* \return zero on success, else non-zero
*/
int ecrt_slave_config_pdo(
ec_slave_config_t *sc, /**< Slave configuration. */
ec_direction_t dir, /**< Pdo direction (input/output). */
uint16_t index /**< Index of the Pdo to map. */
);
/** Add a Pdo entry to the given Pdo's configuration.
*
* The first call of this function for a given \a pdo_index will clear the
* default Pdo configuration.
*
* \see ecrt_slave_config_mapping()
* \return zero on success, else non-zero
*/
int ecrt_slave_config_pdo_entry(
ec_slave_config_t *sc, /**< Slave configuration. */
uint16_t pdo_index, /**< Index of the Pdo to configure. */
uint16_t entry_index, /**< Index of the Pdo entry to add to the Pdo's
configuration. */
uint8_t entry_subindex, /**< Subindex of the Pdo entry to add to the
Pdo's configuration. */
uint8_t entry_bit_length /**< Size of the Pdo entry in bit. */
);
/** Specify the Pdo mapping and (optionally) the Pdo configuration.
*
* This function is a convenience function for the ecrt_slave_config_pdo()
* and ecrt_slave_config_pdo_entry() functions, that are better suitable
* for automatic code generation.
*
* The following example shows, how to specify a complete Pdo mapping
* including the Pdo configuration. With this information, the master is able
......@@ -378,26 +415,29 @@ void ecrt_master_state(
* at configuration time:
*
* \code
* const ec_pdo_info_t complete_mapping[] = {
* {EC_DIR_INPUT, 0x1600, 2, { // channel 1
* {0x7000, 0, 16}, // value
* {0x7000, 1, 8}, // status
* }},
* {EC_DIR_INPUT, 0x1601, 2, { // channel 2
* {0x7001, 0, 16}, // value
* {0x7001, 1, 8}, // status
* }}
* const ec_pdo_entry_info_t el3162_channel1[] = {
* {0x3101, 1, 8}, // status
* {0x3101, 2, 16} // value
* };
*
* const ec_pdo_entry_info_t el3162_channel2[] = {
* {0x3102, 1, 8}, // status
* {0x3102, 2, 16} // value
* };
*
* const ec_pdo_info_t el3162_mapping[] = {
* {EC_DIR_INPUT, 0x1A00, 2, el3162_channel1},
* {EC_DIR_INPUT, 0x1A01, 2, el3162_channel2},
* };
*
* if (ecrt_slave_config_mapping(slave_config_ana_in, 2, complete_mapping)) {
* // error
* }
* if (ecrt_slave_config_mapping(sc, 2, el3162_mapping))
* return -1; // error
* \endcode
*
* The next example shows, how to configure only the Pdo mapping. The entries
* for each mapped Pdo are taken from the default Pdo configuration. Please
* note, that Pdo entry registration will fail, if no Pdo configuration is
* specified and the slave is offline.
* note, that Pdo entry registration will fail, if the Pdo configuration is
* left empty and the slave is offline.
*
* \code
* const ec_pdo_info_t pdo_mapping[] = {
......@@ -405,9 +445,8 @@ void ecrt_master_state(
* {EC_DIR_INPUT, 0x1601} // Channel 2
* };
*
* if (ecrt_slave_config_mapping(slave_config_ana_in, 2, pdo_mapping)) {
* // error
* }
* if (ecrt_slave_config_mapping(slave_config_ana_in, 2, pdo_mapping))
* return -1; // error
* \endcode
*
* \return zero on success, else non-zero
......@@ -418,15 +457,18 @@ int ecrt_slave_config_mapping(
const ec_pdo_info_t pdos[] /**< List with Pdo mapping. */
);
/** Registers a Pdo entry of the given slave configuration at a domain.
/** Registers a Pdo entry for process data exchange in a domain.
*
* Searches the mapping and the Pdo configurations for the given Pdo entry. If
* found, the curresponding sync manager/FMMU is added to the domain and the
* offset of the Pdo entry's data in the domain process data is returned.
* Searches the current mapping and Pdo configurations for the given Pdo
* entry. An error is raised, if the given entry is not mapped. Otherwise, the
* corresponding sync manager and FMMU configurations are provided for slave
* configuration and the respective sync manager's Pdos are appended to the
* given domain, if not already done. The offset of the requested Pdo entry's
* data inside the domain's process data is returned.
*
* \retval >=0 Offset of the Pdo entry's process data.
* \retval -1 Pdo entry not found.
* \retval -2 Failed to register Pdo entry.
* \retval >=0 Success: Offset of the Pdo entry's process data.
* \retval -1 Error: Pdo entry not found.
* \retval -2 Error: Failed to register Pdo entry.
*/
int ecrt_slave_config_reg_pdo_entry(
ec_slave_config_t *sc, /**< Slave configuration. */
......
......@@ -44,10 +44,6 @@
/*****************************************************************************/
void ec_pdo_clear_entries(ec_pdo_t *);
/*****************************************************************************/
/** Pdo constructor.
*/
void ec_pdo_init(
......@@ -57,6 +53,7 @@ void ec_pdo_init(
pdo->sync_index = -1; // not assigned
pdo->name = NULL;
INIT_LIST_HEAD(&pdo->entries);
pdo->default_config = 0;
}
/*****************************************************************************/
......@@ -70,6 +67,7 @@ int ec_pdo_init_copy(ec_pdo_t *pdo, const ec_pdo_t *other_pdo)
pdo->sync_index = other_pdo->sync_index;
pdo->name = NULL;
INIT_LIST_HEAD(&pdo->entries);
pdo->default_config = other_pdo->default_config;
if (ec_pdo_set_name(pdo, other_pdo->name))
goto out_return;
......@@ -89,7 +87,7 @@ out_return:
/** Pdo destructor.
*/
void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT Pdo */)
void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT Pdo. */)
{
if (pdo->name)
kfree(pdo->name);
......@@ -101,7 +99,7 @@ void ec_pdo_clear(ec_pdo_t *pdo /**< EtherCAT Pdo */)
/** Clear Pdo entry list.
*/
void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT Pdo */)
void ec_pdo_clear_entries(ec_pdo_t *pdo /**< EtherCAT Pdo. */)
{
ec_pdo_entry_t *entry, *next;
......@@ -142,6 +140,32 @@ int ec_pdo_set_name(
/*****************************************************************************/
/** Add a new Pdo entry to the configuration.
*/
ec_pdo_entry_t *ec_pdo_add_entry(
ec_pdo_t *pdo,
uint16_t index,
uint8_t subindex,
uint8_t bit_length
)
{
ec_pdo_entry_t *entry;
if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for Pdo entry.\n");
return NULL;
}
ec_pdo_entry_init(entry);
entry->index = index;
entry->subindex = subindex;
entry->bit_length = bit_length;
list_add_tail(&entry->list, &pdo->entries);
return entry;
}
/*****************************************************************************/
/** Copy Pdo entries from another Pdo.
*/
int ec_pdo_copy_entries(ec_pdo_t *pdo, const ec_pdo_t *other)
......
......@@ -58,6 +58,8 @@ typedef struct {
int8_t sync_index; /**< Assigned sync manager. */
char *name; /**< Pdo name. */
struct list_head entries; /**< List of Pdo entries. */
unsigned int default_config; /**< The entries contain the default Pdo
configuration. */
} ec_pdo_t;
/*****************************************************************************/
......@@ -77,7 +79,9 @@ typedef struct {
void ec_pdo_init(ec_pdo_t *);
int ec_pdo_init_copy(ec_pdo_t *, const ec_pdo_t *);
void ec_pdo_clear(ec_pdo_t *);
void ec_pdo_clear_entries(ec_pdo_t *);
int ec_pdo_set_name(ec_pdo_t *, const char *);
ec_pdo_entry_t *ec_pdo_add_entry(ec_pdo_t *, uint16_t, uint8_t, uint8_t);
int ec_pdo_copy_entries(ec_pdo_t *, const ec_pdo_t *);
int ec_pdo_equal_entries(const ec_pdo_t *, const ec_pdo_t *);
......
......@@ -115,7 +115,34 @@ uint16_t ec_pdo_mapping_total_size(
/*****************************************************************************/
/** Adds a Pdo to the mapping.
/** Add a new Pdo to the mapping.
*
* \retval >0 Pointer to new Pdo.
* \retval NULL No memory.
*/
ec_pdo_t *ec_pdo_mapping_add_pdo(
ec_pdo_mapping_t *pm, /**< Pdo mapping. */
uint16_t index, /**< Pdo index. */
ec_direction_t dir /**< Direction. */
)
{
ec_pdo_t *pdo;
if (!(pdo = (ec_pdo_t *) kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for Pdo.\n");
return NULL;
}
ec_pdo_init(pdo);
pdo->dir = dir;
pdo->index = index;
list_add_tail(&pdo->list, &pm->pdos);
return pdo;
}
/*****************************************************************************/
/** Add the copy of an existing Pdo to the mapping.
*
* \return 0 on success, else < 0
*/
......@@ -134,7 +161,7 @@ int ec_pdo_mapping_add_pdo_copy(
}
if (!(mapped_pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for Pdo mapping.\n");
EC_ERR("Failed to allocate Pdo memory.\n");
return -1;
}
......@@ -149,111 +176,6 @@ int ec_pdo_mapping_add_pdo_copy(
/*****************************************************************************/
/** Add a Pdo to the mapping.
*
* The first call of this method will clear the default mapping.
*
* \retval 0 Success.
* \retval -1 Error.
*/
int ec_pdo_mapping_add_pdo_info(
ec_pdo_mapping_t *pm, /**< Pdo mapping. */
const ec_pdo_info_t *pdo_info, /**< Pdo information. */
const ec_slave_config_t *config /**< Slave configuration, to load
default entries. */
)
{
unsigned int i;
ec_pdo_t *pdo;
ec_pdo_entry_t *entry;
const ec_pdo_entry_info_t *entry_info;
if (pm->default_mapping) {
pm->default_mapping = 0;
ec_pdo_mapping_clear_pdos(pm);
}
if (!(pdo = (ec_pdo_t *) kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for Pdo.\n");
goto out_return;
}
ec_pdo_init(pdo);
pdo->dir = pdo_info->dir;
pdo->index = pdo_info->index;
if (config->master->debug_level)
EC_INFO("Adding Pdo 0x%04X to mapping.\n", pdo->index);
if (pdo_info->n_entries && pdo_info->entries) { // configuration provided
if (config->master->debug_level)
EC_INFO(" Pdo configuration provided.\n");
for (i = 0; i < pdo_info->n_entries; i++) {
entry_info = &pdo_info->entries[i];
if (!(entry = kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for Pdo entry.\n");
goto out_free;
}
ec_pdo_entry_init(entry);
entry->index = entry_info->index;
entry->subindex = entry_info->subindex;
entry->bit_length = entry_info->bit_length;
list_add_tail(&entry->list, &pdo->entries);
}
} else { // use default Pdo configuration
if (config->master->debug_level)
EC_INFO(" Using default Pdo configuration.\n");
if (config->slave) {
ec_sync_t *sync;
ec_pdo_t *default_pdo;
if ((sync = ec_slave_get_pdo_sync(config->slave, pdo->dir))) {
list_for_each_entry(default_pdo, &sync->mapping.pdos, list) {
if (default_pdo->index != pdo->index)
continue;
if (config->master->debug_level)
EC_INFO(" Found Pdo name \"%s\".\n",
default_pdo->name);
// try to take Pdo name from mapped one
if (ec_pdo_set_name(pdo, default_pdo->name))
goto out_free;
// copy entries (= default Pdo configuration)
if (ec_pdo_copy_entries(pdo, default_pdo))
goto out_free;
if (config->master->debug_level) {
const ec_pdo_entry_t *entry;
list_for_each_entry(entry, &pdo->entries, list) {
EC_INFO(" Entry 0x%04X:%u.\n",
entry->index, entry->subindex);
}
}
}
} else {
EC_WARN("Slave %u does not provide a default Pdo"
" configuration!\n", config->slave->ring_position);
}
} else {
EC_WARN("Failed to load default Pdo configuration for %u:%u:"
" Slave not found.\n", config->alias, config->position);
}
}
list_add_tail(&pdo->list, &pm->pdos);
return 0;
out_free:
ec_pdo_clear(pdo);
kfree(pdo);
out_return:
return -1;
}
/*****************************************************************************/
/** Makes a deep copy of another Pdo mapping.
*
* \return 0 on success, else < 0
......@@ -318,6 +240,26 @@ int ec_pdo_mapping_equal(
/*****************************************************************************/
/** Finds a Pdo with the given index.
*/
ec_pdo_t *ec_pdo_mapping_find_pdo(
const ec_pdo_mapping_t *pm, /**< Pdo mapping. */
uint16_t index /**< Pdo index. */
)
{
ec_pdo_t *pdo;
list_for_each_entry(pdo, &pm->pdos, list) {
if (pdo->index != index)
continue;
return pdo;
}
return NULL;
}
/*****************************************************************************/
/** Finds a Pdo with the given index and returns a const pointer.
*/
const ec_pdo_t *ec_pdo_mapping_find_pdo_const(
......
......@@ -64,15 +64,16 @@ void ec_pdo_mapping_clear(ec_pdo_mapping_t *);
void ec_pdo_mapping_clear_pdos(ec_pdo_mapping_t *);
ec_pdo_t *ec_pdo_mapping_add_pdo(ec_pdo_mapping_t *, uint16_t,
ec_direction_t);
int ec_pdo_mapping_add_pdo_copy(ec_pdo_mapping_t *, const ec_pdo_t *);
int ec_pdo_mapping_add_pdo_info(ec_pdo_mapping_t *, const ec_pdo_info_t *,
const ec_slave_config_t *);
int ec_pdo_mapping_copy(ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
uint16_t ec_pdo_mapping_total_size(const ec_pdo_mapping_t *);
int ec_pdo_mapping_equal(const ec_pdo_mapping_t *, const ec_pdo_mapping_t *);
ec_pdo_t *ec_pdo_mapping_find_pdo(const ec_pdo_mapping_t *, uint16_t);
const ec_pdo_t *ec_pdo_mapping_find_pdo_const(const ec_pdo_mapping_t *,
uint16_t);
......
......@@ -431,6 +431,58 @@ void ec_slave_config_load_default_mapping(ec_slave_config_t *sc)
if (!(sync = ec_slave_get_pdo_sync(sc->slave, dir)))
continue;
ec_pdo_mapping_copy(map, &sync->mapping);
map->default_mapping = 1;
}
}
/*****************************************************************************/
/** Loads the default configuration for a Pdo from the slave object.
*/
void ec_slave_config_load_default_pdo_config(
const ec_slave_config_t *sc,
ec_pdo_t *pdo
)
{
const ec_sync_t *sync;
const ec_pdo_t *default_pdo;
pdo->default_config = 1;
if (!sc->slave) {
EC_WARN("Failed to load default Pdo configuration for %u:%u:"
" Slave not found.\n", sc->alias, sc->position);
return;
}
if (!(sync = ec_slave_get_pdo_sync(sc->slave, pdo->dir))) {
EC_WARN("Slave %u does not provide a default Pdo"
" configuration!\n", sc->slave->ring_position);
return;
}
list_for_each_entry(default_pdo, &sync->mapping.pdos, list) {
if (default_pdo->index != pdo->index)
continue;
if (sc->master->debug_level)
EC_DBG(" Found Pdo name \"%s\".\n",
default_pdo->name);
// try to take Pdo name from mapped one
ec_pdo_set_name(pdo, default_pdo->name);
// copy entries (= default Pdo configuration)
if (ec_pdo_copy_entries(pdo, default_pdo))
return;
if (sc->master->debug_level) {
const ec_pdo_entry_t *entry;
list_for_each_entry(entry, &pdo->entries, list) {
EC_DBG(" Entry 0x%04X:%u.\n",
entry->index, entry->subindex);
}
}
}
}
......@@ -438,16 +490,89 @@ void ec_slave_config_load_default_mapping(ec_slave_config_t *sc)
* Realtime interface
*****************************************************************************/
int ecrt_slave_config_pdo(ec_slave_config_t *sc, ec_direction_t dir,
uint16_t index)
{
ec_pdo_mapping_t *pm = &sc->mapping[dir];
ec_pdo_t *pdo;
if (pm->default_mapping) {
pm->default_mapping = 0;
ec_pdo_mapping_clear_pdos(pm);
}
if (!(pdo = ec_pdo_mapping_add_pdo(pm, index, dir)))
return -1;
ec_slave_config_load_default_pdo_config(sc, pdo);
return 0;
}
/*****************************************************************************/
int ecrt_slave_config_pdo_entry(ec_slave_config_t *sc, uint16_t pdo_index,
uint16_t entry_index, uint8_t entry_subindex,
uint8_t entry_bit_length)
{
ec_direction_t dir;
ec_pdo_t *pdo;
for (dir = EC_DIR_OUTPUT; dir <= EC_DIR_INPUT; dir++)
if ((pdo = ec_pdo_mapping_find_pdo(&sc->mapping[dir], pdo_index)))
break;
if (pdo->default_config) {
pdo->default_config = 0;
ec_pdo_clear_entries(pdo);
}
return ec_pdo_add_entry(pdo, entry_index, entry_subindex,
entry_bit_length) ? 0 : -1;
}
/*****************************************************************************/
int ecrt_slave_config_mapping(ec_slave_config_t *sc, unsigned int n_entries,
const ec_pdo_info_t pdo_infos[])
{
unsigned int i;
const ec_pdo_info_t *pi;
ec_pdo_mapping_t *pm;
ec_pdo_t *pdo;
const ec_pdo_entry_info_t *ei;
for (i = 0; i < n_entries; i++) {
pi = &pdo_infos[i];
pm = &sc->mapping[pi->dir];
if (pm->default_mapping) {
pm->default_mapping = 0;
ec_pdo_mapping_clear_pdos(pm);
}
if (sc->master->debug_level)
EC_INFO("Adding Pdo 0x%04X to mapping.\n", pi->index);
for (i = 0; i < n_entries; i++)
if (ec_pdo_mapping_add_pdo_info(&sc->mapping[pdo_infos[i].dir],
&pdo_infos[i], sc))
if (!(pdo = ec_pdo_mapping_add_pdo(pm, pi->dir, pi->index)))
return -1;
if (pi->n_entries && pi->entries) { // configuration provided
if (sc->master->debug_level)
EC_DBG(" Pdo configuration information provided.\n");
for (i = 0; i < pi->n_entries; i++) {
ei = &pi->entries[i];
if (!ec_pdo_add_entry(pdo, ei->index, ei->subindex,
ei->bit_length))
return -1;
}
} else { // use default Pdo configuration
if (sc->master->debug_level)
EC_DBG(" Using default Pdo configuration.\n");
ec_slave_config_load_default_pdo_config(sc, pdo);
}
}
return 0;
}
......@@ -526,6 +651,8 @@ int ecrt_slave_config_sdo32(ec_slave_config_t *slave, uint16_t index,
/** \cond */
EXPORT_SYMBOL(ecrt_slave_config_pdo);
EXPORT_SYMBOL(ecrt_slave_config_pdo_entry);
EXPORT_SYMBOL(ecrt_slave_config_mapping);
EXPORT_SYMBOL(ecrt_slave_config_reg_pdo_entry);
EXPORT_SYMBOL(ecrt_slave_config_sdo8);
......
......@@ -83,13 +83,12 @@ int ec_slave_config_init(ec_slave_config_t *, ec_master_t *, uint16_t,
uint16_t, uint32_t, uint32_t);
void ec_slave_config_destroy(ec_slave_config_t *);
int ec_slave_config_reg_pdo_entry(ec_slave_config_t *, ec_domain_t *,
uint16_t, uint8_t);
int ec_slave_config_attach(ec_slave_config_t *);
void ec_slave_config_detach(ec_slave_config_t *);
void ec_slave_config_load_default_mapping(ec_slave_config_t *);
void ec_slave_config_load_default_pdo_config(const ec_slave_config_t *,
ec_pdo_t *);
/*****************************************************************************/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment