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>
Florian Pose
committed
#include "../include/EtherCAT_si.h"
#include "globals.h"
#include "slave.h"
Florian Pose
committed
#include "frame.h"
Florian Pose
committed
/*****************************************************************************/
Florian Pose
committed
*/
Florian Pose
committed
void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
ec_master_t *master /**< EtherCAT-Master */
)
{
slave->master = master;
slave->base_type = 0;
slave->base_revision = 0;
slave->base_build = 0;
slave->base_fmmu_count = 0;
slave->base_sync_count = 0;
slave->ring_position = 0;
slave->station_address = 0;
slave->sii_vendor_id = 0;
slave->sii_product_code = 0;
slave->sii_revision_number = 0;
slave->sii_serial_number = 0;
slave->type = NULL;
slave->registered = 0;
slave->fmmu_count = 0;
}
Florian Pose
committed
/*****************************************************************************/
Florian Pose
committed
/**
EtherCAT-Slave-Destruktor.
Florian Pose
committed
void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */)
Florian Pose
committed
// Nichts freizugeben
}
/*****************************************************************************/
/**
Liest alle bentigten Informationen aus einem Slave.
Florian Pose
committed
*/
int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */)
{
ec_frame_t frame;
// Read base data
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0000, 6);
if (unlikely(ec_frame_send_receive(&frame))) {
EC_ERR("Reading base datafrom slave %i failed!\n",
Florian Pose
committed
return -1;
}
Florian Pose
committed
slave->base_type = EC_READ_U8 (frame.data);
slave->base_revision = EC_READ_U8 (frame.data + 1);
slave->base_build = EC_READ_U16(frame.data + 2);
slave->base_fmmu_count = EC_READ_U8 (frame.data + 4);
slave->base_sync_count = EC_READ_U8 (frame.data + 5);
Florian Pose
committed
if (slave->base_fmmu_count > EC_MAX_FMMUS)
slave->base_fmmu_count = EC_MAX_FMMUS;
// Read identification from "Slave Information Interface" (SII)
if (unlikely(ec_slave_sii_read(slave, 0x0008, &slave->sii_vendor_id))) {
Florian Pose
committed
return -1;
}
if (unlikely(ec_slave_sii_read(slave, 0x000A, &slave->sii_product_code))) {
EC_ERR("Could not read SII product code!\n");
Florian Pose
committed
return -1;
}
if (unlikely(ec_slave_sii_read(slave, 0x000C,
&slave->sii_revision_number))) {
EC_ERR("Could not read SII revision number!\n");
Florian Pose
committed
return -1;
}
if (unlikely(ec_slave_sii_read(slave, 0x000E,
&slave->sii_serial_number))) {
EC_ERR("Could not read SII serial number!\n");
Florian Pose
committed
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
return -1;
}
return 0;
}
/*****************************************************************************/
/**
Liest Daten aus dem Slave-Information-Interface
eines EtherCAT-Slaves.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_sii_read(ec_slave_t *slave,
/**< EtherCAT-Slave */
unsigned short int offset,
/**< Adresse des zu lesenden SII-Registers */
unsigned int *target
/**< Zeiger auf einen 4 Byte groen Speicher zum Ablegen
der Daten */
)
{
ec_frame_t frame;
unsigned char data[10];
unsigned int tries_left;
// Initiate read operation
Florian Pose
committed
EC_WRITE_U8 (data, 0x00);
EC_WRITE_U8 (data + 1, 0x01);
EC_WRITE_U16(data + 2, offset);
EC_WRITE_U16(data + 4, 0x0000);
Florian Pose
committed
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x502, 6, data);
Florian Pose
committed
if (unlikely(ec_frame_send_receive(&frame))) {
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
// den Status auslesen, bis das Bit weg ist.
tries_left = 100;
while (likely(tries_left))
{
udelay(10);
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x502, 10);
Florian Pose
committed
if (unlikely(ec_frame_send_receive(&frame))) {
EC_ERR("Getting SII-read status failed on slave %i!\n",
Florian Pose
committed
return -1;
}
Florian Pose
committed
if (likely((EC_READ_U8(frame.data + 1) & 0x81) == 0)) {
Florian Pose
committed
memcpy(target, frame.data + 6, 4);
break;
}
tries_left--;
}
if (unlikely(!tries_left)) {
EC_ERR("SSI-read. Slave %i timed out!\n", slave->ring_position);
Florian Pose
committed
return -1;
}
return 0;
}
/*****************************************************************************/
/**
Besttigt einen Fehler beim Zustandswechsel.
Florian Pose
committed
*/
void ec_slave_state_ack(ec_slave_t *slave,
/**< Slave, dessen Zustand gendert werden soll */
uint8_t state
/**< Alter Zustand */
)
{
ec_frame_t frame;
unsigned char data[2];
unsigned int tries_left;
Florian Pose
committed
EC_WRITE_U16(data, state | EC_ACK);
Florian Pose
committed
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0120, 2, data);
Florian Pose
committed
if (unlikely(ec_frame_send_receive(&frame))) {
EC_WARN("State %02X acknowledge failed on slave %i!\n",
state, slave->ring_position);
Florian Pose
committed
return;
}
tries_left = 100;
while (likely(tries_left))
{
udelay(10);
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0130, 2);
if (unlikely(ec_frame_send_receive(&frame))) {
EC_WARN("State %02X acknowledge checking failed on slave %i!\n",
state, slave->ring_position);
Florian Pose
committed
return;
}
Florian Pose
committed
if (unlikely(EC_READ_U8(frame.data) != state)) {
EC_WARN("Could not acknowledge state %02X on slave %i (code"
" %02X)!\n", state, slave->ring_position,
EC_READ_U8(frame.data));
Florian Pose
committed
return;
}
Florian Pose
committed
if (likely(EC_READ_U8(frame.data) == state)) {
EC_INFO("Acknowleged state %02X on slave %i.\n", state,
slave->ring_position);
Florian Pose
committed
return;
}
tries_left--;
}
if (unlikely(!tries_left)) {
EC_WARN("Could not check state acknowledgement %02X of slave %i -"
" Timeout while checking!\n", state, slave->ring_position);
Florian Pose
committed
return;
}
}
/*****************************************************************************/
/**
ndert den Zustand eines Slaves.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_state_change(ec_slave_t *slave,
/**< Slave, dessen Zustand gendert werden soll */
uint8_t state
/**< Neuer Zustand */
)
{
ec_frame_t frame;
unsigned char data[2];
unsigned int tries_left;
Florian Pose
committed
EC_WRITE_U16(data, state);
Florian Pose
committed
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0120, 2, data);
Florian Pose
committed
if (unlikely(ec_frame_send_receive(&frame))) {
EC_ERR("Failed to set state %02X on slave %i!\n",
state, slave->ring_position);
Florian Pose
committed
return -1;
}
tries_left = 100;
while (likely(tries_left))
{
udelay(10);
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0130, 2);
if (unlikely(ec_frame_send_receive(&frame))) {
EC_ERR("Failed to check state %02X on slave %i!\n",
Florian Pose
committed
return -1;
}
Florian Pose
committed
if (unlikely(EC_READ_U8(frame.data) & 0x10)) { // State change error
EC_ERR("Could not set state %02X - Slave %i refused state change"
" (code %02X)!\n", state, slave->ring_position,
EC_READ_U8(frame.data));
Florian Pose
committed
ec_slave_state_ack(slave, EC_READ_U8(frame.data) & 0x0F);
Florian Pose
committed
return -1;
}
Florian Pose
committed
if (likely(EC_READ_U8(frame.data) == (state & 0x0F))) {
Florian Pose
committed
// State change successful
break;
}
tries_left--;
}
if (unlikely(!tries_left)) {
EC_ERR("Could not check state %02X of slave %i - Timeout!\n", state,
Florian Pose
committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
slave->ring_position);
return -1;
}
return 0;
}
/*****************************************************************************/
/**
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
FMMUs konfiguriert.
Wenn die entsprechende FMMU bereits konfiguriert ist, wird dies als
Erfolg zurckgegeben.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_set_fmmu(ec_slave_t *slave, /**< EtherCAT-Slave */
const ec_domain_t *domain, /**< Domne */
const ec_sync_t *sync /**< Sync-Manager */
)
{
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.
*/
void ec_slave_print(const ec_slave_t *slave /**< EtherCAT-Slave */)
{
EC_INFO("--- EtherCAT slave information ---\n");
Florian Pose
committed
if (slave->type) {
EC_INFO(" Vendor \"%s\", Product \"%s\": %s\n",
slave->type->vendor_name, slave->type->product_name,
slave->type->description);
Florian Pose
committed
}
else {
EC_INFO(" *** This slave has no type information! ***\n");
Florian Pose
committed
}
EC_INFO(" Ring position: %i, Station address: 0x%04X\n",
slave->ring_position, slave->station_address);
Florian Pose
committed
EC_INFO(" Base information:\n");
EC_INFO(" Type %u, Revision %i, Build %i\n",
slave->base_type, slave->base_revision, slave->base_build);
EC_INFO(" Supported FMMUs: %i, Sync managers: %i\n",
slave->base_fmmu_count, slave->base_sync_count);
Florian Pose
committed
EC_INFO(" Slave information interface:\n");
EC_INFO(" Vendor-ID: 0x%08X, Product code: 0x%08X\n",
slave->sii_vendor_id, slave->sii_product_code);
EC_INFO(" Revision number: 0x%08X, Serial number: 0x%08X\n",
slave->sii_revision_number, slave->sii_serial_number);
Florian Pose
committed
/*****************************************************************************/
/**
Gibt die Zhlerstnde der CRC-Fault-Counter aus und setzt diese zurck.
\return 0 bei Erfolg, sonst < 0
*/
int ec_slave_check_crc(ec_slave_t *slave /**< EtherCAT-Slave */)
{
ec_frame_t frame;
uint8_t data[4];
ec_frame_init_nprd(&frame, slave->master, slave->station_address,
0x0300, 4);
if (unlikely(ec_frame_send_receive(&frame))) {
EC_WARN("Reading CRC fault counters failed on slave %i!\n",
return -1;
}
// No CRC faults.
Florian Pose
committed
if (!EC_READ_U16(frame.data) && !EC_READ_U16(frame.data + 2)) return 0;
EC_WARN("CRC faults on slave %i. A: %i, B: %i\n", slave->ring_position,
EC_READ_U16(frame.data), EC_READ_U16(frame.data + 2));
// Reset CRC counters
Florian Pose
committed
EC_WRITE_U16(data, 0x0000);
EC_WRITE_U16(data + 2, 0x0000);
ec_frame_init_npwr(&frame, slave->master, slave->station_address,
0x0300, 4, data);
if (unlikely(ec_frame_send_receive(&frame))) {
EC_WARN("Resetting CRC fault counters failed on slave %i!\n",
return -1;
}
return 0;
}
/*****************************************************************************/
/* Emacs-Konfiguration
;;; Local Variables: ***
Florian Pose
committed
;;; c-basic-offset:4 ***