master/slave.c
changeset 73 9f4ea66d89a3
parent 55 059a9e712aa7
child 74 9bf603942791
equal deleted inserted replaced
72:7c986b717411 73:9f4ea66d89a3
     7  *  $Id$
     7  *  $Id$
     8  *
     8  *
     9  *****************************************************************************/
     9  *****************************************************************************/
    10 
    10 
    11 #include <linux/module.h>
    11 #include <linux/module.h>
       
    12 #include <linux/delay.h>
    12 
    13 
    13 #include "globals.h"
    14 #include "globals.h"
    14 #include "slave.h"
    15 #include "slave.h"
       
    16 #include "frame.h"
    15 
    17 
    16 /*****************************************************************************/
    18 /*****************************************************************************/
    17 
    19 
    18 /**
    20 /**
    19    EtherCAT-Slave-Konstruktor.
    21    EtherCAT-Slave-Konstruktor.
    20 
    22 */
    21    Initialisiert einen EtherCAT-Slave.
    23 
    22 
    24 void ec_slave_init(ec_slave_t *slave, /**< EtherCAT-Slave */
    23    ACHTUNG! Dieser Konstruktor wird quasi nie aufgerufen. Bitte immer das
    25                    ec_master_t *master /**< EtherCAT-Master */
    24    Makro ECAT_INIT_SLAVE() in ec_slave.h anpassen!
    26                    )
    25 
    27 {
    26    @param slave Zeiger auf den zu initialisierenden Slave
    28     slave->master = master;
    27 */
    29     slave->base_type = 0;
    28 
    30     slave->base_revision = 0;
    29 void ec_slave_init(ec_slave_t *slave)
    31     slave->base_build = 0;
    30 {
    32     slave->base_fmmu_count = 0;
    31   slave->base_type = 0;
    33     slave->base_sync_count = 0;
    32   slave->base_revision = 0;
    34     slave->ring_position = 0;
    33   slave->base_build = 0;
    35     slave->station_address = 0;
    34   slave->ring_position = 0;
    36     slave->sii_vendor_id = 0;
    35   slave->station_address = 0;
    37     slave->sii_product_code = 0;
    36   slave->sii_vendor_id = 0;
    38     slave->sii_revision_number = 0;
    37   slave->sii_product_code = 0;
    39     slave->sii_serial_number = 0;
    38   slave->sii_revision_number = 0;
    40     slave->type = NULL;
    39   slave->sii_serial_number = 0;
    41     slave->registered = 0;
    40   slave->type = NULL;
    42     slave->fmmu_count = 0;
    41   slave->logical_address = 0;
    43 }
    42   slave->process_data = NULL;
    44 
    43   slave->private_data = NULL;
    45 /*****************************************************************************/
    44   slave->configure = NULL;
    46 
    45   slave->registered = 0;
    47 /**
    46   slave->domain = 0;
    48    EtherCAT-Slave-Destruktor.
    47   slave->error_reported = 0;
    49 */
       
    50 
       
    51 void ec_slave_clear(ec_slave_t *slave /**< EtherCAT-Slave */)
       
    52 {
       
    53     // Nichts freizugeben
       
    54 }
       
    55 
       
    56 /*****************************************************************************/
       
    57 
       
    58 /**
       
    59    Liest alle benötigten Informationen aus einem Slave.
       
    60 */
       
    61 
       
    62 int ec_slave_fetch(ec_slave_t *slave /**< EtherCAT-Slave */)
       
    63 {
       
    64     ec_frame_t frame;
       
    65 
       
    66     // Read base data
       
    67     ec_frame_init_nprd(&frame, slave->master, slave->station_address,
       
    68                        0x0000, 6);
       
    69 
       
    70     if (unlikely(ec_frame_send_receive(&frame))) return -1;
       
    71 
       
    72     if (unlikely(frame.working_counter != 1)) {
       
    73         printk(KERN_ERR "EtherCAT: Slave %i did not respond while reading base"
       
    74                " data!\n", slave->ring_position);
       
    75         return -1;
       
    76     }
       
    77 
       
    78     slave->base_type = frame.data[0];
       
    79     slave->base_revision = frame.data[1];
       
    80     slave->base_build = frame.data[2] | (frame.data[3] << 8);
       
    81     slave->base_fmmu_count = frame.data[4];
       
    82     slave->base_sync_count = frame.data[5];
       
    83 
       
    84     if (slave->base_fmmu_count > EC_MAX_FMMUS)
       
    85         slave->base_fmmu_count = EC_MAX_FMMUS;
       
    86 
       
    87     // Read identification from "Slave Information Interface" (SII)
       
    88 
       
    89     if (unlikely(ec_slave_sii_read(slave, 0x0008, &slave->sii_vendor_id))) {
       
    90         printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n");
       
    91         return -1;
       
    92     }
       
    93 
       
    94     if (unlikely(ec_slave_sii_read(slave, 0x000A, &slave->sii_product_code))) {
       
    95         printk(KERN_ERR "EtherCAT: Could not read SII product code!\n");
       
    96         return -1;
       
    97     }
       
    98 
       
    99     if (unlikely(ec_slave_sii_read(slave, 0x000C,
       
   100                                    &slave->sii_revision_number))) {
       
   101         printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n");
       
   102         return -1;
       
   103     }
       
   104 
       
   105     if (unlikely(ec_slave_sii_read(slave, 0x000E,
       
   106                                    &slave->sii_serial_number))) {
       
   107         printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n");
       
   108         return -1;
       
   109     }
       
   110 
       
   111     return 0;
       
   112 }
       
   113 
       
   114 /*****************************************************************************/
       
   115 
       
   116 /**
       
   117    Liest Daten aus dem Slave-Information-Interface
       
   118    eines EtherCAT-Slaves.
       
   119 
       
   120    \return 0 bei Erfolg, sonst < 0
       
   121 */
       
   122 
       
   123 int ec_slave_sii_read(ec_slave_t *slave,
       
   124                       /**< EtherCAT-Slave */
       
   125                       unsigned short int offset,
       
   126                       /**< Adresse des zu lesenden SII-Registers */
       
   127                       unsigned int *target
       
   128                       /**< Zeiger auf einen 4 Byte großen Speicher zum Ablegen
       
   129                          der Daten */
       
   130                       )
       
   131 {
       
   132     ec_frame_t frame;
       
   133     unsigned char data[10];
       
   134     unsigned int tries_left;
       
   135 
       
   136     // Initiate read operation
       
   137 
       
   138     data[0] = 0x00;
       
   139     data[1] = 0x01;
       
   140     data[2] = offset & 0xFF;
       
   141     data[3] = (offset & 0xFF00) >> 8;
       
   142     data[4] = 0x00;
       
   143     data[5] = 0x00;
       
   144 
       
   145     ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x502, 6,
       
   146                        data);
       
   147 
       
   148     if (unlikely(ec_frame_send_receive(&frame))) return -1;
       
   149 
       
   150     if (unlikely(frame.working_counter != 1)) {
       
   151         printk(KERN_ERR "EtherCAT: SII-read - Slave %i did not respond!\n",
       
   152                slave->ring_position);
       
   153         return -1;
       
   154     }
       
   155 
       
   156     // Der Slave legt die Informationen des Slave-Information-Interface
       
   157     // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
       
   158     // den Status auslesen, bis das Bit weg ist.
       
   159 
       
   160     tries_left = 100;
       
   161     while (likely(tries_left))
       
   162     {
       
   163         udelay(10);
       
   164 
       
   165         ec_frame_init_nprd(&frame, slave->master, slave->station_address, 0x502,
       
   166                            10);
       
   167 
       
   168         if (unlikely(ec_frame_send_receive(&frame))) return -1;
       
   169 
       
   170         if (unlikely(frame.working_counter != 1)) {
       
   171             printk(KERN_ERR "EtherCAT: SII-read status -"
       
   172                    " Slave %i did not respond!\n", slave->ring_position);
       
   173             return -1;
       
   174         }
       
   175 
       
   176         if (likely((frame.data[1] & 0x81) == 0)) {
       
   177             memcpy(target, frame.data + 6, 4);
       
   178             break;
       
   179         }
       
   180 
       
   181         tries_left--;
       
   182     }
       
   183 
       
   184     if (unlikely(!tries_left)) {
       
   185         printk(KERN_WARNING "EtherCAT: SSI-read. Slave %i timed out!\n",
       
   186                slave->ring_position);
       
   187         return -1;
       
   188     }
       
   189 
       
   190     return 0;
       
   191 }
       
   192 
       
   193 /*****************************************************************************/
       
   194 
       
   195 /**
       
   196    Bestätigt einen Fehler beim Zustandswechsel.
       
   197 
       
   198    FIXME Funktioniert noch nicht...
       
   199 */
       
   200 
       
   201 void ec_slave_state_ack(ec_slave_t *slave,
       
   202                         /**< Slave, dessen Zustand geändert werden soll */
       
   203                         uint8_t state
       
   204                         /**< Alter Zustand */
       
   205                         )
       
   206 {
       
   207     ec_frame_t frame;
       
   208     unsigned char data[2];
       
   209     unsigned int tries_left;
       
   210 
       
   211     data[0] = state | EC_ACK;
       
   212     data[1] = 0x00;
       
   213 
       
   214     ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120,
       
   215                        2, data);
       
   216 
       
   217     if (unlikely(ec_frame_send_receive(&frame) != 0)) {
       
   218         printk(KERN_ERR "EtherCAT: Could no acknowledge state %02X - Unable to"
       
   219                " send!\n", state);
       
   220         return;
       
   221     }
       
   222 
       
   223     if (unlikely(frame.working_counter != 1)) {
       
   224         printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X - Slave"
       
   225                " %i did not respond!\n", state, slave->ring_position);
       
   226         return;
       
   227     }
       
   228 
       
   229     tries_left = 100;
       
   230     while (likely(tries_left))
       
   231     {
       
   232         udelay(10);
       
   233 
       
   234         ec_frame_init_nprd(&frame, slave->master, slave->station_address,
       
   235                            0x0130, 2);
       
   236 
       
   237         if (unlikely(ec_frame_send_receive(&frame) != 0)) {
       
   238             printk(KERN_ERR "EtherCAT: Could not check state acknowledgement"
       
   239                    " %02X - Unable to send!\n", state);
       
   240             return;
       
   241         }
       
   242 
       
   243         if (unlikely(frame.working_counter != 1)) {
       
   244             printk(KERN_ERR "EtherCAT: Could not check state acknowledgement"
       
   245                    " %02X - Slave %i did not respond!\n", state,
       
   246                    slave->ring_position);
       
   247             return;
       
   248         }
       
   249 
       
   250         if (unlikely(frame.data[0] != state)) {
       
   251             printk(KERN_ERR "EtherCAT: Could not acknowledge state %02X on"
       
   252                    " slave %i (code %02X)!\n", state, slave->ring_position,
       
   253                    frame.data[0]);
       
   254             return;
       
   255         }
       
   256 
       
   257         if (likely(frame.data[0] == state)) {
       
   258             printk(KERN_INFO "EtherCAT: Acknowleged state %02X on slave %i.\n",
       
   259                    state, slave->ring_position);
       
   260             return;
       
   261         }
       
   262 
       
   263         tries_left--;
       
   264     }
       
   265 
       
   266     if (unlikely(!tries_left)) {
       
   267         printk(KERN_ERR "EtherCAT: Could not check state acknowledgement %02X"
       
   268                " of slave %i - Timeout while checking!\n", state,
       
   269                slave->ring_position);
       
   270         return;
       
   271     }
       
   272 }
       
   273 
       
   274 /*****************************************************************************/
       
   275 
       
   276 /**
       
   277    Ändert den Zustand eines Slaves.
       
   278 
       
   279    \return 0 bei Erfolg, sonst < 0
       
   280 */
       
   281 
       
   282 int ec_slave_state_change(ec_slave_t *slave,
       
   283                           /**< Slave, dessen Zustand geändert werden soll */
       
   284                           uint8_t state
       
   285                           /**< Neuer Zustand */
       
   286                           )
       
   287 {
       
   288     ec_frame_t frame;
       
   289     unsigned char data[2];
       
   290     unsigned int tries_left;
       
   291 
       
   292     data[0] = state;
       
   293     data[1] = 0x00;
       
   294 
       
   295     ec_frame_init_npwr(&frame, slave->master, slave->station_address, 0x0120,
       
   296                        2, data);
       
   297 
       
   298     if (unlikely(ec_frame_send_receive(&frame) != 0)) {
       
   299         printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to"
       
   300                " send!\n", state);
       
   301         return -1;
       
   302     }
       
   303 
       
   304     if (unlikely(frame.working_counter != 1)) {
       
   305         printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i did not"
       
   306                " respond!\n", state, slave->ring_position);
       
   307         return -1;
       
   308     }
       
   309 
       
   310     tries_left = 100;
       
   311     while (likely(tries_left))
       
   312     {
       
   313         udelay(10);
       
   314 
       
   315         ec_frame_init_nprd(&frame, slave->master, slave->station_address,
       
   316                            0x0130, 2);
       
   317 
       
   318         if (unlikely(ec_frame_send_receive(&frame) != 0)) {
       
   319             printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to"
       
   320                    " send!\n", state);
       
   321             return -1;
       
   322         }
       
   323 
       
   324         if (unlikely(frame.working_counter != 1)) {
       
   325             printk(KERN_ERR "EtherCAT: Could not check state %02X - Slave %i"
       
   326                    " did not respond!\n", state, slave->ring_position);
       
   327             return -1;
       
   328         }
       
   329 
       
   330         if (unlikely(frame.data[0] & 0x10)) { // State change error
       
   331             printk(KERN_ERR "EtherCAT: Could not set state %02X - Slave %i"
       
   332                    " refused state change (code %02X)!\n", state,
       
   333                    slave->ring_position, frame.data[0]);
       
   334             ec_slave_state_ack(slave, frame.data[0] & 0x0F);
       
   335             return -1;
       
   336         }
       
   337 
       
   338         if (likely(frame.data[0] == (state & 0x0F))) {
       
   339             // State change successful
       
   340             break;
       
   341         }
       
   342 
       
   343         tries_left--;
       
   344     }
       
   345 
       
   346     if (unlikely(!tries_left)) {
       
   347         printk(KERN_ERR "EtherCAT: Could not check state %02X of slave %i -"
       
   348                " Timeout while checking!\n", state,
       
   349                slave->ring_position);
       
   350         return -1;
       
   351     }
       
   352 
       
   353     return 0;
       
   354 }
       
   355 
       
   356 /*****************************************************************************/
       
   357 
       
   358 /**
       
   359    Merkt eine FMMU-Konfiguration vor.
       
   360 
       
   361    Die FMMU wird so konfiguriert, dass sie den gesamten Datenbereich des
       
   362    entsprechenden Sync-Managers abdeckt. Für jede Domäne werden separate
       
   363    FMMUs konfiguriert.
       
   364 
       
   365    Wenn die entsprechende FMMU bereits konfiguriert ist, wird dies als
       
   366    Erfolg zurückgegeben.
       
   367 
       
   368    \return 0 bei Erfolg, sonst < 0
       
   369 */
       
   370 
       
   371 int ec_slave_set_fmmu(ec_slave_t *slave, /**< EtherCAT-Slave */
       
   372                       const ec_domain_t *domain, /**< Domäne */
       
   373                       const ec_sync_t *sync  /**< Sync-Manager */
       
   374                       )
       
   375 {
       
   376     unsigned int i;
       
   377 
       
   378     // FMMU schon vorgemerkt?
       
   379     for (i = 0; i < slave->fmmu_count; i++)
       
   380         if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync)
       
   381             return 0;
       
   382 
       
   383     if (slave->fmmu_count >= slave->base_fmmu_count) {
       
   384         printk(KERN_ERR "EtherCAT: Slave %i supports only %i FMMUs.\n",
       
   385                slave->ring_position, slave->base_fmmu_count);
       
   386         return -1;
       
   387     }
       
   388 
       
   389     slave->fmmus[slave->fmmu_count].domain = domain;
       
   390     slave->fmmus[slave->fmmu_count].sync = sync;
       
   391     slave->fmmus[slave->fmmu_count].logical_start_address = 0;
       
   392     slave->fmmu_count++;
       
   393     slave->registered = 1;
       
   394 
       
   395     return 0;
       
   396 }
       
   397 
       
   398 /*****************************************************************************/
       
   399 
       
   400 /**
       
   401    Gibt alle Informationen über einen EtherCAT-Slave aus.
       
   402 */
       
   403 
       
   404 void ec_slave_print(const ec_slave_t *slave /**< EtherCAT-Slave */)
       
   405 {
       
   406     printk(KERN_INFO "--- EtherCAT slave information ---\n");
       
   407 
       
   408     if (slave->type) {
       
   409         printk(KERN_INFO "  Vendor \"%s\", Product \"%s\": %s\n",
       
   410                slave->type->vendor_name, slave->type->product_name,
       
   411                slave->type->description);
       
   412     }
       
   413     else {
       
   414         printk(KERN_INFO "  *** This slave has no type information! ***\n");
       
   415     }
       
   416 
       
   417     printk(KERN_INFO "  Ring position: %i, Station address: 0x%04X\n",
       
   418            slave->ring_position, slave->station_address);
       
   419 
       
   420     printk(KERN_INFO "  Base information:\n");
       
   421     printk(KERN_INFO "    Type %u, Revision %i, Build %i\n",
       
   422            slave->base_type, slave->base_revision, slave->base_build);
       
   423     printk(KERN_INFO "    Supported FMMUs: %i, Sync managers: %i\n",
       
   424            slave->base_fmmu_count, slave->base_sync_count);
       
   425 
       
   426     printk(KERN_INFO "  Slave information interface:\n");
       
   427     printk(KERN_INFO "    Vendor-ID: 0x%08X, Product code: 0x%08X\n",
       
   428            slave->sii_vendor_id, slave->sii_product_code);
       
   429     printk(KERN_INFO "    Revision number: 0x%08X, Serial number: 0x%08X\n",
       
   430            slave->sii_revision_number, slave->sii_serial_number);
    48 }
   431 }
    49 
   432 
    50 /*****************************************************************************/
   433 /*****************************************************************************/
    51 
   434 
    52 /* Emacs-Konfiguration
   435 /* Emacs-Konfiguration
    53 ;;; Local Variables: ***
   436 ;;; Local Variables: ***
    54 ;;; c-basic-offset:2 ***
   437 ;;; c-basic-offset:4 ***
    55 ;;; End: ***
   438 ;;; End: ***
    56 */
   439 */