master/domain.c
changeset 2589 2b9c78543663
parent 2101 01b30593e942
child 2610 f0fdcce9874b
equal deleted inserted replaced
2415:af21f0bdc7c9 2589:2b9c78543663
    39 #include "globals.h"
    39 #include "globals.h"
    40 #include "master.h"
    40 #include "master.h"
    41 #include "slave_config.h"
    41 #include "slave_config.h"
    42 
    42 
    43 #include "domain.h"
    43 #include "domain.h"
       
    44 #include "datagram_pair.h"
       
    45 
       
    46 /** Extra debug output for redundancy functions.
       
    47  */
       
    48 #define DEBUG_REDUNDANCY 0
    44 
    49 
    45 /*****************************************************************************/
    50 /*****************************************************************************/
    46 
    51 
    47 void ec_domain_clear_data(ec_domain_t *);
    52 void ec_domain_clear_data(ec_domain_t *);
    48 
    53 
    54         ec_domain_t *domain, /**< EtherCAT domain. */
    59         ec_domain_t *domain, /**< EtherCAT domain. */
    55         ec_master_t *master, /**< Parent master. */
    60         ec_master_t *master, /**< Parent master. */
    56         unsigned int index /**< Index. */
    61         unsigned int index /**< Index. */
    57         )
    62         )
    58 {
    63 {
       
    64     unsigned int dev_idx;
       
    65 
    59     domain->master = master;
    66     domain->master = master;
    60     domain->index = index;
    67     domain->index = index;
    61     INIT_LIST_HEAD(&domain->fmmu_configs);
    68     INIT_LIST_HEAD(&domain->fmmu_configs);
    62     domain->data_size = 0;
    69     domain->data_size = 0;
    63     domain->tx_size = 0;
       
    64     domain->data = NULL;
    70     domain->data = NULL;
    65     domain->data_origin = EC_ORIG_INTERNAL;
    71     domain->data_origin = EC_ORIG_INTERNAL;
    66     domain->logical_base_address = 0x00000000;
    72     domain->logical_base_address = 0x00000000;
    67     INIT_LIST_HEAD(&domain->datagrams);
    73     INIT_LIST_HEAD(&domain->datagram_pairs);
    68     domain->working_counter = 0x0000;
    74     for (dev_idx = EC_DEVICE_MAIN; dev_idx < ec_master_num_devices(master);
       
    75             dev_idx++) {
       
    76         domain->working_counter[dev_idx] = 0x0000;
       
    77     }
    69     domain->expected_working_counter = 0x0000;
    78     domain->expected_working_counter = 0x0000;
    70     domain->working_counter_changes = 0;
    79     domain->working_counter_changes = 0;
       
    80     domain->redundancy_active = 0;
    71     domain->notify_jiffies = 0;
    81     domain->notify_jiffies = 0;
    72 }
    82 }
    73 
    83 
    74 /*****************************************************************************/
    84 /*****************************************************************************/
    75 
    85 
    76 /** Domain destructor.
    86 /** Domain destructor.
    77  */
    87  */
    78 void ec_domain_clear(ec_domain_t *domain /**< EtherCAT domain */)
    88 void ec_domain_clear(ec_domain_t *domain /**< EtherCAT domain */)
    79 {
    89 {
    80     ec_datagram_t *datagram, *next;
    90     ec_datagram_pair_t *datagram_pair, *next_pair;
    81 
    91 
    82     // dequeue and free datagrams
    92     // dequeue and free datagrams
    83     list_for_each_entry_safe(datagram, next, &domain->datagrams, list) {
    93     list_for_each_entry_safe(datagram_pair, next_pair,
    84         ec_datagram_clear(datagram);
    94             &domain->datagram_pairs, list) {
    85         kfree(datagram);
    95         ec_datagram_pair_clear(datagram_pair);
       
    96         kfree(datagram_pair);
    86     }
    97     }
    87 
    98 
    88     ec_domain_clear_data(domain);
    99     ec_domain_clear_data(domain);
    89 }
   100 }
    90 
   101 
    97         )
   108         )
    98 {
   109 {
    99     if (domain->data_origin == EC_ORIG_INTERNAL && domain->data) {
   110     if (domain->data_origin == EC_ORIG_INTERNAL && domain->data) {
   100         kfree(domain->data);
   111         kfree(domain->data);
   101     }
   112     }
       
   113 
   102     domain->data = NULL;
   114     domain->data = NULL;
   103     domain->data_origin = EC_ORIG_INTERNAL;
   115     domain->data_origin = EC_ORIG_INTERNAL;
   104 }
   116 }
   105 
   117 
   106 /*****************************************************************************/
   118 /*****************************************************************************/
   113         )
   125         )
   114 {
   126 {
   115     fmmu->domain = domain;
   127     fmmu->domain = domain;
   116 
   128 
   117     domain->data_size += fmmu->data_size;
   129     domain->data_size += fmmu->data_size;
   118     domain->tx_size += fmmu->tx_size;
       
   119     list_add_tail(&fmmu->list, &domain->fmmu_configs);
   130     list_add_tail(&fmmu->list, &domain->fmmu_configs);
   120 
   131 
   121     EC_MASTER_DBG(domain->master, 1, "Domain %u:"
   132     EC_MASTER_DBG(domain->master, 1, "Domain %u:"
   122             " Added %u bytes, total %zu.\n",
   133             " Added %u bytes, total %zu.\n",
   123             domain->index, fmmu->data_size, domain->data_size);
   134             domain->index, fmmu->data_size, domain->data_size);
   124 }
   135 }
   125 
   136 
   126 /*****************************************************************************/
   137 /*****************************************************************************/
   127 
   138 
   128 /** Allocates a domain datagram and appends it to the list.
   139 /** Allocates a domain datagram pair and appends it to the list.
   129  *
   140  *
   130  * The datagram type and expected working counters are determined by the
   141  * The datagrams' types and expected working counters are determined by the
   131  * number of input and output fmmus that share the datagram.
   142  * number of input and output fmmus that share the datagrams.
   132  *
   143  *
   133  * \retval  0 Success.
   144  * \retval  0 Success.
   134  * \retval <0 Error code.
   145  * \retval <0 Error code.
   135  */
   146  */
   136 int ec_domain_add_datagram(
   147 int ec_domain_add_datagram_pair(
   137         ec_domain_t *domain, /**< EtherCAT domain. */
   148         ec_domain_t *domain, /**< EtherCAT domain. */
   138         uint32_t logical_offset, /**< Logical offset. */
   149         uint32_t logical_offset, /**< Logical offset. */
   139         size_t data_size, /**< Size of the data. */
   150         size_t data_size, /**< Size of the data. */
   140         uint8_t *data, /**< Process data. */
   151         uint8_t *data, /**< Process data. */
   141         const unsigned int used[] /**< Slave config counter for in/out. */
   152         const unsigned int used[] /**< Slave config counter for in/out. */
   142         )
   153         )
   143 {
   154 {
   144     ec_datagram_t *datagram;
   155     ec_datagram_pair_t *datagram_pair;
   145     int ret;
   156     int ret;
   146 
   157 
   147     if (!(datagram = kmalloc(sizeof(ec_datagram_t), GFP_KERNEL))) {
   158     if (!(datagram_pair = kmalloc(sizeof(ec_datagram_pair_t), GFP_KERNEL))) {
   148         EC_MASTER_ERR(domain->master,
   159         EC_MASTER_ERR(domain->master,
   149                 "Failed to allocate domain datagram!\n");
   160                 "Failed to allocate domain datagram pair!\n");
   150         return -ENOMEM;
   161         return -ENOMEM;
   151     }
   162     }
   152 
   163 
   153     ec_datagram_init(datagram);
   164     ret = ec_datagram_pair_init(datagram_pair, domain, logical_offset, data,
   154     snprintf(datagram->name, EC_DATAGRAM_NAME_SIZE,
   165             data_size, used);
   155             "domain%u-%u", domain->index, logical_offset);
   166     if (ret) {
   156 
   167         kfree(datagram_pair);
   157     if (used[EC_DIR_OUTPUT] && used[EC_DIR_INPUT]) { // inputs and outputs
   168         return ret;
   158         ret = ec_datagram_lrw(datagram, logical_offset, data_size, data);
   169     }
   159         if (ret < 0) {
   170 
   160             kfree(datagram);
   171     domain->expected_working_counter +=
   161             return ret;
   172         datagram_pair->expected_working_counter;
   162         }
   173 
   163         // If LRW is used, output FMMUs increment the working counter by 2,
   174     EC_MASTER_DBG(domain->master, 1,
   164         // while input FMMUs increment it by 1.
   175             "Adding datagram pair with expected WC %u.\n",
   165         domain->expected_working_counter +=
   176             datagram_pair->expected_working_counter);
   166             used[EC_DIR_OUTPUT] * 2 + used[EC_DIR_INPUT];
   177 
   167     } else if (used[EC_DIR_OUTPUT]) { // outputs only
   178 
   168         ret = ec_datagram_lwr(datagram, logical_offset, data_size, data);
   179     list_add_tail(&datagram_pair->list, &domain->datagram_pairs);
   169         if (ret < 0) {
       
   170             kfree(datagram);
       
   171             return ret;
       
   172         }
       
   173         domain->expected_working_counter += used[EC_DIR_OUTPUT];
       
   174     } else { // inputs only (or nothing)
       
   175         ret = ec_datagram_lrd(datagram, logical_offset, data_size, data);
       
   176         if (ret < 0) {
       
   177             kfree(datagram);
       
   178             return ret;
       
   179         }
       
   180         domain->expected_working_counter += used[EC_DIR_INPUT];
       
   181     }
       
   182 
       
   183     ec_datagram_zero(datagram);
       
   184     list_add_tail(&datagram->list, &domain->datagrams);
       
   185     datagram->domain = domain;
       
   186     return 0;
   180     return 0;
   187 }
   181 }
   188 
   182 
   189 /*****************************************************************************/
   183 /*****************************************************************************/
   190 
   184 
   193  * Detects, if a slave configuration has already been taken into account for
   187  * Detects, if a slave configuration has already been taken into account for
   194  * a datagram's expected working counter calculation.
   188  * a datagram's expected working counter calculation.
   195  *
   189  *
   196  * Walks through the list of all FMMU configurations for the current datagram
   190  * Walks through the list of all FMMU configurations for the current datagram
   197  * and ends before the current datagram.
   191  * and ends before the current datagram.
       
   192  *
       
   193  * \return Non-zero if slave connfig was already counted.
   198  */
   194  */
   199 int shall_count(
   195 int shall_count(
   200         const ec_fmmu_config_t *cur_fmmu, /**< Current FMMU with direction to
   196         const ec_fmmu_config_t *cur_fmmu, /**< Current FMMU with direction to
   201                                             search for. */
   197                                             search for. */
   202         const ec_fmmu_config_t *first_fmmu /**< Datagram's first FMMU. */
   198         const ec_fmmu_config_t *first_fmmu /**< Datagram's first FMMU. */
   236     size_t datagram_size;
   232     size_t datagram_size;
   237     unsigned int datagram_count;
   233     unsigned int datagram_count;
   238     unsigned int datagram_used[EC_DIR_COUNT];
   234     unsigned int datagram_used[EC_DIR_COUNT];
   239     ec_fmmu_config_t *fmmu;
   235     ec_fmmu_config_t *fmmu;
   240     const ec_fmmu_config_t *datagram_first_fmmu = NULL;
   236     const ec_fmmu_config_t *datagram_first_fmmu = NULL;
   241     const ec_datagram_t *datagram;
   237     const ec_datagram_pair_t *datagram_pair;
   242     int ret;
   238     int ret;
   243 
   239 
   244     domain->logical_base_address = base_address;
   240     domain->logical_base_address = base_address;
   245 
   241 
   246     if (domain->data_size && domain->data_origin == EC_ORIG_INTERNAL) {
   242     if (domain->data_size && domain->data_origin == EC_ORIG_INTERNAL) {
   270 
   266 
   271     list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
   267     list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
   272 
   268 
   273         // Correct logical FMMU address
   269         // Correct logical FMMU address
   274         fmmu->logical_start_address += base_address;
   270         fmmu->logical_start_address += base_address;
   275         fmmu->domain_address += base_address;
   271 
   276 
   272         // Increment Input/Output counter to determine datagram types
   277         // Increment input/output counter to determine datagram types
       
   278         // and calculate expected working counters
   273         // and calculate expected working counters
   279         if (shall_count(fmmu, datagram_first_fmmu)) {
   274         if (shall_count(fmmu, datagram_first_fmmu)) {
   280             datagram_used[fmmu->dir]++;
   275             datagram_used[fmmu->dir]++;
   281         }
   276         }
   282 
   277 
   283         // If the current FMMU's data do not fit in the current datagram,
   278         // If the current FMMU's data do not fit in the current datagram,
   284         // allocate a new one.
   279         // allocate a new one.
   285         if (datagram_size + fmmu->tx_size > EC_MAX_DATA_SIZE) {
   280         if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
   286             ret = ec_domain_add_datagram(domain,
   281             ret = ec_domain_add_datagram_pair(domain,
   287                     domain->logical_base_address + datagram_offset,
   282                     domain->logical_base_address + datagram_offset,
   288                     datagram_size, domain->data + datagram_offset,
   283                     datagram_size, domain->data + datagram_offset,
   289                     datagram_used);
   284                     datagram_used);
   290             if (ret < 0)
   285             if (ret < 0)
   291                 return ret;
   286                 return ret;
   296             datagram_used[EC_DIR_OUTPUT] = 0;
   291             datagram_used[EC_DIR_OUTPUT] = 0;
   297             datagram_used[EC_DIR_INPUT] = 0;
   292             datagram_used[EC_DIR_INPUT] = 0;
   298             datagram_first_fmmu = fmmu;
   293             datagram_first_fmmu = fmmu;
   299         }
   294         }
   300 
   295 
   301         datagram_size += fmmu->tx_size;
   296         datagram_size += fmmu->data_size;
   302     }
   297     }
   303 
   298 
   304     // Allocate last datagram, if data are left (this is also the case if the
   299     /* Allocate last datagram pair, if data are left (this is also the case if
   305     // process data fit into a single datagram)
   300      * the process data fit into a single datagram) */
   306     if (datagram_size) {
   301     if (datagram_size) {
   307         ret = ec_domain_add_datagram(domain,
   302         ret = ec_domain_add_datagram_pair(domain,
   308                 domain->logical_base_address + datagram_offset,
   303                 domain->logical_base_address + datagram_offset,
   309                 datagram_size, domain->data + datagram_offset,
   304                 datagram_size, domain->data + datagram_offset,
   310                 datagram_used);
   305                 datagram_used);
   311         if (ret < 0)
   306         if (ret < 0)
   312             return ret;
   307             return ret;
   315 
   310 
   316     EC_MASTER_INFO(domain->master, "Domain%u: Logical address 0x%08x,"
   311     EC_MASTER_INFO(domain->master, "Domain%u: Logical address 0x%08x,"
   317             " %zu byte, expected working counter %u.\n", domain->index,
   312             " %zu byte, expected working counter %u.\n", domain->index,
   318             domain->logical_base_address, domain->data_size,
   313             domain->logical_base_address, domain->data_size,
   319             domain->expected_working_counter);
   314             domain->expected_working_counter);
   320     list_for_each_entry(datagram, &domain->datagrams, list) {
   315 
       
   316     list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
       
   317         const ec_datagram_t *datagram =
       
   318             &datagram_pair->datagrams[EC_DEVICE_MAIN];
   321         EC_MASTER_INFO(domain->master, "  Datagram %s: Logical offset 0x%08x,"
   319         EC_MASTER_INFO(domain->master, "  Datagram %s: Logical offset 0x%08x,"
   322                 " %zu byte, type %s.\n", datagram->name,
   320                 " %zu byte, type %s.\n", datagram->name,
   323                 EC_READ_U32(datagram->address), datagram->data_size,
   321                 EC_READ_U32(datagram->address), datagram->data_size,
   324                 ec_datagram_type_string(datagram));
   322                 ec_datagram_type_string(datagram));
   325     }
   323     }
   326     
   324 
   327     return 0;
   325     return 0;
   328 }
   326 }
   329 
   327 
   330 /*****************************************************************************/
   328 /*****************************************************************************/
   331 
   329 
   344 }
   342 }
   345 
   343 
   346 /*****************************************************************************/
   344 /*****************************************************************************/
   347 
   345 
   348 /** Get a certain FMMU configuration via its position in the list.
   346 /** Get a certain FMMU configuration via its position in the list.
       
   347  *
       
   348  * \return FMMU at position \a pos, or NULL.
   349  */
   349  */
   350 const ec_fmmu_config_t *ec_domain_find_fmmu(
   350 const ec_fmmu_config_t *ec_domain_find_fmmu(
   351         const ec_domain_t *domain, /**< EtherCAT domain. */
   351         const ec_domain_t *domain, /**< EtherCAT domain. */
   352         unsigned int pos /**< List position. */
   352         unsigned int pos /**< List position. */
   353         )
   353         )
   361     }
   361     }
   362 
   362 
   363     return NULL;
   363     return NULL;
   364 }
   364 }
   365 
   365 
       
   366 /*****************************************************************************/
       
   367 
       
   368 #if EC_MAX_NUM_DEVICES > 1
       
   369 
       
   370 /** Process received data.
       
   371  */
       
   372 int data_changed(
       
   373         uint8_t *send_buffer,
       
   374         const ec_datagram_t *datagram,
       
   375         size_t offset,
       
   376         size_t size
       
   377         )
       
   378 {
       
   379     uint8_t *sent = send_buffer + offset;
       
   380     uint8_t *recv = datagram->data + offset;
       
   381     size_t i;
       
   382 
       
   383     for (i = 0; i < size; i++) {
       
   384         if (recv[i] != sent[i]) {
       
   385             return 1;
       
   386         }
       
   387     }
       
   388 
       
   389     return 0;
       
   390 }
       
   391 
       
   392 #endif
       
   393 
   366 /******************************************************************************
   394 /******************************************************************************
   367  *  Application interface
   395  *  Application interface
   368  *****************************************************************************/
   396  *****************************************************************************/
   369 
   397 
   370 int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
   398 int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain,
   371         const ec_pdo_entry_reg_t *regs)
   399         const ec_pdo_entry_reg_t *regs)
   372 {
   400 {
   373     const ec_pdo_entry_reg_t *reg;
   401     const ec_pdo_entry_reg_t *reg;
   374     ec_slave_config_t *sc;
   402     ec_slave_config_t *sc;
   375     int ret;
   403     int ret;
   376     
   404 
   377     EC_MASTER_DBG(domain->master, 1, "ecrt_domain_reg_pdo_entry_list("
   405     EC_MASTER_DBG(domain->master, 1, "ecrt_domain_reg_pdo_entry_list("
   378             "domain = 0x%p, regs = 0x%p)\n", domain, regs);
   406             "domain = 0x%p, regs = 0x%p)\n", domain, regs);
   379 
   407 
   380     for (reg = regs; reg->index; reg++) {
   408     for (reg = regs; reg->index; reg++) {
   381         sc = ecrt_master_slave_config_err(domain->master, reg->alias,
   409         sc = ecrt_master_slave_config_err(domain->master, reg->alias,
   406 void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
   434 void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
   407 {
   435 {
   408     EC_MASTER_DBG(domain->master, 1, "ecrt_domain_external_memory("
   436     EC_MASTER_DBG(domain->master, 1, "ecrt_domain_external_memory("
   409             "domain = 0x%p, mem = 0x%p)\n", domain, mem);
   437             "domain = 0x%p, mem = 0x%p)\n", domain, mem);
   410 
   438 
   411     ec_mutex_lock(&domain->master->master_mutex);
   439     down(&domain->master->master_sem);
   412 
   440 
   413     ec_domain_clear_data(domain);
   441     ec_domain_clear_data(domain);
   414 
   442 
   415     domain->data = mem;
   443     domain->data = mem;
   416     domain->data_origin = EC_ORIG_EXTERNAL;
   444     domain->data_origin = EC_ORIG_EXTERNAL;
   417 
   445 
   418     ec_mutex_unlock(&domain->master->master_mutex);
   446     up(&domain->master->master_sem);
   419 }
   447 }
   420 
   448 
   421 /*****************************************************************************/
   449 /*****************************************************************************/
   422 
   450 
   423 uint8_t *ecrt_domain_data(ec_domain_t *domain)
   451 uint8_t *ecrt_domain_data(ec_domain_t *domain)
   427 
   455 
   428 /*****************************************************************************/
   456 /*****************************************************************************/
   429 
   457 
   430 void ecrt_domain_process(ec_domain_t *domain)
   458 void ecrt_domain_process(ec_domain_t *domain)
   431 {
   459 {
   432     uint16_t working_counter_sum;
   460     uint16_t wc_sum[EC_MAX_NUM_DEVICES] = {}, wc_total;
   433     ec_datagram_t *datagram;
   461     ec_datagram_pair_t *pair;
   434 
   462 #if EC_MAX_NUM_DEVICES > 1
   435     working_counter_sum = 0x0000;
   463     uint16_t datagram_pair_wc, redundant_wc;
   436     list_for_each_entry(datagram, &domain->datagrams, list) {
   464     unsigned int datagram_offset;
   437         ec_datagram_output_stats(datagram);
   465     ec_fmmu_config_t *fmmu = list_first_entry(&domain->fmmu_configs,
   438         if (datagram->state == EC_DATAGRAM_RECEIVED) {
   466             ec_fmmu_config_t, list);
   439             working_counter_sum += datagram->working_counter;
   467     unsigned int redundancy;
   440         }
   468 #endif
   441     }
   469     unsigned int dev_idx;
   442 
   470 #ifdef EC_RT_SYSLOG
   443     if (working_counter_sum != domain->working_counter) {
   471     unsigned int wc_change;
       
   472 #endif
       
   473 
       
   474 #if DEBUG_REDUNDANCY
       
   475     EC_MASTER_DBG(domain->master, 1, "domain %u process\n", domain->index);
       
   476 #endif
       
   477 
       
   478     list_for_each_entry(pair, &domain->datagram_pairs, list) {
       
   479 #if EC_MAX_NUM_DEVICES > 1
       
   480         datagram_pair_wc = ec_datagram_pair_process(pair, wc_sum);
       
   481 #else
       
   482         ec_datagram_pair_process(pair, wc_sum);
       
   483 #endif
       
   484 
       
   485 #if EC_MAX_NUM_DEVICES > 1
       
   486         if (ec_master_num_devices(domain->master) > 1) {
       
   487             ec_datagram_t *main_datagram = &pair->datagrams[EC_DEVICE_MAIN];
       
   488             uint32_t logical_datagram_address =
       
   489                 EC_READ_U32(main_datagram->address);
       
   490             size_t datagram_size = main_datagram->data_size;
       
   491 
       
   492 #if DEBUG_REDUNDANCY
       
   493             EC_MASTER_DBG(domain->master, 1, "dgram %s log=%u\n",
       
   494                     main_datagram->name, logical_datagram_address);
       
   495 #endif
       
   496 
       
   497             /* Redundancy: Go through FMMU configs to detect data changes. */
       
   498             list_for_each_entry_from(fmmu, &domain->fmmu_configs, list) {
       
   499                 ec_datagram_t *backup_datagram =
       
   500                     &pair->datagrams[EC_DEVICE_BACKUP];
       
   501 
       
   502                 if (fmmu->dir != EC_DIR_INPUT) {
       
   503                     continue;
       
   504                 }
       
   505 
       
   506                 if (fmmu->logical_start_address >=
       
   507                         logical_datagram_address + datagram_size) {
       
   508                     // fmmu data contained in next datagram pair
       
   509                     break;
       
   510                 }
       
   511 
       
   512                 datagram_offset =
       
   513                     fmmu->logical_start_address - logical_datagram_address;
       
   514 
       
   515 #if DEBUG_REDUNDANCY
       
   516                 EC_MASTER_DBG(domain->master, 1,
       
   517                         "input fmmu log=%u size=%u offset=%u\n",
       
   518                         fmmu->logical_start_address, fmmu->data_size,
       
   519                         datagram_offset);
       
   520                 if (domain->master->debug_level > 0) {
       
   521                     ec_print_data(pair->send_buffer + datagram_offset,
       
   522                             fmmu->data_size);
       
   523                     ec_print_data(main_datagram->data + datagram_offset,
       
   524                             fmmu->data_size);
       
   525                     ec_print_data(backup_datagram->data + datagram_offset,
       
   526                             fmmu->data_size);
       
   527                 }
       
   528 #endif
       
   529 
       
   530                 if (data_changed(pair->send_buffer, main_datagram,
       
   531                             datagram_offset, fmmu->data_size)) {
       
   532                     /* data changed on main link: no copying necessary. */
       
   533 #if DEBUG_REDUNDANCY
       
   534                     EC_MASTER_DBG(domain->master, 1, "main changed\n");
       
   535 #endif
       
   536                 } else if (data_changed(pair->send_buffer, backup_datagram,
       
   537                             datagram_offset, fmmu->data_size)) {
       
   538                     /* data changed on backup link: copy to main memory. */
       
   539 #if DEBUG_REDUNDANCY
       
   540                     EC_MASTER_DBG(domain->master, 1, "backup changed\n");
       
   541 #endif
       
   542                     memcpy(main_datagram->data + datagram_offset,
       
   543                             backup_datagram->data + datagram_offset,
       
   544                             fmmu->data_size);
       
   545                 } else if (datagram_pair_wc ==
       
   546                         pair->expected_working_counter) {
       
   547                     /* no change, but WC complete: use main data. */
       
   548 #if DEBUG_REDUNDANCY
       
   549                     EC_MASTER_DBG(domain->master, 1,
       
   550                             "no change but complete\n");
       
   551 #endif
       
   552                 } else {
       
   553                     /* no change and WC incomplete: mark WC as zero to avoid
       
   554                      * data.dependent WC flickering. */
       
   555                     datagram_pair_wc = 0;
       
   556 #if DEBUG_REDUNDANCY
       
   557                     EC_MASTER_DBG(domain->master, 1,
       
   558                             "no change and incomplete\n");
       
   559 #endif
       
   560                 }
       
   561             }
       
   562         }
       
   563 #endif // EC_MAX_NUM_DEVICES > 1
       
   564     }
       
   565 
       
   566 #if EC_MAX_NUM_DEVICES > 1
       
   567     redundant_wc = 0;
       
   568     for (dev_idx = EC_DEVICE_BACKUP;
       
   569             dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
       
   570         redundant_wc += wc_sum[dev_idx];
       
   571     }
       
   572 
       
   573     redundancy = redundant_wc > 0;
       
   574     if (redundancy != domain->redundancy_active) {
       
   575 #ifdef EC_RT_SYSLOG
       
   576         if (redundancy) {
       
   577             EC_MASTER_WARN(domain->master,
       
   578                     "Domain %u: Redundant link in use!\n",
       
   579                     domain->index);
       
   580         } else {
       
   581             EC_MASTER_INFO(domain->master,
       
   582                     "Domain %u: Redundant link unused again.\n",
       
   583                     domain->index);
       
   584         }
       
   585 #endif
       
   586         domain->redundancy_active = redundancy;
       
   587     }
       
   588 #else
       
   589     domain->redundancy_active = 0;
       
   590 #endif
       
   591 
       
   592 #ifdef EC_RT_SYSLOG
       
   593     wc_change = 0;
       
   594 #endif
       
   595     wc_total = 0;
       
   596     for (dev_idx = EC_DEVICE_MAIN;
       
   597             dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
       
   598         if (wc_sum[dev_idx] != domain->working_counter[dev_idx]) {
       
   599 #ifdef EC_RT_SYSLOG
       
   600             wc_change = 1;
       
   601 #endif
       
   602             domain->working_counter[dev_idx] = wc_sum[dev_idx];
       
   603         }
       
   604         wc_total += wc_sum[dev_idx];
       
   605     }
       
   606 
       
   607 #ifdef EC_RT_SYSLOG
       
   608     if (wc_change) {
   444         domain->working_counter_changes++;
   609         domain->working_counter_changes++;
   445         domain->working_counter = working_counter_sum;
       
   446     }
   610     }
   447 
   611 
   448     if (domain->working_counter_changes &&
   612     if (domain->working_counter_changes &&
   449         jiffies - domain->notify_jiffies > HZ) {
   613         jiffies - domain->notify_jiffies > HZ) {
   450         domain->notify_jiffies = jiffies;
   614         domain->notify_jiffies = jiffies;
   451         if (domain->working_counter_changes == 1) {
   615         if (domain->working_counter_changes == 1) {
   452             EC_MASTER_INFO(domain->master, "Domain %u: Working counter"
   616             EC_MASTER_INFO(domain->master, "Domain %u: Working counter"
   453                     " changed to %u/%u.\n", domain->index,
   617                     " changed to %u/%u", domain->index,
   454                     domain->working_counter, domain->expected_working_counter);
   618                     wc_total, domain->expected_working_counter);
   455         } else {
   619         } else {
   456             EC_MASTER_INFO(domain->master, "Domain %u: %u working counter"
   620             EC_MASTER_INFO(domain->master, "Domain %u: %u working counter"
   457                     " changes - now %u/%u.\n", domain->index,
   621                     " changes - now %u/%u", domain->index,
   458                     domain->working_counter_changes, domain->working_counter,
   622                     domain->working_counter_changes,
   459                     domain->expected_working_counter);
   623                     wc_total, domain->expected_working_counter);
   460         }
   624         }
       
   625 #if EC_MAX_NUM_DEVICES > 1
       
   626         if (ec_master_num_devices(domain->master) > 1) {
       
   627             printk(" (");
       
   628             for (dev_idx = EC_DEVICE_MAIN;
       
   629                     dev_idx < ec_master_num_devices(domain->master);
       
   630                     dev_idx++) {
       
   631                 printk("%u", domain->working_counter[dev_idx]);
       
   632                 if (dev_idx + 1 < ec_master_num_devices(domain->master)) {
       
   633                     printk("+");
       
   634                 }
       
   635             }
       
   636             printk(")");
       
   637         }
       
   638 #endif
       
   639         printk(".\n");
       
   640 
   461         domain->working_counter_changes = 0;
   641         domain->working_counter_changes = 0;
   462     }
   642     }
       
   643 #endif
   463 }
   644 }
   464 
   645 
   465 /*****************************************************************************/
   646 /*****************************************************************************/
   466 
   647 
   467 void ecrt_domain_queue(ec_domain_t *domain)
   648 void ecrt_domain_queue(ec_domain_t *domain)
   468 {
   649 {
   469     ec_datagram_t *datagram;
   650     ec_datagram_pair_t *datagram_pair;
   470 
   651     ec_device_index_t dev_idx;
   471     list_for_each_entry(datagram, &domain->datagrams, list) {
   652 
   472         ec_master_queue_datagram(domain->master, datagram);
   653     list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
       
   654 
       
   655 #if EC_MAX_NUM_DEVICES > 1
       
   656         /* copy main data to send buffer */
       
   657         memcpy(datagram_pair->send_buffer,
       
   658                 datagram_pair->datagrams[EC_DEVICE_MAIN].data,
       
   659                 datagram_pair->datagrams[EC_DEVICE_MAIN].data_size);
       
   660 #endif
       
   661         ec_master_queue_datagram(domain->master,
       
   662                 &datagram_pair->datagrams[EC_DEVICE_MAIN]);
       
   663 
       
   664         /* copy main data to backup datagram */
       
   665         for (dev_idx = EC_DEVICE_BACKUP;
       
   666                 dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
       
   667             memcpy(datagram_pair->datagrams[dev_idx].data,
       
   668                     datagram_pair->datagrams[EC_DEVICE_MAIN].data,
       
   669                     datagram_pair->datagrams[EC_DEVICE_MAIN].data_size);
       
   670             ec_master_queue_datagram(domain->master,
       
   671                     &datagram_pair->datagrams[dev_idx]);
       
   672         }
   473     }
   673     }
   474 }
   674 }
   475 
   675 
   476 /*****************************************************************************/
   676 /*****************************************************************************/
   477 
   677 
   478 void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
   678 void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
   479 {
   679 {
   480     state->working_counter = domain->working_counter;
   680     unsigned int dev_idx;
   481 
   681     uint16_t wc = 0;
   482     if (domain->working_counter) {
   682 
   483         if (domain->working_counter == domain->expected_working_counter) {
   683     for (dev_idx = EC_DEVICE_MAIN;
       
   684             dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
       
   685         wc += domain->working_counter[dev_idx];
       
   686     }
       
   687 
       
   688     state->working_counter = wc;
       
   689 
       
   690     if (wc) {
       
   691         if (wc == domain->expected_working_counter) {
   484             state->wc_state = EC_WC_COMPLETE;
   692             state->wc_state = EC_WC_COMPLETE;
   485         } else {
   693         } else {
   486             state->wc_state = EC_WC_INCOMPLETE;
   694             state->wc_state = EC_WC_INCOMPLETE;
   487         }
   695         }
   488     } else {
   696     } else {
   489         state->wc_state = EC_WC_ZERO;
   697         state->wc_state = EC_WC_ZERO;
   490     }
   698     }
       
   699 
       
   700     state->redundancy_active = domain->redundancy_active;
   491 }
   701 }
   492 
   702 
   493 /*****************************************************************************/
   703 /*****************************************************************************/
   494 
   704 
   495 /** \cond */
   705 /** \cond */