Newer
Older
Florian Pose
committed
/******************************************************************************
* s l a v e . c
* EtherCAT slave methods.
Florian Pose
committed
* $Id$
Florian Pose
committed
*****************************************************************************/
Florian Pose
committed
#include <linux/delay.h>
#include "globals.h"
#include "slave.h"
#include "command.h"
#include "master.h"
Florian Pose
committed
/*****************************************************************************/
int ec_slave_fetch_categories(ec_slave_t *);
int ec_slave_fetch_strings(ec_slave_t *, const uint8_t *);
int ec_slave_fetch_general(ec_slave_t *, const uint8_t *);
int ec_slave_fetch_sync(ec_slave_t *, const uint8_t *, size_t);
int ec_slave_fetch_pdo(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t);
int ec_slave_locate_string(ec_slave_t *, unsigned int, char **);
ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
/*****************************************************************************/
Florian Pose
committed
EC_SYSFS_READ_ATTR(coupler_address);
EC_SYSFS_READ_ATTR(vendor_name);
EC_SYSFS_READ_ATTR(product_name);
EC_SYSFS_READ_ATTR(product_desc);
static struct attribute *def_attrs[] = {
&attr_ring_position,
Florian Pose
committed
&attr_coupler_address,
&attr_vendor_name,
&attr_product_name,
&attr_product_desc,
NULL,
};
static struct sysfs_ops sysfs_ops = {
.show = &ec_show_slave_attribute,
.store = NULL
};
static struct kobj_type ktype_ec_slave = {
.release = ec_slave_clear,
.sysfs_ops = &sysfs_ops,
.default_attrs = def_attrs
};
/*****************************************************************************/
const ec_code_msg_t al_status_messages[];
/*****************************************************************************/
Slave constructor.
\return 0 in case of success, else < 0
Florian Pose
committed
*/
int ec_slave_init(ec_slave_t *slave, /**< EtherCAT slave */
ec_master_t *master, /**< EtherCAT master */
uint16_t ring_position, /**< ring position */
uint16_t station_address /**< station address to configure */
Florian Pose
committed
{
slave->ring_position = ring_position;
slave->station_address = station_address;
// init kobject and add it to the hierarchy
memset(&slave->kobj, 0x00, sizeof(struct kobject));
kobject_init(&slave->kobj);
slave->kobj.ktype = &ktype_ec_slave;
slave->kobj.parent = &master->kobj;
if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) {
EC_ERR("Failed to set kobject name.\n");
kobject_put(&slave->kobj);
return -1;
}
Florian Pose
committed
slave->master = master;
Florian Pose
committed
slave->coupler_index = 0;
slave->coupler_subindex = 0xFFFF;
Florian Pose
committed
slave->base_type = 0;
slave->base_revision = 0;
slave->base_build = 0;
slave->base_fmmu_count = 0;
slave->base_sync_count = 0;
Florian Pose
committed
slave->sii_vendor_id = 0;
slave->sii_product_code = 0;
slave->sii_revision_number = 0;
slave->sii_serial_number = 0;
slave->sii_rx_mailbox_offset = 0;
slave->sii_rx_mailbox_size = 0;
slave->sii_tx_mailbox_offset = 0;
slave->sii_tx_mailbox_size = 0;
Florian Pose
committed
slave->sii_mailbox_protocols = 0;
Florian Pose
committed
slave->type = NULL;
slave->registered = 0;
slave->fmmu_count = 0;
slave->eeprom_name = NULL;
slave->eeprom_group = NULL;
slave->eeprom_desc = NULL;
ec_command_init(&slave->mbox_command);
INIT_LIST_HEAD(&slave->eeprom_strings);
INIT_LIST_HEAD(&slave->eeprom_syncs);
INIT_LIST_HEAD(&slave->eeprom_pdos);
INIT_LIST_HEAD(&slave->sdo_dictionary);
for (i = 0; i < 4; i++) {
slave->dl_link[i] = 0;
slave->dl_loop[i] = 0;
slave->dl_signal[i] = 0;
slave->sii_physical_layer[i] = 0xFF;
Florian Pose
committed
}
Florian Pose
committed
/*****************************************************************************/
Florian Pose
committed
/**
Slave destructor.
void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */)
ec_eeprom_string_t *string, *next_str;
ec_eeprom_sync_t *sync, *next_sync;
ec_eeprom_pdo_t *pdo, *next_pdo;
ec_eeprom_pdo_entry_t *entry, *next_ent;
ec_sdo_t *sdo, *next_sdo;
ec_sdo_entry_t *en, *next_en;
slave = container_of(kobj, ec_slave_t, kobj);
// free all string objects
list_for_each_entry_safe(string, next_str, &slave->eeprom_strings, list) {
list_del(&string->list);
kfree(string);
}
// free all sync managers
list_for_each_entry_safe(sync, next_sync, &slave->eeprom_syncs, list) {
list_del(&sync->list);
kfree(sync);
}
// free all PDOs
list_for_each_entry_safe(pdo, next_pdo, &slave->eeprom_pdos, list) {
list_del(&pdo->list);
if (pdo->name) kfree(pdo->name);
// free all PDO entries
list_for_each_entry_safe(entry, next_ent, &pdo->entries, list) {
list_del(&entry->list);
if (entry->name) kfree(entry->name);
kfree(entry);
}
kfree(pdo);
}
if (slave->eeprom_name) kfree(slave->eeprom_name);
if (slave->eeprom_group) kfree(slave->eeprom_group);
if (slave->eeprom_desc) kfree(slave->eeprom_desc);
// free all SDOs
list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
list_del(&sdo->list);
if (sdo->name) kfree(sdo->name);
// free all SDO entries
list_for_each_entry_safe(en, next_en, &sdo->entries, list) {
list_del(&en->list);
kfree(en);
}
ec_command_clear(&slave->mbox_command);
Florian Pose
committed
}
/*****************************************************************************/
/**
Reads all necessary information from a slave.
\return 0 in case of success, else < 0
Florian Pose
committed
*/
int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT slave */)
Florian Pose
committed
{
ec_command_t *command;
Florian Pose
committed
command = &slave->master->simple_command;
// read base data
if (ec_command_nprd(command, slave->station_address, 0x0000, 6)) return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Reading base data from slave %i failed!\n",
Florian Pose
committed
return -1;
}
slave->base_type = EC_READ_U8 (command->data);
slave->base_revision = EC_READ_U8 (command->data + 1);
slave->base_build = EC_READ_U16(command->data + 2);
slave->base_fmmu_count = EC_READ_U8 (command->data + 4);
slave->base_sync_count = EC_READ_U8 (command->data + 5);
Florian Pose
committed
if (slave->base_fmmu_count > EC_MAX_FMMUS)
slave->base_fmmu_count = EC_MAX_FMMUS;
// read data link status
if (ec_command_nprd(command, slave->station_address, 0x0110, 2)) return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Reading DL status from slave %i failed!\n",
slave->ring_position);
return -1;
}
dl_status = EC_READ_U16(command->data);
for (i = 0; i < 4; i++) {
slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0;
// read EEPROM data
if (ec_slave_sii_read16(slave, 0x0004, &slave->sii_alias))
if (ec_slave_sii_read32(slave, 0x0008, &slave->sii_vendor_id))
Florian Pose
committed
return -1;
if (ec_slave_sii_read32(slave, 0x000A, &slave->sii_product_code))
Florian Pose
committed
return -1;
if (ec_slave_sii_read32(slave, 0x000C, &slave->sii_revision_number))
Florian Pose
committed
return -1;
if (ec_slave_sii_read32(slave, 0x000E, &slave->sii_serial_number))
Florian Pose
committed
return -1;
if (ec_slave_sii_read16(slave, 0x0018, &slave->sii_rx_mailbox_offset))
return -1;
if (ec_slave_sii_read16(slave, 0x0019, &slave->sii_rx_mailbox_size))
return -1;
if (ec_slave_sii_read16(slave, 0x001A, &slave->sii_tx_mailbox_offset))
return -1;
if (ec_slave_sii_read16(slave, 0x001B, &slave->sii_tx_mailbox_size))
return -1;
if (ec_slave_sii_read16(slave, 0x001C, &slave->sii_mailbox_protocols))
Florian Pose
committed
return -1;
if (unlikely(ec_slave_fetch_categories(slave))) {
EC_ERR("Failed to fetch category data!\n");
Florian Pose
committed
return 0;
}
/*****************************************************************************/
/**
Reads 16 bit from the slave information interface (SII).
\return 0 in case of success, else < 0
Florian Pose
committed
*/
int ec_slave_sii_read16(ec_slave_t *slave,
/**< EtherCAT slave */
uint16_t offset,
/**< address of the SII register to read */
uint16_t *target
/**< target memory */
ec_command_t *command;
cycles_t start, end, timeout;
command = &slave->master->simple_command;
// initiate read operation
if (ec_command_npwr(command, slave->station_address, 0x502, 6)) return -1;
EC_WRITE_U8 (command->data, 0x00); // read-only access
EC_WRITE_U8 (command->data + 1, 0x01); // request read operation
EC_WRITE_U32(command->data + 2, offset);
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("SII-read failed on slave %i!\n", slave->ring_position);
return -1;
}
start = get_cycles();
timeout = (cycles_t) 100 * cpu_khz; // 100ms
while (1)
{
udelay(10);
if (ec_command_nprd(command, slave->station_address, 0x502, 10))
return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Getting SII-read status failed on slave %i!\n",
slave->ring_position);
return -1;
}
end = get_cycles();
// check for "busy bit"
if (likely((EC_READ_U8(command->data + 1) & 0x81) == 0)) {
*target = EC_READ_U16(command->data + 6);
return 0;
}
if (unlikely((end - start) >= timeout)) {
EC_ERR("SII-read. Slave %i timed out!\n", slave->ring_position);
return -1;
}
}
}
/*****************************************************************************/
/**
Reads 32 bit from the slave information interface (SII).
\return 0 in case of success, else < 0
*/
int ec_slave_sii_read32(ec_slave_t *slave,
/**< EtherCAT slave */
uint16_t offset,
/**< address of the SII register to read */
uint32_t *target
/**< target memory */
Florian Pose
committed
{
ec_command_t *command;
cycles_t start, end, timeout;
Florian Pose
committed
command = &slave->master->simple_command;
Florian Pose
committed
// initiate read operation
if (ec_command_npwr(command, slave->station_address, 0x502, 6)) return -1;
EC_WRITE_U8 (command->data, 0x00); // read-only access
EC_WRITE_U8 (command->data + 1, 0x01); // request read operation
EC_WRITE_U32(command->data + 2, offset);
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("SII-read failed on slave %i!\n", slave->ring_position);
Florian Pose
committed
return -1;
}
start = get_cycles();
timeout = (cycles_t) 100 * cpu_khz; // 100ms
Florian Pose
committed
if (ec_command_nprd(command, slave->station_address, 0x502, 10))
return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Getting SII-read status failed on slave %i!\n",
Florian Pose
committed
return -1;
}
end = get_cycles();
// check "busy bit"
if (likely((EC_READ_U8(command->data + 1) & 0x81) == 0)) {
*target = EC_READ_U32(command->data + 6);
Florian Pose
committed
}
EC_ERR("SII-read. Slave %i timed out!\n", slave->ring_position);
Florian Pose
committed
}
}
/*****************************************************************************/
Writes 16 bit of data to the slave information interface (SII).
\return 0 in case of success, else < 0
int ec_slave_sii_write16(ec_slave_t *slave,
/**< EtherCAT slave */
uint16_t offset,
/**< address of the SII register to write */
uint16_t value
/**< new value */
ec_command_t *command;
command = &slave->master->simple_command;
EC_INFO("SII-write (slave %i, offset 0x%04X, value 0x%04X)\n",
slave->ring_position, offset, value);
// initiate write operation
if (ec_command_npwr(command, slave->station_address, 0x502, 8)) return -1;
EC_WRITE_U8 (command->data, 0x01); // enable write access
EC_WRITE_U8 (command->data + 1, 0x02); // request write operation
EC_WRITE_U32(command->data + 2, offset);
EC_WRITE_U16(command->data + 6, value);
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("SII-write failed on slave %i!\n", slave->ring_position);
return -1;
}
start = get_cycles();
timeout = (cycles_t) 100 * cpu_khz; // 100ms
if (ec_command_nprd(command, slave->station_address, 0x502, 2))
return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Getting SII-write status failed on slave %i!\n",
slave->ring_position);
return -1;
}
end = get_cycles();
// check "busy bit"
if (likely((EC_READ_U8(command->data + 1) & 0x82) == 0)) {
if (EC_READ_U8(command->data + 1) & 0x40) {
EC_ERR("SII-write failed!\n");
return -1;
}
else {
EC_INFO("SII-write succeeded!\n");
return 0;
}
}
if (unlikely((end - start) >= timeout)) {
EC_ERR("SII-write: Slave %i timed out!\n", slave->ring_position);
return -1;
}
}
}
/*****************************************************************************/
Fetches data from slave's EEPROM.
\return 0 in case of success, else < 0
int ec_slave_fetch_categories(ec_slave_t *slave /**< EtherCAT slave */)
uint16_t word_offset, cat_type, word_count;
uint32_t value;
uint8_t *cat_data;
unsigned int i;
word_offset = 0x0040;
if (!(cat_data = (uint8_t *) kmalloc(0x10000, GFP_KERNEL))) {
EC_ERR("Failed to allocate 64k bytes for category data.\n");
return -1;
}
while (1) {
if (ec_slave_sii_read32(slave, word_offset, &value)) {
EC_ERR("Unable to read category header.\n");
// last category?
if ((value & 0xFFFF) == 0xFFFF) break;
word_count = (value >> 16) & 0xFFFF;
// fetch category data
if (ec_slave_sii_read32(slave, word_offset + 2 + i, &value)) {
EC_ERR("Unable to read category data word %i.\n", i);
}
cat_data[i * 2] = (value >> 0) & 0xFF;
cat_data[i * 2 + 1] = (value >> 8) & 0xFF;
// read second word "on the fly"
if (i + 1 < word_count) {
i++;
cat_data[i * 2] = (value >> 16) & 0xFF;
cat_data[i * 2 + 1] = (value >> 24) & 0xFF;
}
}
if (ec_slave_fetch_strings(slave, cat_data))
goto out_free;
if (ec_slave_fetch_general(slave, cat_data))
goto out_free;
break;
case 0x0028:
break;
case 0x0029:
if (ec_slave_fetch_sync(slave, cat_data, word_count))
goto out_free;
if (ec_slave_fetch_pdo(slave, cat_data, word_count, EC_TX_PDO))
goto out_free;
if (ec_slave_fetch_pdo(slave, cat_data, word_count, EC_RX_PDO))
goto out_free;
EC_WARN("Unknown category type 0x%04X in slave %i.\n",
cat_type, slave->ring_position);
}
word_offset += 2 + word_count;
}
kfree(cat_data);
return 0;
}
/*****************************************************************************/
/**
Fetches data from a STRING category.
\return 0 in case of success, else < 0
int ec_slave_fetch_strings(ec_slave_t *slave, /**< EtherCAT slave */
const uint8_t *data /**< category data */
)
{
unsigned int string_count, i;
size_t size;
off_t offset;
string_count = data[0];
offset = 1;
for (i = 0; i < string_count; i++) {
size = data[offset];
// allocate memory for string structure and data at a single blow
if (!(string = (ec_eeprom_string_t *)
kmalloc(sizeof(ec_eeprom_string_t) + size + 1, GFP_KERNEL))) {
EC_ERR("Failed to allocate string memory.\n");
return -1;
}
// string memory appended to string structure
string->data = (char *) string + sizeof(ec_eeprom_string_t);
memcpy(string->data, data + offset + 1, size);
string->data[size] = 0x00;
list_add_tail(&string->list, &slave->eeprom_strings);
offset += 1 + size;
}
return 0;
}
/*****************************************************************************/
/**
Fetches data from a GENERAL category.
\return 0 in case of success, else < 0
int ec_slave_fetch_general(ec_slave_t *slave, /**< EtherCAT slave */
const uint8_t *data /**< category data */
if (ec_slave_locate_string(slave, data[0], &slave->eeprom_group))
return -1;
if (ec_slave_locate_string(slave, data[1], &slave->eeprom_name))
return -1;
if (ec_slave_locate_string(slave, data[3], &slave->eeprom_desc))
return -1;
slave->sii_physical_layer[i] =
(data[4] & (0x03 << (i * 2))) >> (i * 2);
}
/*****************************************************************************/
/**
Fetches data from a SYNC MANAGER category.
\return 0 in case of success, else < 0
int ec_slave_fetch_sync(ec_slave_t *slave, /**< EtherCAT slave */
const uint8_t *data, /**< category data */
size_t word_count /**< number of words */
unsigned int sync_count, i;
ec_eeprom_sync_t *sync;
sync_count = word_count / 4; // sync manager struct is 4 words long
for (i = 0; i < sync_count; i++, data += 8) {
if (!(sync = (ec_eeprom_sync_t *)
kmalloc(sizeof(ec_eeprom_sync_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate Sync-Manager memory.\n");
return -1;
}
sync->index = i;
sync->physical_start_address = *((uint16_t *) (data + 0));
sync->length = *((uint16_t *) (data + 2));
sync->control_register = data[4];
sync->enable = data[6];
list_add_tail(&sync->list, &slave->eeprom_syncs);
}
return 0;
}
/*****************************************************************************/
/**
Fetches data from a [RT]XPDO category.
\return 0 in case of success, else < 0
int ec_slave_fetch_pdo(ec_slave_t *slave, /**< EtherCAT slave */
const uint8_t *data, /**< category data */
size_t word_count, /**< number of words */
ec_pdo_type_t pdo_type /**< PDO type */
ec_eeprom_pdo_t *pdo;
ec_eeprom_pdo_entry_t *entry;
unsigned int entry_count, i;
while (word_count >= 4) {
if (!(pdo = (ec_eeprom_pdo_t *)
kmalloc(sizeof(ec_eeprom_pdo_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO memory.\n");
return -1;
}
INIT_LIST_HEAD(&pdo->entries);
pdo->type = pdo_type;
pdo->index = *((uint16_t *) data);
entry_count = data[2];
pdo->sync_manager = data[3];
pdo->name = NULL;
ec_slave_locate_string(slave, data[5], &pdo->name);
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
list_add_tail(&pdo->list, &slave->eeprom_pdos);
word_count -= 4;
data += 8;
for (i = 0; i < entry_count; i++) {
if (!(entry = (ec_eeprom_pdo_entry_t *)
kmalloc(sizeof(ec_eeprom_pdo_entry_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO entry memory.\n");
return -1;
}
entry->index = *((uint16_t *) data);
entry->subindex = data[2];
entry->name = NULL;
ec_slave_locate_string(slave, data[3], &entry->name);
entry->bit_length = data[5];
list_add_tail(&entry->list, &pdo->entries);
word_count -= 4;
data += 8;
}
}
return 0;
}
/*****************************************************************************/
Searches the string list for an index and allocates a new string.
\return 0 in case of success, else < 0
*/
int ec_slave_locate_string(ec_slave_t *slave, unsigned int index, char **ptr)
{
ec_eeprom_string_t *string;
char *err_string;
if (*ptr) {
kfree(*ptr);
*ptr = NULL;
}
// EEPROM-String mit Index finden und kopieren
list_for_each_entry(string, &slave->eeprom_strings, list) {
if (--index) continue;
if (!(*ptr = (char *) kmalloc(string->size + 1, GFP_KERNEL))) {
EC_ERR("Unable to allocate string memory.\n");
return -1;
memcpy(*ptr, string->data, string->size + 1);
return 0;
EC_WARN("String %i not found in slave %i.\n", index, slave->ring_position);
err_string = "(string not found)";
if (!(*ptr = (char *) kmalloc(strlen(err_string) + 1, GFP_KERNEL))) {
EC_ERR("Unable to allocate string memory.\n");
return -1;
}
memcpy(*ptr, err_string, strlen(err_string) + 1);
return 0;
}
/*****************************************************************************/
Florian Pose
committed
/**
Acknowledges an error after a state transition.
Florian Pose
committed
*/
void ec_slave_state_ack(ec_slave_t *slave, /**< EtherCAT slave */
uint8_t state /**< previous state */
Florian Pose
committed
)
{
ec_command_t *command;
cycles_t start, end, timeout;
Florian Pose
committed
command = &slave->master->simple_command;
Florian Pose
committed
if (ec_command_npwr(command, slave->station_address, 0x0120, 2)) return;
EC_WRITE_U16(command->data, state | EC_ACK);
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_WARN("Acknowledge sending failed on slave %i!\n",
slave->ring_position);
Florian Pose
committed
return;
}
start = get_cycles();
timeout = (cycles_t) 10 * cpu_khz; // 10ms
Florian Pose
committed
udelay(100); // wait a little bit...
if (ec_command_nprd(command, slave->station_address, 0x0130, 2))
return;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_WARN("Acknowledge checking failed on slave %i!\n",
slave->ring_position);
Florian Pose
committed
return;
}
end = get_cycles();
if (likely(EC_READ_U8(command->data) == state)) {
EC_INFO("Acknowleged state 0x%02X on slave %i.\n", state,
Florian Pose
committed
return;
}
EC_WARN("Failed to acknowledge state 0x%02X on slave %i"
" - Timeout!\n", state, slave->ring_position);
Florian Pose
committed
}
}
/*****************************************************************************/
/**
Reads the AL status code of a slave and displays it.
If the AL status code is not supported, or if no error occurred (both
resulting in code=0), nothing is displayed.
*/
void ec_slave_read_al_status_code(ec_slave_t *slave /**< EtherCAT slave */)
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
{
ec_command_t *command;
uint16_t code;
const ec_code_msg_t *al_msg;
command = &slave->master->simple_command;
if (ec_command_nprd(command, slave->station_address, 0x0134, 2)) return;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_WARN("Failed to read AL status code on slave %i!\n",
slave->ring_position);
return;
}
if (!(code = EC_READ_U16(command->data))) return;
for (al_msg = al_status_messages; al_msg->code; al_msg++) {
if (al_msg->code == code) {
EC_ERR("AL status message 0x%04X: \"%s\".\n",
al_msg->code, al_msg->message);
return;
}
}
EC_ERR("Unknown AL status code 0x%04X.\n", code);
}
/*****************************************************************************/
Florian Pose
committed
/**
Does a state transition.
\return 0 in case of success, else < 0
Florian Pose
committed
*/
int ec_slave_state_change(ec_slave_t *slave, /**< EtherCAT slave */
uint8_t state /**< new state */
Florian Pose
committed
)
{
ec_command_t *command;
cycles_t start, end, timeout;
Florian Pose
committed
command = &slave->master->simple_command;
Florian Pose
committed
if (ec_command_npwr(command, slave->station_address, 0x0120, 2)) return -1;
EC_WRITE_U16(command->data, state);
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Failed to set state 0x%02X on slave %i!\n",
Florian Pose
committed
return -1;
}
start = get_cycles();
timeout = (cycles_t) 10 * cpu_khz; // 10ms
Florian Pose
committed
udelay(100); // wait a little bit
Florian Pose
committed
if (ec_command_nprd(command, slave->station_address, 0x0130, 2))
return -1;
if (unlikely(ec_master_simple_io(slave->master, command))) {
EC_ERR("Failed to check state 0x%02X on slave %i!\n",
Florian Pose
committed
return -1;
}
end = get_cycles();
if (unlikely(EC_READ_U8(command->data) & 0x10)) { // state change error
EC_ERR("Failed to set state 0x%02X - Slave %i refused state change"
" (code 0x%02X)!\n", state, slave->ring_position,
EC_READ_U8(command->data));
state = EC_READ_U8(command->data) & 0x0F;
ec_slave_read_al_status_code(slave);
ec_slave_state_ack(slave, state);
Florian Pose
committed
return -1;
}
if (likely(EC_READ_U8(command->data) == (state & 0x0F)))
return 0; // state change successful
Florian Pose
committed
EC_ERR("Failed to check state 0x%02X of slave %i - Timeout!\n",
Florian Pose
committed
}
}
/*****************************************************************************/
/**
Prepares an FMMU configuration.
Configuration data for the FMMU is saved in the slave structure and is
written to the slave in ecrt_master_activate().
The FMMU configuration is done in a way, that the complete data range
of the corresponding sync manager is covered. Seperate FMMUs arce configured
for each domain.
If the FMMU configuration is already prepared, the function returns with
success.
\return 0 in case of success, else < 0
Florian Pose
committed
*/
int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT slave */
const ec_domain_t *domain, /**< domain */
const ec_sync_t *sync /**< sync manager */
Florian Pose
committed
{
unsigned int i;
// FMMU configuration already prepared?
Florian Pose
committed
for (i = 0; i < slave->fmmu_count; i++)
if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync)
return 0;
// reserve new FMMU...
Florian Pose
committed
if (slave->fmmu_count >= slave->base_fmmu_count) {
EC_ERR("Slave %i FMMU limit reached!\n", slave->ring_position);
Florian Pose
committed
return -1;
}
slave->fmmus[slave->fmmu_count].domain = domain;
slave->fmmus[slave->fmmu_count].sync = sync;
slave->fmmus[slave->fmmu_count].logical_start_address = 0;
slave->fmmu_count++;
slave->registered = 1;
return 0;
}
/*****************************************************************************/
/**
Outputs all information about a certain slave.
- 0: Only slave types and addresses
- 1: with EEPROM information
- >1: with SDO dictionaries
Florian Pose
committed
*/
void ec_slave_print(const ec_slave_t *slave, /**< EtherCAT slave */
unsigned int verbosity /**< verbosity level */
Florian Pose
committed
{
ec_eeprom_sync_t *sync;
ec_eeprom_pdo_t *pdo;
Florian Pose
committed
if (slave->type) {
EC_INFO("%i) %s %s: %s\n", slave->ring_position,
slave->type->vendor_name, slave->type->product_name,
slave->type->description);
Florian Pose
committed
}
else {
EC_INFO("%i) UNKNOWN SLAVE: vendor 0x%08X, product 0x%08X\n",
slave->ring_position, slave->sii_vendor_id,
slave->sii_product_code);
Florian Pose
committed
}
if (!verbosity) return;
EC_INFO(" Station address: 0x%04X\n", slave->station_address);
Florian Pose
committed
EC_INFO(" Data link status:\n");
for (i = 0; i < 4; i++) {
EC_INFO(" Port %i (", i);
switch (slave->sii_physical_layer[i]) {
case 0x00: