diff -r 7c986b717411 -r 9f4ea66d89a3 master/slave.c --- a/master/slave.c Wed Feb 22 17:36:28 2006 +0000 +++ b/master/slave.c Thu Feb 23 09:58:50 2006 +0000 @@ -9,48 +9,431 @@ *****************************************************************************/ #include +#include #include "globals.h" #include "slave.h" +#include "frame.h" /*****************************************************************************/ /** EtherCAT-Slave-Konstruktor. - - Initialisiert einen EtherCAT-Slave. - - ACHTUNG! Dieser Konstruktor wird quasi nie aufgerufen. Bitte immer das - Makro ECAT_INIT_SLAVE() in ec_slave.h anpassen! - - @param slave Zeiger auf den zu initialisierenden Slave -*/ - -void ec_slave_init(ec_slave_t *slave) -{ - slave->base_type = 0; - slave->base_revision = 0; - slave->base_build = 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->logical_address = 0; - slave->process_data = NULL; - slave->private_data = NULL; - slave->configure = NULL; - slave->registered = 0; - slave->domain = 0; - slave->error_reported = 0; +*/ + +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; +} + +/*****************************************************************************/ + +/** + EtherCAT-Slave-Destruktor. +*/ + +void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */) +{ + // Nichts freizugeben +} + +/*****************************************************************************/ + +/** + Liest alle benötigten Informationen aus einem Slave. +*/ + +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))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Slave %i did not respond while reading base" + " data!\n", slave->ring_position); + return -1; + } + + slave->base_type = frame.data[0]; + slave->base_revision = frame.data[1]; + slave->base_build = frame.data[2] | (frame.data[3] << 8); + slave->base_fmmu_count = frame.data[4]; + slave->base_sync_count = frame.data[5]; + + 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))) { + printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000A, &slave->sii_product_code))) { + printk(KERN_ERR "EtherCAT: Could not read SII product code!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000C, + &slave->sii_revision_number))) { + printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n"); + return -1; + } + + if (unlikely(ec_slave_sii_read(slave, 0x000E, + &slave->sii_serial_number))) { + printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n"); + 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 großen Speicher zum Ablegen + der Daten */ + ) +{ + ec_frame_t frame; + unsigned char data[10]; + unsigned int tries_left; + + // Initiate read operation + + data[0] = 0x00; + data[1] = 0x01; + data[2] = offset & 0xFF; + data[3] = (offset & 0xFF00) >> 8; + data[4] = 0x00; + data[5] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x502, 6, + data); + + if (unlikely(ec_frame_send_receive(&frame))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: SII-read - Slave %i did not respond!\n", + slave->ring_position); + return -1; + } + + // Der Slave legt die Informationen des Slave-Information-Interface + // in das Datenregister und löscht 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); + + if (unlikely(ec_frame_send_receive(&frame))) return -1; + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: SII-read status -" + " Slave %i did not respond!\n", slave->ring_position); + return -1; + } + + if (likely((frame.data[1] & 0x81) == 0)) { + memcpy(target, frame.data + 6, 4); + break; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_WARNING "EtherCAT: SSI-read. Slave %i timed out!\n", + slave->ring_position); + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +/** + Bestätigt einen Fehler beim Zustandswechsel. + + FIXME Funktioniert noch nicht... +*/ + +void ec_slave_state_ack(ec_slave_t *slave, + /**< Slave, dessen Zustand geändert werden soll */ + uint8_t state + /**< Alter Zustand */ + ) +{ + ec_frame_t frame; + unsigned char data[2]; + unsigned int tries_left; + + data[0] = state | EC_ACK; + data[1] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120, + 2, data); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could no acknowledge state %02X - Unable to" + " send!\n", state); + return; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X - Slave" + " %i did not respond!\n", state, slave->ring_position); + 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) != 0)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement" + " %02X - Unable to send!\n", state); + return; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement" + " %02X - Slave %i did not respond!\n", state, + slave->ring_position); + return; + } + + if (unlikely(frame.data[0] != state)) { + printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X on" + " slave %i (code %02X)!\n", state, slave->ring_position, + frame.data[0]); + return; + } + + if (likely(frame.data[0] == state)) { + printk(KERN_INFO "EtherCAT: Acknowleged state %02X on slave %i.\n", + state, slave->ring_position); + return; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_ERR "EtherCAT: Could not check state acknowledgement %02X" + " of slave %i - Timeout while checking!\n", state, + slave->ring_position); + return; + } +} + +/*****************************************************************************/ + +/** + Ändert den Zustand eines Slaves. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_slave_state_change(ec_slave_t *slave, + /**< Slave, dessen Zustand geändert werden soll */ + uint8_t state + /**< Neuer Zustand */ + ) +{ + ec_frame_t frame; + unsigned char data[2]; + unsigned int tries_left; + + data[0] = state; + data[1] = 0x00; + + ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120, + 2, data); + + if (unlikely(ec_frame_send_receive(&frame) != 0)) { + printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to" + " send!\n", state); + return -1; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i did not" + " respond!\n", state, slave->ring_position); + 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) != 0)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to" + " send!\n", state); + return -1; + } + + if (unlikely(frame.working_counter != 1)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X - Slave %i" + " did not respond!\n", state, slave->ring_position); + return -1; + } + + if (unlikely(frame.data[0] & 0x10)) { // State change error + printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i" + " refused state change (code %02X)!\n", state, + slave->ring_position, frame.data[0]); + ec_slave_state_ack(slave, frame.data[0] & 0x0F); + return -1; + } + + if (likely(frame.data[0] == (state & 0x0F))) { + // State change successful + break; + } + + tries_left--; + } + + if (unlikely(!tries_left)) { + printk(KERN_ERR "EtherCAT: Could not check state %02X of slave %i -" + " Timeout while checking!\n", state, + 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. Für jede Domäne werden separate + FMMUs konfiguriert. + + Wenn die entsprechende FMMU bereits konfiguriert ist, wird dies als + Erfolg zurückgegeben. + + \return 0 bei Erfolg, sonst < 0 +*/ + +int ec_slave_set_fmmu(ec_slave_t *slave, /**< EtherCAT-Slave */ + const ec_domain_t *domain, /**< Domäne */ + 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; + + if (slave->fmmu_count >= slave->base_fmmu_count) { + printk(KERN_ERR "EtherCAT: Slave %i supports only %i FMMUs.\n", + slave->ring_position, slave->base_fmmu_count); + 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 */) +{ + printk(KERN_INFO "--- EtherCAT slave information ---\n"); + + if (slave->type) { + printk(KERN_INFO " Vendor \"%s\", Product \"%s\": %s\n", + slave->type->vendor_name, slave->type->product_name, + slave->type->description); + } + else { + printk(KERN_INFO " *** This slave has no type information! ***\n"); + } + + printk(KERN_INFO " Ring position: %i, Station address: 0x%04X\n", + slave->ring_position, slave->station_address); + + printk(KERN_INFO " Base information:\n"); + printk(KERN_INFO " Type %u, Revision %i, Build %i\n", + slave->base_type, slave->base_revision, slave->base_build); + printk(KERN_INFO " Supported FMMUs: %i, Sync managers: %i\n", + slave->base_fmmu_count, slave->base_sync_count); + + printk(KERN_INFO " Slave information interface:\n"); + printk(KERN_INFO " Vendor-ID: 0x%08X, Product code: 0x%08X\n", + slave->sii_vendor_id, slave->sii_product_code); + printk(KERN_INFO " Revision number: 0x%08X, Serial number: 0x%08X\n", + slave->sii_revision_number, slave->sii_serial_number); } /*****************************************************************************/ /* Emacs-Konfiguration ;;; Local Variables: *** -;;; c-basic-offset:2 *** +;;; c-basic-offset:4 *** ;;; End: *** */