IgH EtherCAT Master  1.6.0-rc1
domain.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
6  *
7  * This file is part of the IgH EtherCAT Master.
8  *
9  * The IgH EtherCAT Master is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version 2, as
11  * published by the Free Software Foundation.
12  *
13  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with the IgH EtherCAT Master; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * ---
23  *
24  * The license mentioned above concerns the source code only. Using the
25  * EtherCAT technology and brand is only permitted in compliance with the
26  * industrial property and similar rights of Beckhoff Automation GmbH.
27  *
28  *****************************************************************************/
29 
35 /*****************************************************************************/
36 
37 #include <linux/module.h>
38 
39 #include "globals.h"
40 #include "master.h"
41 #include "slave_config.h"
42 
43 #include "domain.h"
44 #include "datagram_pair.h"
45 
48 #define DEBUG_REDUNDANCY 0
49 
50 #ifndef list_next_entry
51 #define list_next_entry(pos, member) \
52  list_entry((pos)->member.next, typeof(*(pos)), member)
53 #endif
54 
55 /*****************************************************************************/
56 
58 
59 /*****************************************************************************/
60 
64  ec_domain_t *domain,
65  ec_master_t *master,
66  unsigned int index
67  )
68 {
69  unsigned int dev_idx;
70 
71  domain->master = master;
72  domain->index = index;
73  INIT_LIST_HEAD(&domain->fmmu_configs);
74  domain->data_size = 0;
75  domain->data = NULL;
76  domain->data_origin = EC_ORIG_INTERNAL;
77  domain->logical_base_address = 0x00000000;
78  INIT_LIST_HEAD(&domain->datagram_pairs);
79  ec_lock_init(&domain->datagram_pairs_lock);
80  for (dev_idx = EC_DEVICE_MAIN; dev_idx < ec_master_num_devices(master);
81  dev_idx++) {
82  domain->working_counter[dev_idx] = 0x0000;
83  }
84  domain->expected_working_counter = 0x0000;
85  domain->working_counter_changes = 0;
86  domain->redundancy_active = 0;
87  domain->notify_jiffies = 0;
88 
89  /* Used by ec_domain_add_fmmu_config */
90  memset(domain->offset_used, 0, sizeof(domain->offset_used));
91  domain->sc_in_work = 0;
92 }
93 
94 /*****************************************************************************/
95 
99 {
100  ec_datagram_pair_t *datagram_pair, *next_pair;
101 
102  // lockdep_assert_held(&domain->master->domains_lock);
103  ec_lock_down(&domain->datagram_pairs_lock);
104  // dequeue and free datagrams
105  list_for_each_entry_safe(datagram_pair, next_pair,
106  &domain->datagram_pairs, list) {
107  ec_datagram_pair_clear(datagram_pair);
108  kfree(datagram_pair);
109  }
110  ec_lock_up(&domain->datagram_pairs_lock);
111 
112  ec_domain_clear_data(domain);
113 }
114 
115 /*****************************************************************************/
116 
120  ec_domain_t *domain
121  )
122 {
123  // lockdep_assert_held(&domain->master->domains_lock);
124  if (domain->data_origin == EC_ORIG_INTERNAL && domain->data) {
125  kfree(domain->data);
126  }
127 
128  domain->data = NULL;
129  domain->data_origin = EC_ORIG_INTERNAL;
130 }
131 
132 /*****************************************************************************/
133 
137  ec_domain_t *domain,
138  ec_fmmu_config_t *fmmu
139  )
140 {
141  const ec_slave_config_t *sc;
142  uint32_t logical_domain_offset;
143  unsigned fmmu_data_size;
144 
145  fmmu->domain = domain;
146  sc = fmmu->sc;
147 
148  fmmu_data_size = ec_pdo_list_total_size(
149  &sc->sync_configs[fmmu->sync_index].pdos);
150 
151  if (sc->allow_overlapping_pdos && (sc == domain->sc_in_work)) {
152  // If we permit overlapped PDOs, and we already have an allocated FMMU
153  // for this slave, allocate the subsequent FMMU offsets by direction
154  logical_domain_offset = domain->offset_used[fmmu->dir];
155  } else {
156  // otherwise, allocate to the furthest extent of any allocated
157  // FMMU on this domain.
158  logical_domain_offset = max(domain->offset_used[EC_DIR_INPUT],
159  domain->offset_used[EC_DIR_OUTPUT]);
160  // rebase the free offsets to the current position
161  domain->offset_used[EC_DIR_INPUT] = logical_domain_offset;
162  domain->offset_used[EC_DIR_OUTPUT] = logical_domain_offset;
163  }
164  domain->sc_in_work = sc;
165 
166  // consume the offset space for this FMMU's direction
167  domain->offset_used[fmmu->dir] += fmmu_data_size;
168 
169  ec_fmmu_set_domain_offset_size(fmmu, logical_domain_offset, fmmu_data_size);
170 
171  list_add_tail(&fmmu->list, &domain->fmmu_configs);
172 
173  // Determine domain size from furthest extent of FMMU data
174  domain->data_size = max(domain->offset_used[EC_DIR_INPUT],
175  domain->offset_used[EC_DIR_OUTPUT]);
176 
177  EC_MASTER_DBG(domain->master, 1, "Domain %u:"
178  " Added %u bytes at %u.\n",
179  domain->index, fmmu->data_size, logical_domain_offset);
180 }
181 
182 /*****************************************************************************/
183 
193  ec_domain_t *domain,
194  uint32_t logical_offset,
195  size_t data_size,
196  uint8_t *data,
197  const unsigned int used[]
198  )
199 {
200  ec_datagram_pair_t *datagram_pair;
201  int ret;
202 
203  if (!(datagram_pair = kmalloc(sizeof(ec_datagram_pair_t), GFP_KERNEL))) {
204  EC_MASTER_ERR(domain->master,
205  "Failed to allocate domain datagram pair!\n");
206  return -ENOMEM;
207  }
208 
209  ret = ec_datagram_pair_init(datagram_pair, domain, logical_offset, data,
210  data_size, used);
211  if (ret) {
212  kfree(datagram_pair);
213  return ret;
214  }
215 
216  domain->expected_working_counter +=
217  datagram_pair->expected_working_counter;
218 
219  EC_MASTER_DBG(domain->master, 1,
220  "Adding datagram pair with expected WC %u.\n",
221  datagram_pair->expected_working_counter);
222 
223 
224  ec_lock_down(&domain->datagram_pairs_lock);
225  list_add_tail(&datagram_pair->list, &domain->datagram_pairs);
226  ec_lock_up(&domain->datagram_pairs_lock);
227  return 0;
228 }
229 
230 /*****************************************************************************/
231 
242 static int shall_count(
243  const ec_fmmu_config_t *cur_fmmu,
245  const ec_fmmu_config_t *first_fmmu
246  )
247 {
248  for (; first_fmmu != cur_fmmu;
249  first_fmmu = list_entry(first_fmmu->list.next,
250  ec_fmmu_config_t, list)) {
251 
252  if (first_fmmu->sc == cur_fmmu->sc
253  && first_fmmu->dir == cur_fmmu->dir) {
254  return 0; // was already counted
255  }
256  }
257 
258  return 1;
259 }
260 
261 /*****************************************************************************/
262 
276 static int emplace_datagram(ec_domain_t *domain,
277  uint32_t datagram_begin_offset,
278  uint32_t datagram_end_offset,
279  const ec_fmmu_config_t *datagram_first_fmmu,
280  const ec_fmmu_config_t *datagram_end_fmmu
281  )
282 {
283  unsigned int datagram_used[EC_DIR_COUNT];
284  const ec_fmmu_config_t *curr_fmmu;
285  size_t data_size;
286 
287  data_size = datagram_end_offset - datagram_begin_offset;
288 
289  memset(datagram_used, 0, sizeof(datagram_used));
290  for (curr_fmmu = datagram_first_fmmu;
291  &curr_fmmu->list != &datagram_end_fmmu->list;
292  curr_fmmu = list_next_entry(curr_fmmu, list)) {
293  if (shall_count(curr_fmmu, datagram_first_fmmu)) {
294  datagram_used[curr_fmmu->dir]++;
295  }
296  }
297 
298  return ec_domain_add_datagram_pair(domain,
299  domain->logical_base_address + datagram_begin_offset,
300  data_size,
301  domain->data + datagram_begin_offset,
302  datagram_used);
303 }
304 
305 /*****************************************************************************/
306 
316  ec_domain_t *domain,
317  uint32_t base_address
318  )
319 {
320  uint32_t datagram_offset = 0;
321  unsigned int datagram_count = 0;
322  ec_fmmu_config_t *fmmu;
323  const ec_fmmu_config_t *datagram_first_fmmu = NULL;
324  const ec_fmmu_config_t *valid_fmmu = NULL;
325  unsigned candidate_start = 0;
326  unsigned valid_start = 0;
327  const ec_datagram_pair_t *datagram_pair;
328  int ret;
329 
330  domain->logical_base_address = base_address;
331 
332  if (domain->data_size && domain->data_origin == EC_ORIG_INTERNAL) {
333  if (!(domain->data =
334  (uint8_t *) kmalloc(domain->data_size, GFP_KERNEL))) {
335  EC_MASTER_ERR(domain->master, "Failed to allocate %zu bytes"
336  " internal memory for domain %u!\n",
337  domain->data_size, domain->index);
338  return -ENOMEM;
339  }
340  }
341 
342  // Cycle through all domain FMMUs and
343  // - correct the logical base addresses
344  // - set up the datagrams to carry the process data
345  // - calculate the datagrams' expected working counters
346  if (!list_empty(&domain->fmmu_configs)) {
347  datagram_first_fmmu =
348  list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list);
349  }
350 
351  list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
352  if (fmmu->data_size > EC_MAX_DATA_SIZE) {
353  EC_MASTER_ERR(domain->master,
354  "FMMU size %u bytes exceeds maximum data size %u",
355  fmmu->data_size, EC_MAX_DATA_SIZE);
356  return -EINVAL;
357  }
358  if (fmmu->logical_domain_offset >= candidate_start) {
359  // As FMMU offsets increase monotonically, and candidate start
360  // offset has never been contradicted, it can now never be
361  // contradicted, as no future FMMU can cross it.
362  // All FMMUs prior to this point approved for next datagram
363  valid_fmmu = fmmu;
364  valid_start = candidate_start;
365  if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset
366  > EC_MAX_DATA_SIZE) {
367  // yet the new candidate exceeds the datagram size, so we
368  // use the last known valid candidate to create the datagram
369  ret = emplace_datagram(domain, datagram_offset, valid_start,
370  datagram_first_fmmu, valid_fmmu);
371  if (ret < 0)
372  return ret;
373 
374  datagram_offset = valid_start;
375  datagram_count++;
376  datagram_first_fmmu = fmmu;
377  }
378  }
379  if (fmmu->logical_domain_offset + fmmu->data_size > candidate_start) {
380  candidate_start = fmmu->logical_domain_offset + fmmu->data_size;
381  }
382  }
383 
384  /* Allocate last datagram pair, if data are left (this is also the case if
385  * the process data fit into a single datagram) */
386  if (domain->data_size > datagram_offset) {
387  ret = emplace_datagram(domain, datagram_offset, domain->data_size,
388  datagram_first_fmmu, fmmu);
389  if (ret < 0)
390  return ret;
391  datagram_count++;
392  }
393 
394  EC_MASTER_INFO(domain->master, "Domain%u: Logical address 0x%08x,"
395  " %zu byte, expected working counter %u.\n", domain->index,
396  domain->logical_base_address, domain->data_size,
397  domain->expected_working_counter);
398 
399  ec_lock_down(&domain->datagram_pairs_lock);
400  list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
401  const ec_datagram_t *datagram =
402  &datagram_pair->datagrams[EC_DEVICE_MAIN];
403  EC_MASTER_INFO(domain->master, " Datagram %s: Logical offset 0x%08x,"
404  " %zu byte, type %s at %p.\n", datagram->name,
405  EC_READ_U32(datagram->address), datagram->data_size,
406  ec_datagram_type_string(datagram), datagram);
407  }
408  ec_lock_up(&domain->datagram_pairs_lock);
409 
410  return 0;
411 }
412 
413 /*****************************************************************************/
414 
417 unsigned int ec_domain_fmmu_count(const ec_domain_t *domain)
418 {
419  const ec_fmmu_config_t *fmmu;
420  unsigned int num = 0;
421 
422  list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
423  num++;
424  }
425 
426  return num;
427 }
428 
429 /*****************************************************************************/
430 
436  const ec_domain_t *domain,
437  unsigned int pos
438  )
439 {
440  const ec_fmmu_config_t *fmmu;
441 
442  list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
443  if (pos--)
444  continue;
445  return fmmu;
446  }
447 
448  return NULL;
449 }
450 
451 /*****************************************************************************/
452 
453 #if EC_MAX_NUM_DEVICES > 1
454 
457 int data_changed(
458  uint8_t *send_buffer,
459  const ec_datagram_t *datagram,
460  size_t offset,
461  size_t size
462  )
463 {
464  uint8_t *sent = send_buffer + offset;
465  uint8_t *recv = datagram->data + offset;
466  size_t i;
467 
468  for (i = 0; i < size; i++) {
469  if (recv[i] != sent[i]) {
470  return 1;
471  }
472  }
473 
474  return 0;
475 }
476 
477 #endif
478 
479 /******************************************************************************
480  * Application interface
481  *****************************************************************************/
482 
484  const ec_pdo_entry_reg_t *regs)
485 {
486  const ec_pdo_entry_reg_t *reg;
487  ec_slave_config_t *sc;
488  int ret;
489 
490  EC_MASTER_DBG(domain->master, 1, "ecrt_domain_reg_pdo_entry_list("
491  "domain = 0x%p, regs = 0x%p)\n", domain, regs);
492 
493  for (reg = regs; reg->index; reg++) {
494  sc = ecrt_master_slave_config_err(domain->master, reg->alias,
495  reg->position, reg->vendor_id, reg->product_code);
496  if (IS_ERR(sc))
497  return PTR_ERR(sc);
498 
499  ret = ecrt_slave_config_reg_pdo_entry(sc, reg->index,
500  reg->subindex, domain, reg->bit_position);
501  if (ret < 0)
502  return ret;
503 
504  *reg->offset = ret;
505  }
506 
507  return 0;
508 }
509 
510 /*****************************************************************************/
511 
512 size_t ecrt_domain_size(const ec_domain_t *domain)
513 {
514  return domain->data_size;
515 }
516 
517 /*****************************************************************************/
518 
519 void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
520 {
521  EC_MASTER_DBG(domain->master, 1, "ecrt_domain_external_memory("
522  "domain = 0x%p, mem = 0x%p)\n", domain, mem);
523 
524  // lockdep_assert_held(&domain->master->domains_lock);
525  ec_domain_clear_data(domain);
526 
527  domain->data = mem;
528  domain->data_origin = EC_ORIG_EXTERNAL;
529 }
530 
531 /*****************************************************************************/
532 
533 uint8_t *ecrt_domain_data(ec_domain_t *domain)
534 {
535  return domain->data;
536 }
537 
538 /*****************************************************************************/
539 
541 {
542  uint16_t wc_sum[EC_MAX_NUM_DEVICES] = {}, wc_total;
543  ec_datagram_pair_t *pair;
544 #if EC_MAX_NUM_DEVICES > 1
545  uint16_t datagram_pair_wc, redundant_wc;
546  unsigned int datagram_offset;
547  ec_fmmu_config_t *fmmu = list_first_entry(&domain->fmmu_configs,
548  ec_fmmu_config_t, list);
549  unsigned int redundancy;
550 #endif
551  unsigned int dev_idx;
552 #ifdef EC_RT_SYSLOG
553  unsigned int wc_change;
554 #endif
555 
556 #if DEBUG_REDUNDANCY
557  EC_MASTER_DBG(domain->master, 1, "domain %u process\n", domain->index);
558 #endif
559 
560  ec_lock_down(&domain->datagram_pairs_lock);
561  list_for_each_entry(pair, &domain->datagram_pairs, list) {
562 #if EC_MAX_NUM_DEVICES > 1
563  datagram_pair_wc = ec_datagram_pair_process(pair, wc_sum);
564 #else
565  ec_datagram_pair_process(pair, wc_sum);
566 #endif
567 
568 #if EC_MAX_NUM_DEVICES > 1
569  if (ec_master_num_devices(domain->master) > 1) {
570  ec_datagram_t *main_datagram = &pair->datagrams[EC_DEVICE_MAIN];
571 #if DEBUG_REDUNDANCY
572  uint32_t logical_datagram_address =
573  EC_READ_U32(main_datagram->address);
574 #endif
575  size_t datagram_size = main_datagram->data_size;
576 
577 #if DEBUG_REDUNDANCY
578  EC_MASTER_DBG(domain->master, 1, "dgram %s log=%u\n",
579  main_datagram->name, logical_datagram_address);
580 #endif
581 
582  /* Redundancy: Go through FMMU configs to detect data changes. */
583  list_for_each_entry_from(fmmu, &domain->fmmu_configs, list) {
584  ec_datagram_t *backup_datagram =
585  &pair->datagrams[EC_DEVICE_BACKUP];
586 
587  if (fmmu->dir != EC_DIR_INPUT) {
588  continue;
589  }
590 
591  if (fmmu->logical_domain_offset >= datagram_size) {
592  // fmmu data contained in next datagram pair
593  break;
594  }
595 
596  datagram_offset = fmmu->logical_domain_offset;
597 
598 #if DEBUG_REDUNDANCY
599  EC_MASTER_DBG(domain->master, 1,
600  "input fmmu log_off=%u size=%u offset=%u\n",
601  fmmu->logical_domain_offset, fmmu->data_size,
602  datagram_offset);
603  if (domain->master->debug_level > 0) {
604  ec_print_data(pair->send_buffer + datagram_offset,
605  fmmu->data_size);
606  ec_print_data(main_datagram->data + datagram_offset,
607  fmmu->data_size);
608  ec_print_data(backup_datagram->data + datagram_offset,
609  fmmu->data_size);
610  }
611 #endif
612 
613  if (data_changed(pair->send_buffer, main_datagram,
614  datagram_offset, fmmu->data_size)) {
615  /* data changed on main link: no copying necessary. */
616 #if DEBUG_REDUNDANCY
617  EC_MASTER_DBG(domain->master, 1, "main changed\n");
618 #endif
619  } else if (data_changed(pair->send_buffer, backup_datagram,
620  datagram_offset, fmmu->data_size)) {
621  /* data changed on backup link: copy to main memory. */
622 #if DEBUG_REDUNDANCY
623  EC_MASTER_DBG(domain->master, 1, "backup changed\n");
624 #endif
625  memcpy(main_datagram->data + datagram_offset,
626  backup_datagram->data + datagram_offset,
627  fmmu->data_size);
628  } else if (datagram_pair_wc ==
629  pair->expected_working_counter) {
630  /* no change, but WC complete: use main data. */
631 #if DEBUG_REDUNDANCY
632  EC_MASTER_DBG(domain->master, 1,
633  "no change but complete\n");
634 #endif
635  } else {
636  /* no change and WC incomplete: mark WC as zero to avoid
637  * data.dependent WC flickering. */
638  datagram_pair_wc = 0;
639 #if DEBUG_REDUNDANCY
640  EC_MASTER_DBG(domain->master, 1,
641  "no change and incomplete\n");
642 #endif
643  }
644  }
645  }
646 #endif // EC_MAX_NUM_DEVICES > 1
647  }
648  ec_lock_up(&domain->datagram_pairs_lock);
649 
650 #if EC_MAX_NUM_DEVICES > 1
651  redundant_wc = 0;
652  for (dev_idx = EC_DEVICE_BACKUP;
653  dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
654  redundant_wc += wc_sum[dev_idx];
655  }
656 
657  redundancy = redundant_wc > 0;
658  if (redundancy != domain->redundancy_active) {
659 #ifdef EC_RT_SYSLOG
660  if (redundancy) {
661  EC_MASTER_WARN(domain->master,
662  "Domain %u: Redundant link in use!\n",
663  domain->index);
664  } else {
665  EC_MASTER_INFO(domain->master,
666  "Domain %u: Redundant link unused again.\n",
667  domain->index);
668  }
669 #endif
670  domain->redundancy_active = redundancy;
671  }
672 #else
673  domain->redundancy_active = 0;
674 #endif
675 
676 #ifdef EC_RT_SYSLOG
677  wc_change = 0;
678 #endif
679  wc_total = 0;
680  for (dev_idx = EC_DEVICE_MAIN;
681  dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
682  if (wc_sum[dev_idx] != domain->working_counter[dev_idx]) {
683 #ifdef EC_RT_SYSLOG
684  wc_change = 1;
685 #endif
686  domain->working_counter[dev_idx] = wc_sum[dev_idx];
687  }
688  wc_total += wc_sum[dev_idx];
689  }
690 
691 #ifdef EC_RT_SYSLOG
692  if (wc_change) {
693  domain->working_counter_changes++;
694  }
695 
696  if (domain->working_counter_changes &&
697  jiffies - domain->notify_jiffies > HZ) {
698  domain->notify_jiffies = jiffies;
699  if (domain->working_counter_changes == 1) {
700  EC_MASTER_INFO(domain->master, "Domain %u: Working counter"
701  " changed to %u/%u", domain->index,
702  wc_total, domain->expected_working_counter);
703  } else {
704  EC_MASTER_INFO(domain->master, "Domain %u: %u working counter"
705  " changes - now %u/%u", domain->index,
706  domain->working_counter_changes,
707  wc_total, domain->expected_working_counter);
708  }
709 #if EC_MAX_NUM_DEVICES > 1
710  if (ec_master_num_devices(domain->master) > 1) {
711  printk(KERN_CONT " (");
712  for (dev_idx = EC_DEVICE_MAIN;
713  dev_idx < ec_master_num_devices(domain->master);
714  dev_idx++) {
715  printk(KERN_CONT "%u", domain->working_counter[dev_idx]);
716  if (dev_idx + 1 < ec_master_num_devices(domain->master)) {
717  printk(KERN_CONT "+");
718  }
719  }
720  printk(KERN_CONT ")");
721  }
722 #endif
723  printk(KERN_CONT ".\n");
724 
725  domain->working_counter_changes = 0;
726  }
727 #endif
728 }
729 
730 /*****************************************************************************/
731 
733 {
734  ec_datagram_pair_t *datagram_pair;
735  ec_device_index_t dev_idx;
736 
737  ec_lock_down(&domain->datagram_pairs_lock);
738  list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
739 
740 #if EC_MAX_NUM_DEVICES > 1
741  /* copy main data to send buffer */
742  memcpy(datagram_pair->send_buffer,
743  datagram_pair->datagrams[EC_DEVICE_MAIN].data,
744  datagram_pair->datagrams[EC_DEVICE_MAIN].data_size);
745 #endif
747  &datagram_pair->datagrams[EC_DEVICE_MAIN]);
748 
749  /* copy main data to backup datagram */
750  for (dev_idx = EC_DEVICE_BACKUP;
751  dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
752  memcpy(datagram_pair->datagrams[dev_idx].data,
753  datagram_pair->datagrams[EC_DEVICE_MAIN].data,
754  datagram_pair->datagrams[EC_DEVICE_MAIN].data_size);
756  &datagram_pair->datagrams[dev_idx]);
757  }
758  }
759  ec_lock_up(&domain->datagram_pairs_lock);
760 }
761 
762 /*****************************************************************************/
763 
765 {
766  unsigned int dev_idx;
767  uint16_t wc = 0;
768 
769  for (dev_idx = EC_DEVICE_MAIN;
770  dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
771  wc += domain->working_counter[dev_idx];
772  }
773 
774  state->working_counter = wc;
775 
776  if (wc) {
777  if (wc == domain->expected_working_counter) {
778  state->wc_state = EC_WC_COMPLETE;
779  } else {
780  state->wc_state = EC_WC_INCOMPLETE;
781  }
782  } else {
783  state->wc_state = EC_WC_ZERO;
784  }
785 
786  state->redundancy_active = domain->redundancy_active;
787 }
788 
789 /*****************************************************************************/
790 
793 EXPORT_SYMBOL(ecrt_domain_reg_pdo_entry_list);
794 EXPORT_SYMBOL(ecrt_domain_size);
795 EXPORT_SYMBOL(ecrt_domain_external_memory);
796 EXPORT_SYMBOL(ecrt_domain_data);
797 EXPORT_SYMBOL(ecrt_domain_process);
798 EXPORT_SYMBOL(ecrt_domain_queue);
799 EXPORT_SYMBOL(ecrt_domain_state);
800 
803 /*****************************************************************************/
unsigned int working_counter
Value of the last working counter.
Definition: ecrt.h:426
size_t ecrt_domain_size(const ec_domain_t *domain)
Returns the current size of the domain&#39;s process data.
Definition: domain.c:512
const ec_slave_config_t * sc
EtherCAT slave config.
Definition: fmmu_config.h:48
uint8_t subindex
PDO entry subindex.
Definition: ecrt.h:519
uint16_t position
Slave position.
Definition: ecrt.h:515
size_t data_size
Size of the data in data.
Definition: datagram.h:98
Domain datagram pair.
Definition: datagram_pair.h:49
uint32_t logical_domain_offset
Logical offset address relative to domain->logical_base_address.
Definition: fmmu_config.h:52
FMMU configuration.
Definition: fmmu_config.h:46
size_t data_size
Size of the process data.
Definition: domain.h:62
uint32_t offset_used[EC_DIR_COUNT]
Next available domain offset of PDO, by direction.
Definition: domain.h:78
unsigned int expected_working_counter
Expectord working conter.
Definition: datagram_pair.h:56
unsigned int redundancy_active
Redundant link is in use.
Definition: ecrt.h:428
uint16_t index
PDO entry index.
Definition: ecrt.h:518
#define ec_master_num_devices(MASTER)
Number of Ethernet devices.
Definition: master.h:327
int ecrt_domain_reg_pdo_entry_list(ec_domain_t *domain, const ec_pdo_entry_reg_t *regs)
Registers a bunch of PDO entries for a domain.
Definition: domain.c:483
static int emplace_datagram(ec_domain_t *domain, uint32_t datagram_begin_offset, uint32_t datagram_end_offset, const ec_fmmu_config_t *datagram_first_fmmu, const ec_fmmu_config_t *datagram_end_fmmu)
Domain finish helper function.
Definition: domain.c:276
EtherCAT datagram.
Definition: datagram.h:88
unsigned int data_size
Covered PDO size.
Definition: fmmu_config.h:54
char name[EC_DATAGRAM_NAME_SIZE]
Description of the datagram.
Definition: datagram.h:114
ec_wc_state_t wc_state
Working counter interpretation.
Definition: ecrt.h:427
void ecrt_domain_external_memory(ec_domain_t *domain, uint8_t *mem)
Provide external memory to store the domain&#39;s process data.
Definition: domain.c:519
Global definitions and macros.
Some of the registered process data were exchanged.
Definition: ecrt.h:414
EtherCAT master structure.
uint8_t * data
Memory for the process data.
Definition: domain.h:63
uint16_t alias
Slave alias address.
Definition: ecrt.h:514
Internal.
Definition: globals.h:310
#define EC_MASTER_DBG(master, level, fmt, args...)
Convenience macro for printing master-specific debug messages to syslog.
Definition: master.h:106
struct list_head list
List node used by domain.
Definition: fmmu_config.h:47
unsigned int working_counter_changes
Working counter changes since last notification.
Definition: domain.h:74
uint16_t ec_pdo_list_total_size(const ec_pdo_list_t *pl)
Calculates the total size of the mapped PDO entries.
Definition: pdo_list.c:87
const ec_domain_t * domain
Domain.
Definition: fmmu_config.h:49
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:139
Domain state.
Definition: ecrt.h:425
uint32_t vendor_id
Slave vendor ID.
Definition: ecrt.h:516
unsigned int * bit_position
Pointer to a variable to store a bit position (0-7) within the offset.
Definition: ecrt.h:522
void ec_domain_clear(ec_domain_t *domain)
Domain destructor.
Definition: domain.c:98
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
int ec_domain_finish(ec_domain_t *domain, uint32_t base_address)
Finishes a domain.
Definition: domain.c:315
unsigned int debug_level
Master debug level.
Definition: master.h:285
uint16_t ec_datagram_pair_process(ec_datagram_pair_t *pair, uint16_t wc_sum[])
Process received data.
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:49
ec_device_index_t
Master devices.
Definition: globals.h:204
void ec_datagram_pair_clear(ec_datagram_pair_t *pair)
Datagram pair destructor.
unsigned int index
Index (just a number).
Definition: domain.h:59
External.
Definition: globals.h:311
Main device.
Definition: globals.h:205
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2266
struct list_head fmmu_configs
FMMU configurations contained.
Definition: domain.h:61
#define EC_MASTER_WARN(master, fmt, args...)
Convenience macro for printing master-specific warnings to syslog.
Definition: master.h:92
void ec_fmmu_set_domain_offset_size(ec_fmmu_config_t *fmmu, uint32_t logical_domain_offset, unsigned data_size)
Definition: fmmu_config.c:69
unsigned int ec_domain_fmmu_count(const ec_domain_t *domain)
Get the number of FMMU configurations of the domain.
Definition: domain.c:417
#define EC_MASTER_ERR(master, fmt, args...)
Convenience macro for printing master-specific errors to syslog.
Definition: master.h:80
void ec_master_queue_datagram(ec_master_t *master, ec_datagram_t *datagram)
Places a datagram in the datagram queue.
Definition: master.c:947
Values read by the master.
Definition: ecrt.h:438
ec_origin_t data_origin
Origin of the data memory.
Definition: domain.h:64
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:345
uint16_t working_counter[EC_MAX_NUM_DEVICES]
Last working counter values.
Definition: domain.h:71
uint32_t logical_base_address
Logical offset address of the process data.
Definition: domain.h:65
ec_lock_t datagram_pairs_lock
Semaphore protecting the datagram_pairs.
Definition: domain.h:69
uint16_t expected_working_counter
Expected working counter.
Definition: domain.h:73
unsigned int redundancy_active
Non-zero, if redundancy is in use.
Definition: domain.h:76
uint8_t allow_overlapping_pdos
Allow input PDOs use the same frame space as output PDOs.
Definition: slave_config.h:134
int ecrt_slave_config_reg_pdo_entry(ec_slave_config_t *sc, uint16_t index, uint8_t subindex, ec_domain_t *domain, unsigned int *bit_position)
Registers a PDO entry for process data exchange in a domain.
Definition: slave_config.c:898
const ec_slave_config_t * sc_in_work
slave_config which is actively being registered in this domain (i.e.
Definition: domain.h:80
int ec_datagram_pair_init(ec_datagram_pair_t *pair, ec_domain_t *domain, uint32_t logical_offset, uint8_t *data, size_t data_size, const unsigned int used[])
Datagram pair constructor.
Definition: datagram_pair.c:48
void ec_domain_add_fmmu_config(ec_domain_t *domain, ec_fmmu_config_t *fmmu)
Adds an FMMU configuration to the domain.
Definition: domain.c:136
Number of directions.
Definition: ecrt.h:439
struct list_head list
List header.
Definition: datagram_pair.h:50
uint8_t * ecrt_domain_data(ec_domain_t *domain)
Returns the domain&#39;s process data.
Definition: domain.c:533
List record type for PDO entry mass-registration.
Definition: ecrt.h:513
EtherCAT domain structure.
No registered process data were exchanged.
Definition: ecrt.h:413
All registered process data were exchanged.
Definition: ecrt.h:416
EtherCAT datagram pair structure.
const char * ec_datagram_type_string(const ec_datagram_t *datagram)
Returns a string describing the datagram type.
Definition: datagram.c:649
uint8_t * data
Datagram payload.
Definition: datagram.h:95
EtherCAT slave configuration.
Definition: slave_config.h:119
ec_datagram_t datagrams[EC_MAX_NUM_DEVICES]
Datagrams.
Definition: datagram_pair.h:52
EtherCAT slave configuration structure.
ec_slave_config_t * ecrt_master_slave_config_err(ec_master_t *master, uint16_t alias, uint16_t position, uint32_t vendor_id, uint32_t product_code)
Same as ecrt_master_slave_config(), but with ERR_PTR() return value.
Definition: master.c:2868
unsigned int * offset
Pointer to a variable to store the PDO entry&#39;s (byte-)offset in the process data. ...
Definition: ecrt.h:520
void ecrt_domain_state(const ec_domain_t *domain, ec_domain_state_t *state)
Reads the state of a domain.
Definition: domain.c:764
uint8_t address[EC_ADDR_LEN]
Recipient address.
Definition: datagram.h:94
void ecrt_domain_process(ec_domain_t *domain)
Determines the states of the domain&#39;s datagrams.
Definition: domain.c:540
void ec_domain_init(ec_domain_t *domain, ec_master_t *master, unsigned int index)
Domain constructor.
Definition: domain.c:63
ec_direction_t dir
FMMU direction.
Definition: fmmu_config.h:51
Backup device.
Definition: globals.h:206
static int shall_count(const ec_fmmu_config_t *cur_fmmu, const ec_fmmu_config_t *first_fmmu)
Domain finish helper function.
Definition: domain.c:242
Values written by the master.
Definition: ecrt.h:437
struct list_head datagram_pairs
Datagrams pairs (main/backup) for process data exchange.
Definition: domain.h:67
void ecrt_domain_queue(ec_domain_t *domain)
(Re-)queues all domain datagrams in the master&#39;s datagram queue.
Definition: domain.c:732
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition: master.h:68
uint32_t product_code
Slave product code.
Definition: ecrt.h:517
EtherCAT master.
Definition: master.h:189
unsigned long notify_jiffies
Time of last notification.
Definition: domain.h:77
void ec_domain_clear_data(ec_domain_t *)
Frees internally allocated memory.
Definition: domain.c:119
int ec_domain_add_datagram_pair(ec_domain_t *domain, uint32_t logical_offset, size_t data_size, uint8_t *data, const unsigned int used[])
Allocates a domain datagram pair and appends it to the list.
Definition: domain.c:192
EtherCAT domain.
Definition: domain.h:55
ec_master_t * master
EtherCAT master owning the domain.
Definition: domain.h:58
#define EC_MAX_DATA_SIZE
Resulting maximum data size of a single datagram in a frame.
Definition: globals.h:84
const ec_fmmu_config_t * ec_domain_find_fmmu(const ec_domain_t *domain, unsigned int pos)
Get a certain FMMU configuration via its position in the list.
Definition: domain.c:435