master/domain.c
changeset 73 9f4ea66d89a3
parent 58 21b7342e2a90
child 76 9dc136e3801c
equal deleted inserted replaced
72:7c986b717411 73:9f4ea66d89a3
     5  *  Methoden für Gruppen von EtherCAT-Slaves.
     5  *  Methoden für Gruppen von EtherCAT-Slaves.
     6  *
     6  *
     7  *  $Id$
     7  *  $Id$
     8  *
     8  *
     9  *****************************************************************************/
     9  *****************************************************************************/
    10 
       
    11 #include <linux/module.h>
       
    12 
    10 
    13 #include "globals.h"
    11 #include "globals.h"
    14 #include "domain.h"
    12 #include "domain.h"
       
    13 #include "master.h"
    15 
    14 
    16 /*****************************************************************************/
    15 /*****************************************************************************/
    17 
    16 
    18 /**
    17 /**
    19    Konstruktor einer EtherCAT-Domäne.
    18    Konstruktor einer EtherCAT-Domäne.
    20 
    19 */
    21    @param dom Zeiger auf die zu initialisierende Domäne
    20 
    22 */
    21 void ec_domain_init(ec_domain_t *domain, /**< Domäne */
    23 
    22                     ec_master_t *master, /**< Zugehöriger Master */
    24 void ec_domain_init(ec_domain_t *dom)
    23                     ec_domain_mode_t mode, /**< Synchron/Asynchron */
    25 {
    24                     unsigned int timeout_us /**< Timeout in Mikrosekunden */
    26   dom->number = -1;
    25                     )
    27   dom->data_size = 0;
    26 {
    28   dom->logical_offset = 0;
    27     domain->master = master;
    29   dom->response_count = 0xFFFFFFFF;
    28     domain->mode = mode;
    30 
    29     domain->timeout_us = timeout_us;
    31   memset(dom->data, 0x00, EC_FRAME_SIZE);
    30 
    32 }
    31     domain->data = NULL;
       
    32     domain->data_size = 0;
       
    33     domain->base_address = 0;
       
    34     domain->response_count = 0xFFFFFFFF;
       
    35 
       
    36     INIT_LIST_HEAD(&domain->field_regs);
       
    37 }
       
    38 
       
    39 /*****************************************************************************/
       
    40 
       
    41 /**
       
    42    Destruktor einer EtherCAT-Domäne.
       
    43 */
       
    44 
       
    45 void ec_domain_clear(ec_domain_t *domain /**< Domäne */)
       
    46 {
       
    47     ec_field_reg_t *field_reg, *next;
       
    48 
       
    49     if (domain->data) {
       
    50         kfree(domain->data);
       
    51         domain->data = NULL;
       
    52     }
       
    53 
       
    54     // Liste der registrierten Datenfelder löschen
       
    55     list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
       
    56         kfree(field_reg);
       
    57     }
       
    58 }
       
    59 
       
    60 /*****************************************************************************/
       
    61 
       
    62 /**
       
    63    Registriert ein Feld in einer Domäne.
       
    64 
       
    65    \returns 0 bei Erfolg, < 0 bei Fehler
       
    66 */
       
    67 
       
    68 int ec_domain_reg_field(ec_domain_t *domain, /**< Domäne */
       
    69                         ec_slave_t *slave, /**< Slave */
       
    70                         const ec_sync_t *sync, /**< Sync-Manager */
       
    71                         uint32_t field_offset, /**< Datenfeld-Offset */
       
    72                         void **data_ptr /**< Adresse des Prozessdatenzeigers */
       
    73                         )
       
    74 {
       
    75     ec_field_reg_t *field_reg;
       
    76 
       
    77     if (!(field_reg = (ec_field_reg_t *) kmalloc(sizeof(ec_field_reg_t),
       
    78                                                  GFP_KERNEL))) {
       
    79         printk(KERN_ERR "EtherCAT: Failed to allocate field registration.\n");
       
    80         return -1;
       
    81     }
       
    82 
       
    83     if (ec_slave_set_fmmu(slave, domain, sync)) {
       
    84         printk(KERN_ERR "EtherCAT: FMMU configuration failed.\n");
       
    85         kfree(field_reg);
       
    86         return -1;
       
    87     }
       
    88 
       
    89     field_reg->slave = slave;
       
    90     field_reg->sync = sync;
       
    91     field_reg->field_offset = field_offset;
       
    92     field_reg->data_ptr = data_ptr;
       
    93 
       
    94     list_add_tail(&field_reg->list, &domain->field_regs);
       
    95 
       
    96     return 0;
       
    97 }
       
    98 
       
    99 /*****************************************************************************/
       
   100 
       
   101 /**
       
   102     \returns 0 bei Erfolg, < 0 bei Fehler
       
   103 */
       
   104 
       
   105 int ec_domain_alloc(ec_domain_t *domain, /**< Domäne */
       
   106                     uint32_t base_address /**< Logische Basisadresse */
       
   107                     )
       
   108 {
       
   109     ec_field_reg_t *field_reg, *next;
       
   110     ec_slave_t *slave;
       
   111     ec_fmmu_t *fmmu;
       
   112     unsigned int i, j, found, data_offset;
       
   113 
       
   114     if (domain->data) {
       
   115         printk(KERN_ERR "EtherCAT: Domain already allocated!\n");
       
   116         return -1;
       
   117     }
       
   118 
       
   119     domain->base_address = base_address;
       
   120 
       
   121     // Größe der Prozessdaten berechnen
       
   122     // und logische Adressen der FMMUs setzen
       
   123     domain->data_size = 0;
       
   124     for (i = 0; i < domain->master->slave_count; i++) {
       
   125         slave = &domain->master->slaves[i];
       
   126         for (j = 0; j < slave->fmmu_count; j++) {
       
   127             fmmu = &slave->fmmus[j];
       
   128             if (fmmu->domain == domain) {
       
   129                 fmmu->logical_start_address = base_address + domain->data_size;
       
   130                 domain->data_size += fmmu->sync->size;
       
   131             }
       
   132         }
       
   133     }
       
   134 
       
   135     if (!domain->data_size) {
       
   136         printk(KERN_WARNING "EtherCAT: Domain 0x%08X contains no data!\n",
       
   137                (u32) domain);
       
   138     }
       
   139     else {
       
   140         // Prozessdaten allozieren
       
   141         if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
       
   142             printk(KERN_ERR "EtherCAT: Failed to allocate domain data!\n");
       
   143             return -1;
       
   144         }
       
   145 
       
   146         // Prozessdaten mit Nullen vorbelegen
       
   147         memset(domain->data, 0x00, domain->data_size);
       
   148 
       
   149         // Alle Prozessdatenzeiger setzen
       
   150         list_for_each_entry(field_reg, &domain->field_regs, list) {
       
   151             found = 0;
       
   152             for (i = 0; i < field_reg->slave->fmmu_count; i++) {
       
   153                 fmmu = &field_reg->slave->fmmus[i];
       
   154                 if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
       
   155                     data_offset = fmmu->logical_start_address - base_address
       
   156                         + field_reg->field_offset;
       
   157                     *field_reg->data_ptr = domain->data + data_offset;
       
   158                     found = 1;
       
   159                     break;
       
   160                 }
       
   161             }
       
   162 
       
   163             if (!found) { // Sollte nie passieren
       
   164                 printk(KERN_ERR "EtherCAT: FMMU not found. Please report!\n");
       
   165                 return -1;
       
   166             }
       
   167         }
       
   168     }
       
   169 
       
   170     // Registrierungsliste wird jetzt nicht mehr gebraucht.
       
   171     list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
       
   172         kfree(field_reg);
       
   173     }
       
   174     INIT_LIST_HEAD(&domain->field_regs); // wichtig!
       
   175 
       
   176     return 0;
       
   177 }
       
   178 
       
   179 /******************************************************************************
       
   180  *
       
   181  * Echtzeitschnittstelle
       
   182  *
       
   183  *****************************************************************************/
       
   184 
       
   185 /**
       
   186    Registriert einer Domäne ein Datenfeld hinzu.
       
   187 
       
   188    \return Zeiger auf den Slave bei Erfolg, sonst NULL
       
   189 */
       
   190 
       
   191 ec_slave_t *EtherCAT_rt_register_slave_field(
       
   192     ec_domain_t *domain, /**< Domäne */
       
   193     const char *address, /**< ASCII-Addresse des Slaves, siehe ec_address() */
       
   194     const char *vendor_name, /**< Herstellername */
       
   195     const char *product_name, /**< Produktname */
       
   196     void **data_ptr, /**< Adresse des Zeigers auf die Prozessdaten */
       
   197     ec_field_type_t field_type, /**< Typ des Datenfeldes */
       
   198     unsigned int field_index, /**< Gibt an, ab welchem Feld mit Typ
       
   199                                  \a field_type gezählt werden soll. */
       
   200     unsigned int field_count /**< Anzahl Felder des selben Typs */
       
   201     )
       
   202 {
       
   203     ec_slave_t *slave;
       
   204     const ec_slave_type_t *type;
       
   205     ec_master_t *master;
       
   206     const ec_sync_t *sync;
       
   207     const ec_field_t *field;
       
   208     unsigned int field_idx, found, i, j;
       
   209     uint32_t field_offset;
       
   210 
       
   211     if (!field_count) {
       
   212         printk(KERN_ERR "EtherCAT: field_count may not be 0!\n");
       
   213         return NULL;
       
   214     }
       
   215 
       
   216     master = domain->master;
       
   217 
       
   218     // Adresse übersetzen
       
   219     if ((slave = ec_address(master, address)) == NULL) return NULL;
       
   220 
       
   221     if (!(type = slave->type)) {
       
   222         printk(KERN_ERR "EtherCAT: Slave \"%s\" (position %i) has unknown"
       
   223                " type!\n", address, slave->ring_position);
       
   224         return NULL;
       
   225     }
       
   226 
       
   227     if (strcmp(vendor_name, type->vendor_name) ||
       
   228         strcmp(product_name, type->product_name)) {
       
   229         printk(KERN_ERR "EtherCAT: Invalid slave type at position %i -"
       
   230                " Requested: \"%s %s\", found: \"%s %s\".\n",
       
   231                slave->ring_position, vendor_name, product_name,
       
   232                type->vendor_name, type->product_name);
       
   233         return NULL;
       
   234     }
       
   235 
       
   236     field_idx = 0;
       
   237     found = 0;
       
   238     for (i = 0; type->sync_managers[i] && !found; i++) {
       
   239         sync = type->sync_managers[i];
       
   240         field_offset = 0;
       
   241         for (j = 0; sync->fields[j]; j++) {
       
   242             field = sync->fields[j];
       
   243             if (field->type == field_type) {
       
   244                 if (field_idx == field_index) {
       
   245                     ec_domain_reg_field(domain, slave, sync, field_offset,
       
   246                                         data_ptr++);
       
   247                     if (!(--field_count)) return slave;
       
   248                 }
       
   249                 field_idx++;
       
   250             }
       
   251             field_offset += field->size;
       
   252         }
       
   253     }
       
   254 
       
   255     printk(KERN_ERR "EtherCAT: Slave %i (\"%s %s\") has less than %i fields of"
       
   256            " type %i, starting at %i!\n", slave->ring_position,
       
   257            vendor_name, product_name, field_count, field_type, field_index);
       
   258     return NULL;
       
   259 }
       
   260 
       
   261 /*****************************************************************************/
       
   262 
       
   263 /**
       
   264    Sendet und empfängt Prozessdaten der angegebenen Domäne
       
   265 
       
   266    \return 0 bei Erfolg, sonst < 0
       
   267 */
       
   268 
       
   269 int EtherCAT_rt_domain_xio(ec_domain_t *domain /**< Domäne */)
       
   270 {
       
   271     unsigned int offset, size, working_counter_sum;
       
   272     unsigned long start_ticks, end_ticks, timeout_ticks;
       
   273     ec_master_t *master;
       
   274     ec_frame_t *frame;
       
   275 
       
   276     master = domain->master;
       
   277     frame = &domain->frame;
       
   278     working_counter_sum = 0;
       
   279 
       
   280     ec_output_lost_frames(master); // Evtl. verlorene Frames ausgeben
       
   281 
       
   282     rdtscl(start_ticks); // Sendezeit nehmen
       
   283     timeout_ticks = domain->timeout_us * cpu_khz / 1000;
       
   284 
       
   285     offset = 0;
       
   286     while (offset < domain->data_size)
       
   287     {
       
   288         size = domain->data_size - offset;
       
   289         if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
       
   290 
       
   291         ec_frame_init_lrw(frame, master, domain->base_address + offset, size,
       
   292                           domain->data + offset);
       
   293 
       
   294         if (unlikely(ec_frame_send(frame) < 0)) {
       
   295             printk(KERN_ERR "EtherCAT: Could not send process data"
       
   296                    " command!\n");
       
   297             return -1;
       
   298         }
       
   299 
       
   300         // Warten
       
   301         do {
       
   302             ec_device_call_isr(&master->device);
       
   303             rdtscl(end_ticks); // Empfangszeit nehmen
       
   304         }
       
   305         while (unlikely(master->device.state == EC_DEVICE_STATE_SENT
       
   306                         && end_ticks - start_ticks < timeout_ticks));
       
   307 
       
   308         master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
       
   309 
       
   310         if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
       
   311             master->device.state = EC_DEVICE_STATE_READY;
       
   312             master->frames_lost++;
       
   313             ec_output_lost_frames(master);
       
   314             return -1;
       
   315         }
       
   316 
       
   317         if (unlikely(ec_frame_receive(frame) < 0)) {
       
   318             printk(KERN_ERR "EtherCAT: Receive error!\n");
       
   319             return -1;
       
   320         }
       
   321 
       
   322         if (unlikely(frame->state != ec_frame_received)) {
       
   323             printk(KERN_WARNING "EtherCAT: Process data command not"
       
   324                    " received!\n");
       
   325             return -1;
       
   326         }
       
   327 
       
   328         working_counter_sum += frame->working_counter;
       
   329 
       
   330         // Daten vom Rahmen in den Prozessdatenspeicher kopieren
       
   331         memcpy(domain->data + offset, frame->data, size);
       
   332 
       
   333         offset += size;
       
   334     }
       
   335 
       
   336     if (working_counter_sum != domain->response_count) {
       
   337         domain->response_count = working_counter_sum;
       
   338         printk(KERN_INFO "EtherCAT: Domain %08X state change - %i slaves"
       
   339                " responding.\n", (unsigned int) domain, working_counter_sum);
       
   340     }
       
   341 
       
   342     return 0;
       
   343 }
       
   344 
       
   345 /*****************************************************************************/
       
   346 
       
   347 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field);
       
   348 EXPORT_SYMBOL(EtherCAT_rt_domain_xio);
    33 
   349 
    34 /*****************************************************************************/
   350 /*****************************************************************************/
    35 
   351 
    36 /* Emacs-Konfiguration
   352 /* Emacs-Konfiguration
    37 ;;; Local Variables: ***
   353 ;;; Local Variables: ***
    38 ;;; c-basic-offset:2 ***
   354 ;;; c-basic-offset:4 ***
    39 ;;; End: ***
   355 ;;; End: ***
    40 */
   356 */