Newer
Older
Florian Pose
committed
/******************************************************************************
* s l a v e . c
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 *);
/*****************************************************************************/
static struct attribute attr_ring_position = {
.name = "ring_position",
.owner = THIS_MODULE,
.mode = S_IRUGO
};
static struct attribute *def_attrs[] = {
&attr_ring_position,
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[];
/*****************************************************************************/
Florian Pose
committed
*/
int ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
ec_master_t *master, /**< EtherCAT-Master */
uint16_t ring_position, /**< Ringposition */
uint16_t station_address /**< Programmierte Adresse */
)
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;
slave->buscoupler_index = 0;
slave->index_after_buscoupler = 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 < 2; i++) {
slave->dl_status_link[i] = 0;
slave->dl_status_loop[i] = 0;
slave->dl_status_comm[i] = 0;
}
Florian Pose
committed
}
Florian Pose
committed
/*****************************************************************************/
Florian Pose
committed
/**
EtherCAT-Slave-Destruktor.
void ec_slave_clear(struct kobject *kobj /**< KObject des Slaves */)
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);
list_for_each_entry_safe(string, next_str, &slave->eeprom_strings, list) {
list_del(&string->list);
kfree(string);
}
// Alle Sync-Manager freigeben
list_for_each_entry_safe(sync, next_sync, &slave->eeprom_syncs, list) {
list_del(&sync->list);
kfree(sync);
}
// Alle PDOs freigeben
list_for_each_entry_safe(pdo, next_pdo, &slave->eeprom_pdos, list) {
list_del(&pdo->list);
if (pdo->name) kfree(pdo->name);
// Alle Entries innerhalb eines PDOs freigeben
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);
// Alle SDOs freigeben
list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) {
list_del(&sdo->list);
if (sdo->name) kfree(sdo->name);
// Alle Entries freigeben
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
}
/*****************************************************************************/
/**
Liest alle bentigten Informationen aus einem Slave.
\return 0 wenn alles ok, < 0 bei Fehler.
Florian Pose
committed
*/
int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */)
{
ec_command_t *command;
Florian Pose
committed
command = &slave->master->simple_command;
Florian Pose
committed
// 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;
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 < 2; i++) {
slave->dl_status_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
slave->dl_status_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
slave->dl_status_comm[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;
}
/*****************************************************************************/
/**
Liest 16 Bit aus dem Slave-Information-Interface
Florian Pose
committed
eines EtherCAT-Slaves.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_sii_read16(ec_slave_t *slave,
/**< EtherCAT-Slave */
uint16_t offset,
/**< Adresse des zu lesenden SII-Registers */
uint16_t *target
/**< Speicher fr Wert (16-Bit) */
)
{
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;
}
// Der Slave legt die Informationen des Slave-Information-Interface
// in das Datenregister und lscht daraufhin ein Busy-Bit. Solange
// den Status auslesen, bis das Bit weg ist.
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();
if (likely((EC_READ_U8(command->data + 1) & 0x81) == 0)) {
*target = EC_READ_U16(command->data + 6);
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
return 0;
}
if (unlikely((end - start) >= timeout)) {
EC_ERR("SII-read. Slave %i timed out!\n", slave->ring_position);
return -1;
}
}
}
/*****************************************************************************/
/**
Liest 32 Bit aus dem Slave-Information-Interface
eines EtherCAT-Slaves.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_sii_read32(ec_slave_t *slave,
/**< EtherCAT-Slave */
uint16_t offset,
/**< Adresse des zu lesenden SII-Registers */
uint32_t *target
/**< Speicher fr Wert (32-Bit) */
)
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;
}
// Der Slave legt die Informationen des Slave-Information-Interface
// in das Datenregister und lscht daraufhin ein Busy-Bit. Solange
Florian Pose
committed
// den Status auslesen, bis das Bit weg ist.
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();
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
}
}
/*****************************************************************************/
Schreibt 16 Bit Daten in das Slave-Information-Interface
eines EtherCAT-Slaves.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_sii_write16(ec_slave_t *slave,
/**< EtherCAT-Slave */
uint16_t offset,
/**< Adresse des zu lesenden SII-Registers */
uint16_t value
/**< Zu schreibender Wert */
)
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;
}
// Der Slave legt die Informationen des Slave-Information-Interface
// in das Datenregister und lscht daraufhin ein Busy-Bit. Solange
// den Status auslesen, bis das Bit weg ist.
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();
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;
}
}
}
/*****************************************************************************/
/**
Holt Daten aus dem EEPROM.
\return 0, wenn alles ok, sonst < 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
for (i = 0; i < word_count; i++) {
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;
}
/*****************************************************************************/
/**
Holt die Daten einer String-Kategorie.
\return 0 wenn alles ok, sonst < 0
*/
int ec_slave_fetch_strings(ec_slave_t *slave, /**< EtherCAT-Slave */
const uint8_t *data /**< Kategoriedaten */
)
{
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];
// Speicher fr String-Objekt und Daten in einem Rutsch allozieren
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;
}
/*****************************************************************************/
/**
Holt die Daten einer General-Kategorie.
*/
int ec_slave_fetch_general(ec_slave_t *slave, /**< EtherCAT-Slave */
const uint8_t *data /**< Kategorie-Daten */
)
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;
return 0;
}
/*****************************************************************************/
/**
Holt die Daten einer Sync-Manager-Kategorie.
int ec_slave_fetch_sync(ec_slave_t *slave, /**< EtherCAT-Slave */
const uint8_t *data, /**< Kategorie-Daten */
size_t word_count /**< Anzahl Words */
)
unsigned int sync_count, i;
ec_eeprom_sync_t *sync;
sync_count = word_count / 4; // Sync-Manager-Strunktur ist 4 Worte lang
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;
}
/*****************************************************************************/
/**
Holt die Daten einer TXPDO-Kategorie.
*/
int ec_slave_fetch_pdo(ec_slave_t *slave, /**< EtherCAT-Slave */
const uint8_t *data, /**< Kategorie-Daten */
size_t word_count, /**< Anzahl Worte */
ec_pdo_type_t pdo_type /**< PDO-Typ */
)
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);
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
718
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;
}
/*****************************************************************************/
/**
Durchsucht die temporren Strings und dupliziert den gefundenen String.
*/
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
/**
Besttigt einen Fehler beim Zustandswechsel.
Florian Pose
committed
*/
void ec_slave_state_ack(ec_slave_t *slave,
/**< Slave, dessen Zustand gendert werden soll */
Florian Pose
committed
uint8_t state
/**< Alter Zustand */
)
{
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
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
}
}
/*****************************************************************************/
824
825
826
827
828
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
858
859
860
/**
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 */)
{
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
/**
Florian Pose
committed
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_state_change(ec_slave_t *slave,
/**< Slave, dessen Zustand gendert werden soll */
Florian Pose
committed
uint8_t state
/**< Neuer Zustand */
)
{
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); // Dem Slave etwas Zeit lassen...
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))) {
Florian Pose
committed
// State change successful
Florian Pose
committed
}
EC_ERR("Failed to check state 0x%02X of slave %i - Timeout!\n",
Florian Pose
committed
}
}
/*****************************************************************************/
/**
Merkt eine FMMU-Konfiguration vor.
Die FMMU wird so konfiguriert, dass sie den gesamten Datenbereich des
entsprechenden Sync-Managers abdeckt. Fr jede Domne werden separate
Florian Pose
committed
FMMUs konfiguriert.
Wenn die entsprechende FMMU bereits konfiguriert ist, wird dies als
Florian Pose
committed
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_prepare_fmmu(ec_slave_t *slave, /**< EtherCAT-Slave */
const ec_domain_t *domain, /**< Domne */
const ec_sync_t *sync /**< Sync-Manager */
)
Florian Pose
committed
{
unsigned int i;
// FMMU schon vorgemerkt?
for (i = 0; i < slave->fmmu_count; i++)
if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync)
return 0;
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;
}
/*****************************************************************************/
/**
Gibt alle Informationen ber einen EtherCAT-Slave aus.
Verbosity:
0 - Nur Slavetypen und Adressen
1 - mit EEPROM-Informationen
>1 - mit SDO-Dictionaries
Florian Pose
committed
*/
void ec_slave_print(const ec_slave_t *slave, /**< EtherCAT-Slave */
unsigned int verbosity /**< Geschwtzigkeit */
)
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);