master/domain.c
changeset 98 f564d0929292
parent 97 e6264685dd7b
child 101 b0c19892145a
equal deleted inserted replaced
97:e6264685dd7b 98:f564d0929292
     9  *****************************************************************************/
     9  *****************************************************************************/
    10 
    10 
    11 #include "globals.h"
    11 #include "globals.h"
    12 #include "domain.h"
    12 #include "domain.h"
    13 #include "master.h"
    13 #include "master.h"
       
    14 
       
    15 void ec_domain_clear_field_regs(ec_domain_t *);
    14 
    16 
    15 /*****************************************************************************/
    17 /*****************************************************************************/
    16 
    18 
    17 /**
    19 /**
    18    Konstruktor einer EtherCAT-Domäne.
    20    Konstruktor einer EtherCAT-Domäne.
    28     domain->mode = mode;
    30     domain->mode = mode;
    29     domain->timeout_us = timeout_us;
    31     domain->timeout_us = timeout_us;
    30 
    32 
    31     domain->data = NULL;
    33     domain->data = NULL;
    32     domain->data_size = 0;
    34     domain->data_size = 0;
       
    35     domain->commands = NULL;
       
    36     domain->command_count = 0;
    33     domain->base_address = 0;
    37     domain->base_address = 0;
    34     domain->response_count = 0xFFFFFFFF;
    38     domain->response_count = 0xFFFFFFFF;
    35 
    39 
    36     INIT_LIST_HEAD(&domain->field_regs);
    40     INIT_LIST_HEAD(&domain->field_regs);
    37 }
    41 }
    42    Destruktor einer EtherCAT-Domäne.
    46    Destruktor einer EtherCAT-Domäne.
    43 */
    47 */
    44 
    48 
    45 void ec_domain_clear(ec_domain_t *domain /**< Domäne */)
    49 void ec_domain_clear(ec_domain_t *domain /**< Domäne */)
    46 {
    50 {
    47     ec_field_reg_t *field_reg, *next;
    51     if (domain->data) kfree(domain->data);
    48 
    52     if (domain->commands) kfree(domain->commands);
    49     if (domain->data) {
    53 
    50         kfree(domain->data);
    54     ec_domain_clear_field_regs(domain);
    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 }
    55 }
    59 
    56 
    60 /*****************************************************************************/
    57 /*****************************************************************************/
    61 
    58 
    62 /**
    59 /**
    97 }
    94 }
    98 
    95 
    99 /*****************************************************************************/
    96 /*****************************************************************************/
   100 
    97 
   101 /**
    98 /**
       
    99    Gibt die Liste der registrierten Datenfelder frei.
       
   100 */
       
   101 
       
   102 void ec_domain_clear_field_regs(ec_domain_t *domain)
       
   103 {
       
   104     ec_field_reg_t *field_reg, *next;
       
   105 
       
   106     list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
       
   107         list_del(&field_reg->list);
       
   108         kfree(field_reg);
       
   109     }
       
   110 }
       
   111 
       
   112 /*****************************************************************************/
       
   113 
       
   114 /**
   102    Erzeugt eine Domäne.
   115    Erzeugt eine Domäne.
   103 
   116 
   104    Reserviert den Speicher einer Domäne, berechnet die logischen Adressen der
   117    Reserviert den Speicher einer Domäne, berechnet die logischen Adressen der
   105    FMMUs und setzt die Prozessdatenzeiger der registrierten Felder.
   118    FMMUs und setzt die Prozessdatenzeiger der registrierten Felder.
   106 
   119 
   109 
   122 
   110 int ec_domain_alloc(ec_domain_t *domain, /**< Domäne */
   123 int ec_domain_alloc(ec_domain_t *domain, /**< Domäne */
   111                     uint32_t base_address /**< Logische Basisadresse */
   124                     uint32_t base_address /**< Logische Basisadresse */
   112                     )
   125                     )
   113 {
   126 {
   114     ec_field_reg_t *field_reg, *next;
   127     ec_field_reg_t *field_reg;
   115     ec_slave_t *slave;
   128     ec_slave_t *slave;
   116     ec_fmmu_t *fmmu;
   129     ec_fmmu_t *fmmu;
   117     unsigned int i, j, found, data_offset;
   130     unsigned int i, j, found, data_offset;
   118 
   131 
   119     if (domain->data) {
   132     if (domain->data) {
   137         }
   150         }
   138     }
   151     }
   139 
   152 
   140     if (!domain->data_size) {
   153     if (!domain->data_size) {
   141         EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain);
   154         EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain);
   142     }
   155         ec_domain_clear_field_regs(domain);
   143     else {
   156         return 0;
   144         // Prozessdaten allozieren
   157     }
   145         if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
   158 
   146             EC_ERR("Failed to allocate domain data!\n");
   159     // Prozessdaten allozieren
       
   160     if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) {
       
   161         EC_ERR("Failed to allocate domain data!\n");
       
   162         return -1;
       
   163     }
       
   164 
       
   165     // Prozessdaten mit Nullen vorbelegen
       
   166     memset(domain->data, 0x00, domain->data_size);
       
   167 
       
   168     // Alle Prozessdatenzeiger setzen
       
   169     list_for_each_entry(field_reg, &domain->field_regs, list) {
       
   170         found = 0;
       
   171         for (i = 0; i < field_reg->slave->fmmu_count; i++) {
       
   172             fmmu = &field_reg->slave->fmmus[i];
       
   173             if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
       
   174                 data_offset = fmmu->logical_start_address - base_address
       
   175                     + field_reg->field_offset;
       
   176                 *field_reg->data_ptr = domain->data + data_offset;
       
   177                 found = 1;
       
   178                 break;
       
   179             }
       
   180         }
       
   181 
       
   182         if (!found) { // Sollte nie passieren
       
   183             EC_ERR("FMMU not found. Please report!\n");
   147             return -1;
   184             return -1;
   148         }
   185         }
   149 
   186     }
   150         // Prozessdaten mit Nullen vorbelegen
   187 
   151         memset(domain->data, 0x00, domain->data_size);
   188     // Kommando-Array erzeugen
   152 
   189     domain->command_count = domain->data_size / EC_MAX_DATA_SIZE + 1;
   153         // Alle Prozessdatenzeiger setzen
   190     if (!(domain->commands = (ec_command_t *) kmalloc(sizeof(ec_command_t)
   154         list_for_each_entry(field_reg, &domain->field_regs, list) {
   191                                                       * domain->command_count,
   155             found = 0;
   192                                                       GFP_KERNEL))) {
   156             for (i = 0; i < field_reg->slave->fmmu_count; i++) {
   193         EC_ERR("Failed to allocate domain command array!\n");
   157                 fmmu = &field_reg->slave->fmmus[i];
   194         return -1;
   158                 if (fmmu->domain == domain && fmmu->sync == field_reg->sync) {
   195     }
   159                     data_offset = fmmu->logical_start_address - base_address
   196 
   160                         + field_reg->field_offset;
   197     EC_INFO("Domain %X - Allocated %i bytes in %i command(s)\n",
   161                     *field_reg->data_ptr = domain->data + data_offset;
   198             (u32) domain, domain->data_size, domain->command_count);
   162                     found = 1;
   199 
   163                     break;
   200     ec_domain_clear_field_regs(domain);
   164                 }
       
   165             }
       
   166 
       
   167             if (!found) { // Sollte nie passieren
       
   168                 EC_ERR("FMMU not found. Please report!\n");
       
   169                 return -1;
       
   170             }
       
   171         }
       
   172     }
       
   173 
       
   174     // Registrierungsliste wird jetzt nicht mehr gebraucht.
       
   175     list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) {
       
   176         kfree(field_reg);
       
   177     }
       
   178     INIT_LIST_HEAD(&domain->field_regs); // wichtig!
       
   179 
   201 
   180     return 0;
   202     return 0;
   181 }
   203 }
   182 
   204 
   183 /*****************************************************************************/
   205 /*****************************************************************************/
   190                               unsigned int count /**< Neue Anzahl */
   212                               unsigned int count /**< Neue Anzahl */
   191                               )
   213                               )
   192 {
   214 {
   193     if (count != domain->response_count) {
   215     if (count != domain->response_count) {
   194         domain->response_count = count;
   216         domain->response_count = count;
   195         EC_INFO("Domain %08X state change - %i slaves responding.\n",
   217         EC_INFO("Domain %08X state change - %i slave%s responding.\n",
   196                 (u32) domain, count);
   218                 (u32) domain, count, count == 1 ? "" : "s");
   197     }
   219     }
   198 }
   220 }
   199 
   221 
   200 /******************************************************************************
   222 /******************************************************************************
   201  *
   223  *
   207    Registriert ein Datenfeld innerhalb einer Domäne.
   229    Registriert ein Datenfeld innerhalb einer Domäne.
   208 
   230 
   209    \return Zeiger auf den Slave bei Erfolg, sonst NULL
   231    \return Zeiger auf den Slave bei Erfolg, sonst NULL
   210 */
   232 */
   211 
   233 
   212 ec_slave_t *EtherCAT_rt_register_slave_field(
   234 ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain,
   213     ec_domain_t *domain, /**< Domäne */
   235                                              /**< Domäne */
   214     const char *address, /**< ASCII-Addresse des Slaves, siehe ec_address() */
   236                                              const char *address,
   215     const char *vendor_name, /**< Herstellername */
   237                                              /**< ASCII-Addresse des Slaves,
   216     const char *product_name, /**< Produktname */
   238                                                 siehe ec_master_slave_address()
   217     void **data_ptr, /**< Adresse des Zeigers auf die Prozessdaten */
   239                                              */
   218     ec_field_type_t field_type, /**< Typ des Datenfeldes */
   240                                              const char *vendor_name,
   219     unsigned int field_index, /**< Gibt an, ab welchem Feld mit Typ
   241                                              /**< Herstellername */
   220                                  \a field_type gezählt werden soll. */
   242                                              const char *product_name,
   221     unsigned int field_count /**< Anzahl Felder des selben Typs */
   243                                              /**< Produktname */
   222     )
   244                                              void **data_ptr,
       
   245                                              /**< Adresse des Zeigers auf die
       
   246                                                 Prozessdaten */
       
   247                                              ec_field_type_t field_type,
       
   248                                              /**< Typ des Datenfeldes */
       
   249                                              unsigned int field_index,
       
   250                                              /**< Gibt an, ab welchem Feld mit
       
   251                                                 Typ \a field_type gezählt
       
   252                                                 werden soll. */
       
   253                                              unsigned int field_count
       
   254                                              /**< Anzahl Felder selben Typs */
       
   255                                              )
   223 {
   256 {
   224     ec_slave_t *slave;
   257     ec_slave_t *slave;
   225     const ec_slave_type_t *type;
   258     const ec_slave_type_t *type;
   226     ec_master_t *master;
   259     ec_master_t *master;
   227     const ec_sync_t *sync;
   260     const ec_sync_t *sync;
   235     }
   268     }
   236 
   269 
   237     master = domain->master;
   270     master = domain->master;
   238 
   271 
   239     // Adresse übersetzen
   272     // Adresse übersetzen
   240     if ((slave = ec_address(master, address)) == NULL) return NULL;
   273     if (!(slave = ec_master_slave_address(master, address))) return NULL;
   241 
   274 
   242     if (!(type = slave->type)) {
   275     if (!(type = slave->type)) {
   243         EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
   276         EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address,
   244                slave->ring_position);
   277                slave->ring_position);
   245         return NULL;
   278         return NULL;
   278 }
   311 }
   279 
   312 
   280 /*****************************************************************************/
   313 /*****************************************************************************/
   281 
   314 
   282 /**
   315 /**
   283    Sendet und empfängt Prozessdaten der angegebenen Domäne.
   316    Registriert eine ganze Liste von Datenfeldern innerhalb einer Domäne.
       
   317 
       
   318    Achtung: Die Liste muss mit einer NULL-Struktur ({}) abgeschlossen sein!
   284 
   319 
   285    \return 0 bei Erfolg, sonst < 0
   320    \return 0 bei Erfolg, sonst < 0
   286 */
   321 */
   287 
   322 
   288 int EtherCAT_rt_domain_xio(ec_domain_t *domain /**< Domäne */)
   323 int EtherCAT_rt_register_domain_fields(ec_domain_t *domain,
   289 {
   324                                        /**< Domäne */
   290     unsigned int offset, size, working_counter_sum;
   325                                        ec_field_init_t *fields
   291     unsigned long start_ticks, end_ticks, timeout_ticks;
   326                                        /**< Array mit Datenfeldern */
   292     ec_master_t *master;
   327                                        )
   293     ec_frame_t *frame;
   328 {
   294 
   329     ec_field_init_t *field;
   295     master = domain->master;
   330 
   296     frame = &domain->frame;
   331     for (field = fields; field->data; field++) {
   297     working_counter_sum = 0;
   332         if (!EtherCAT_rt_register_slave_field(domain, field->address,
   298 
   333                                               field->vendor, field->product,
   299     ec_cyclic_output(master);
   334                                               field->data, field->field_type,
   300 
   335                                               field->field_index,
   301     if (unlikely(!master->device.link_state)) {
   336                                               field->field_count)) {
   302         ec_domain_response_count(domain, working_counter_sum);
   337             return -1;
   303         ec_device_call_isr(&master->device);
   338         }
   304         return -1;
   339     }
   305     }
   340 
   306 
   341     return 0;
   307     rdtscl(start_ticks); // Sendezeit nehmen
   342 }
   308     timeout_ticks = domain->timeout_us * cpu_khz / 1000;
   343 
       
   344 /*****************************************************************************/
       
   345 
       
   346 /**
       
   347    Setzt Prozessdaten-Kommandos in die Warteschlange des Masters.
       
   348 */
       
   349 
       
   350 void EtherCAT_rt_domain_queue(ec_domain_t *domain /**< Domäne */)
       
   351 {
       
   352     unsigned int offset, i;
       
   353     size_t size;
   309 
   354 
   310     offset = 0;
   355     offset = 0;
   311     while (offset < domain->data_size)
   356     for (i = 0; i < domain->command_count; i++) {
   312     {
       
   313         size = domain->data_size - offset;
   357         size = domain->data_size - offset;
   314         if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
   358         if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
   315 
   359         ec_command_init_lrw(domain->commands + i,
   316         ec_frame_init_lrw(frame, master, domain->base_address + offset, size,
   360                             domain->base_address + offset, size,
   317                           domain->data + offset);
   361                             domain->data + offset);
   318 
   362         ec_master_queue_command(domain->master, domain->commands + i);
   319         if (unlikely(ec_frame_send(frame) < 0)) {
       
   320             master->device.state = EC_DEVICE_STATE_READY;
       
   321             master->frames_lost++;
       
   322             ec_cyclic_output(master);
       
   323             ec_domain_response_count(domain, working_counter_sum);
       
   324             return -1;
       
   325         }
       
   326 
       
   327         // Warten
       
   328         do {
       
   329             ec_device_call_isr(&master->device);
       
   330             rdtscl(end_ticks); // Empfangszeit nehmen
       
   331         }
       
   332         while (unlikely(master->device.state == EC_DEVICE_STATE_SENT
       
   333                         && end_ticks - start_ticks < timeout_ticks));
       
   334 
       
   335         master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
       
   336 
       
   337         if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
       
   338             if (master->device.state == EC_DEVICE_STATE_RECEIVED) {
       
   339                 master->frames_delayed++;
       
   340                 ec_cyclic_output(master);
       
   341             }
       
   342             else {
       
   343                 master->device.state = EC_DEVICE_STATE_READY;
       
   344                 master->frames_lost++;
       
   345                 ec_cyclic_output(master);
       
   346                 ec_domain_response_count(domain, working_counter_sum);
       
   347                 return -1;
       
   348             }
       
   349         }
       
   350 
       
   351         if (unlikely(ec_frame_receive(frame) < 0)) {
       
   352             ec_domain_response_count(domain, working_counter_sum);
       
   353             return -1;
       
   354         }
       
   355 
       
   356         working_counter_sum += frame->working_counter;
       
   357 
       
   358         // Daten vom Rahmen in den Prozessdatenspeicher kopieren
       
   359         memcpy(domain->data + offset, frame->data, size);
       
   360 
       
   361         offset += size;
   363         offset += size;
   362     }
   364     }
       
   365 }
       
   366 
       
   367 /*****************************************************************************/
       
   368 
       
   369 /**
       
   370    Verarbeitet empfangene Prozessdaten.
       
   371 */
       
   372 
       
   373 void EtherCAT_rt_domain_process(ec_domain_t *domain /**< Domäne */)
       
   374 {
       
   375     unsigned int offset, working_counter_sum, i;
       
   376     ec_command_t *command;
       
   377     size_t size;
       
   378 
       
   379     working_counter_sum = 0;
       
   380 
       
   381     offset = 0;
       
   382     for (i = 0; i < domain->command_count; i++) {
       
   383         command = domain->commands + i;
       
   384         size = domain->data_size - offset;
       
   385         if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE;
       
   386         if (command->state == EC_CMD_RECEIVED) {
       
   387             // Daten vom Kommando- in den Prozessdatenspeicher kopieren
       
   388             memcpy(domain->data + offset, command->data, size);
       
   389             working_counter_sum += command->working_counter;
       
   390         }
       
   391         else if (unlikely(domain->master->debug_level)) {
       
   392             EC_DBG("process data command not received!\n");
       
   393         }
       
   394         offset += size;
       
   395     }
   363 
   396 
   364     ec_domain_response_count(domain, working_counter_sum);
   397     ec_domain_response_count(domain, working_counter_sum);
   365 
       
   366     return 0;
       
   367 }
   398 }
   368 
   399 
   369 /*****************************************************************************/
   400 /*****************************************************************************/
   370 
   401 
   371 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field);
   402 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field);
   372 EXPORT_SYMBOL(EtherCAT_rt_domain_xio);
   403 EXPORT_SYMBOL(EtherCAT_rt_register_domain_fields);
       
   404 EXPORT_SYMBOL(EtherCAT_rt_domain_queue);
       
   405 EXPORT_SYMBOL(EtherCAT_rt_domain_process);
   373 
   406 
   374 /*****************************************************************************/
   407 /*****************************************************************************/
   375 
   408 
   376 /* Emacs-Konfiguration
   409 /* Emacs-Konfiguration
   377 ;;; Local Variables: ***
   410 ;;; Local Variables: ***