IgH EtherCAT Master  1.6.0
fsm_slave_scan.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
4  *
5  * This file is part of the IgH EtherCAT Master.
6  *
7  * The IgH EtherCAT Master is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version 2, as
9  * published by the Free Software Foundation.
10  *
11  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14  * Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with the IgH EtherCAT Master; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  ****************************************************************************/
21 
27 /****************************************************************************/
28 
29 #include "globals.h"
30 #include "master.h"
31 #include "mailbox.h"
32 #include "slave_config.h"
33 
34 #include "fsm_slave_scan.h"
35 
36 /****************************************************************************/
37 
45 #ifdef EC_SII_ASSIGN
47 #endif
50 #ifdef EC_REGALIAS
51 void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *);
52 #endif
56 
59 
61 #ifdef EC_REGALIAS
62 void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *);
63 #endif
66 
67 /****************************************************************************/
68 
72  ec_fsm_slave_scan_t *fsm,
73  ec_datagram_t *datagram,
74  ec_fsm_slave_config_t *fsm_slave_config,
76  ec_fsm_pdo_t *fsm_pdo
77  )
78 {
79  fsm->datagram = datagram;
80  fsm->fsm_slave_config = fsm_slave_config;
81  fsm->fsm_pdo = fsm_pdo;
82 
83  // init sub state machines
84  ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
85 }
86 
87 /****************************************************************************/
88 
92 {
93  // clear sub state machines
95 }
96 
97 /****************************************************************************/
98 
104  ec_fsm_slave_scan_t *fsm,
105  ec_slave_t *slave
106  )
107 {
108  fsm->slave = slave;
110 }
111 
112 /****************************************************************************/
113 
119 {
120  return fsm->state != ec_fsm_slave_scan_state_end
122 }
123 
124 /****************************************************************************/
125 
134 {
135  if (fsm->datagram->state == EC_DATAGRAM_SENT
136  || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
137  // datagram was not sent or received yet.
138  return ec_fsm_slave_scan_running(fsm);
139  }
140 
141  fsm->state(fsm);
142  return ec_fsm_slave_scan_running(fsm);
143 }
144 
145 /****************************************************************************/
146 
152 {
153  return fsm->state == ec_fsm_slave_scan_state_end;
154 }
155 
156 /*****************************************************************************
157  * slave scan state machine
158  ****************************************************************************/
159 
167 {
168  // write station address
169  ec_datagram_apwr(fsm->datagram, fsm->slave->ring_position, 0x0010, 2);
171  fsm->retries = EC_FSM_RETRIES;
173 }
174 
175 /****************************************************************************/
176 
182  ec_fsm_slave_scan_t *fsm
183  )
184 {
185  ec_datagram_t *datagram = fsm->datagram;
186 
187  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
188  return;
189 
190  if (datagram->state != EC_DATAGRAM_RECEIVED) {
192  EC_SLAVE_ERR(fsm->slave,
193  "Failed to receive station address datagram: ");
194  ec_datagram_print_state(datagram);
195  return;
196  }
197 
198  if (datagram->working_counter != 1) {
199  fsm->slave->error_flag = 1;
201  EC_SLAVE_ERR(fsm->slave, "Failed to write station address: ");
202  ec_datagram_print_wc_error(datagram);
203  return;
204  }
205 
206  // Read AL state
207  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0130, 2);
208  ec_datagram_zero(datagram);
209  fsm->retries = EC_FSM_RETRIES;
211 }
212 
213 /****************************************************************************/
214 
220  ec_fsm_slave_scan_t *fsm
221  )
222 {
223  ec_datagram_t *datagram = fsm->datagram;
224  ec_slave_t *slave = fsm->slave;
225 
226  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
227  return;
228 
229  if (datagram->state != EC_DATAGRAM_RECEIVED) {
231  EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: ");
232  ec_datagram_print_state(datagram);
233  return;
234  }
235 
236  if (datagram->working_counter != 1) {
237  fsm->slave->error_flag = 1;
239  EC_SLAVE_ERR(slave, "Failed to read AL state: ");
240  ec_datagram_print_wc_error(datagram);
241  return;
242  }
243 
244  slave->current_state = EC_READ_U8(datagram->data);
245  if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
246  char state_str[EC_STATE_STRING_SIZE];
247  ec_state_string(slave->current_state, state_str, 0);
248  EC_SLAVE_WARN(slave, "Slave has state error bit set (%s)!\n",
249  state_str);
250  }
251 
252  // read base data
253  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0000, 12);
254  ec_datagram_zero(datagram);
255  fsm->retries = EC_FSM_RETRIES;
257 }
258 
259 /****************************************************************************/
260 
264  ec_fsm_slave_scan_t *fsm
265  )
266 {
267  ec_datagram_t *datagram = fsm->datagram;
268  ec_slave_t *slave = fsm->slave;
269  u8 octet;
270  int i;
271 
272  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
273  return;
274 
275  if (datagram->state != EC_DATAGRAM_RECEIVED) {
277  EC_SLAVE_ERR(slave, "Failed to receive base data datagram: ");
278  ec_datagram_print_state(datagram);
279  return;
280  }
281 
282  if (datagram->working_counter != 1) {
283  fsm->slave->error_flag = 1;
285  EC_SLAVE_ERR(slave, "Failed to read base data: ");
286  ec_datagram_print_wc_error(datagram);
287  return;
288  }
289 
290  slave->base_type = EC_READ_U8 (datagram->data);
291  slave->base_revision = EC_READ_U8 (datagram->data + 1);
292  slave->base_build = EC_READ_U16(datagram->data + 2);
293 
294  slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4);
295  if (slave->base_fmmu_count > EC_MAX_FMMUS) {
296  EC_SLAVE_WARN(slave, "Slave has more FMMUs (%u) than the master can"
297  " handle (%u).\n", slave->base_fmmu_count, EC_MAX_FMMUS);
298  slave->base_fmmu_count = EC_MAX_FMMUS;
299  }
300 
301  slave->base_sync_count = EC_READ_U8(datagram->data + 5);
302  if (slave->base_sync_count > EC_MAX_SYNC_MANAGERS) {
303  EC_SLAVE_WARN(slave, "Slave provides more sync managers (%u)"
304  " than the master can handle (%u).\n",
307  }
308 
309  octet = EC_READ_U8(datagram->data + 7);
310  for (i = 0; i < EC_MAX_PORTS; i++) {
311  slave->ports[i].desc = (octet >> (2 * i)) & 0x03;
312  }
313 
314  octet = EC_READ_U8(datagram->data + 8);
315  slave->base_fmmu_bit_operation = octet & 0x01;
316  slave->base_dc_supported = (octet >> 2) & 0x01;
317  slave->base_dc_range = ((octet >> 3) & 0x01) ? EC_DC_64 : EC_DC_32;
318 
319  if (slave->base_dc_supported) {
320  // read DC capabilities
321  ec_datagram_fprd(datagram, slave->station_address, 0x0910,
322  slave->base_dc_range == EC_DC_64 ? 8 : 4);
323  ec_datagram_zero(datagram);
324  fsm->retries = EC_FSM_RETRIES;
326  } else {
328  }
329 }
330 
331 /****************************************************************************/
332 
338  ec_fsm_slave_scan_t *fsm
339  )
340 {
341  ec_datagram_t *datagram = fsm->datagram;
342  ec_slave_t *slave = fsm->slave;
343 
344  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
345  return;
346 
347  if (datagram->state != EC_DATAGRAM_RECEIVED) {
349  EC_SLAVE_ERR(slave, "Failed to receive system time datagram: ");
350  ec_datagram_print_state(datagram);
351  return;
352  }
353 
354  if (datagram->working_counter == 1) {
355  slave->has_dc_system_time = 1;
356  EC_SLAVE_DBG(slave, 1, "Slave has the System Time register.\n");
357  } else if (datagram->working_counter == 0) {
358  EC_SLAVE_DBG(slave, 1, "Slave has no System Time register; delay "
359  "measurement only.\n");
360  } else {
361  fsm->slave->error_flag = 1;
363  EC_SLAVE_ERR(slave, "Failed to determine, if system time register is "
364  "supported: ");
365  ec_datagram_print_wc_error(datagram);
366  return;
367  }
368 
369  // read DC port receive times
370  ec_datagram_fprd(datagram, slave->station_address, 0x0900, 16);
371  ec_datagram_zero(datagram);
372  fsm->retries = EC_FSM_RETRIES;
374 }
375 
376 /****************************************************************************/
377 
383  ec_fsm_slave_scan_t *fsm
384  )
385 {
386  ec_datagram_t *datagram = fsm->datagram;
387  ec_slave_t *slave = fsm->slave;
388  int i;
389 
390  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
391  return;
392 
393  if (datagram->state != EC_DATAGRAM_RECEIVED) {
395  EC_SLAVE_ERR(slave, "Failed to receive system time datagram: ");
396  ec_datagram_print_state(datagram);
397  return;
398  }
399 
400  if (datagram->working_counter != 1) {
401  fsm->slave->error_flag = 1;
403  EC_SLAVE_ERR(slave, "Failed to get DC receive times: ");
404  ec_datagram_print_wc_error(datagram);
405  return;
406  }
407 
408  for (i = 0; i < EC_MAX_PORTS; i++) {
409  slave->ports[i].receive_time = EC_READ_U32(datagram->data + 4 * i);
410  }
411 
413 }
414 
415 /****************************************************************************/
416 
422  ec_fsm_slave_scan_t *fsm
423  )
424 {
425  ec_datagram_t *datagram = fsm->datagram;
426  ec_slave_t *slave = fsm->slave;
427 
428  // read data link status
429  ec_datagram_fprd(datagram, slave->station_address, 0x0110, 2);
430  ec_datagram_zero(datagram);
431  fsm->retries = EC_FSM_RETRIES;
433 }
434 
435 /****************************************************************************/
436 
440  ec_fsm_slave_scan_t *fsm
441  )
442 {
443  // Start fetching SII size
444 
445  EC_SLAVE_DBG(fsm->slave, 1, "Determining SII size.\n");
446 
447  fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
448  ec_fsm_sii_read(&fsm->fsm_sii, fsm->slave, fsm->sii_offset,
451  fsm->state(fsm); // execute state immediately
452 }
453 
454 /****************************************************************************/
455 
456 #ifdef EC_SII_ASSIGN
457 
461  ec_fsm_slave_scan_t *fsm
462  )
463 {
464  ec_datagram_t *datagram = fsm->datagram;
465  ec_slave_t *slave = fsm->slave;
466 
467  EC_SLAVE_DBG(slave, 1, "Assigning SII access to EtherCAT.\n");
468 
469  // assign SII to ECAT
470  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 1);
471  EC_WRITE_U8(datagram->data, 0x00); // EtherCAT
472  fsm->retries = EC_FSM_RETRIES;
474 }
475 
476 #endif
477 
478 /****************************************************************************/
479 
485  ec_fsm_slave_scan_t *fsm
486  )
487 {
488  ec_datagram_t *datagram = fsm->datagram;
489  ec_slave_t *slave = fsm->slave;
490  uint16_t dl_status;
491  unsigned int i;
492 
493  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
494  return;
495 
496  if (datagram->state != EC_DATAGRAM_RECEIVED) {
498  EC_SLAVE_ERR(slave, "Failed to receive DL status datagram: ");
499  ec_datagram_print_state(datagram);
500  return;
501  }
502 
503  if (datagram->working_counter != 1) {
504  fsm->slave->error_flag = 1;
506  EC_SLAVE_ERR(slave, "Failed to read DL status: ");
507  ec_datagram_print_wc_error(datagram);
508  return;
509  }
510 
511  dl_status = EC_READ_U16(datagram->data);
512  for (i = 0; i < EC_MAX_PORTS; i++) {
513  slave->ports[i].link.link_up =
514  dl_status & (1 << (4 + i)) ? 1 : 0;
515  slave->ports[i].link.loop_closed =
516  dl_status & (1 << (8 + i * 2)) ? 1 : 0;
517  slave->ports[i].link.signal_detected =
518  dl_status & (1 << (9 + i * 2)) ? 1 : 0;
519  }
520 
521 #ifdef EC_SII_ASSIGN
523 #else
525 #endif
526 }
527 
528 /****************************************************************************/
529 
530 #ifdef EC_SII_ASSIGN
531 
537  ec_fsm_slave_scan_t *fsm
538  )
539 {
540  ec_datagram_t *datagram = fsm->datagram;
541  ec_slave_t *slave = fsm->slave;
542 
543  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
544  return;
545  }
546 
547  if (datagram->state != EC_DATAGRAM_RECEIVED) {
548  EC_SLAVE_WARN(slave, "Failed to receive SII assignment datagram: ");
549  ec_datagram_print_state(datagram);
550  // Try to go on, probably assignment is correct
551  goto continue_with_sii_size;
552  }
553 
554  if (datagram->working_counter != 1) {
555  EC_SLAVE_WARN(slave, "Failed to assign SII to EtherCAT: ");
556  ec_datagram_print_wc_error(datagram);
557  // Try to go on, probably assignment is correct
558  }
559 
560 continue_with_sii_size:
562 }
563 
564 #endif
565 
566 /****************************************************************************/
567 
573  ec_fsm_slave_scan_t *fsm
574  )
575 {
576  ec_slave_t *slave = fsm->slave;
577  uint16_t cat_type, cat_size;
578 
579  if (ec_fsm_sii_exec(&fsm->fsm_sii))
580  return;
581 
582  if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
583  fsm->slave->error_flag = 1;
585  EC_SLAVE_ERR(slave, "Failed to determine SII content size:"
586  " Reading word offset 0x%04x failed. Assuming %u words.\n",
589  goto alloc_sii;
590  }
591 
592  cat_type = EC_READ_U16(fsm->fsm_sii.value);
593  cat_size = EC_READ_U16(fsm->fsm_sii.value + 2);
594 
595  if (cat_type != 0xFFFF) { // not the last category
596  off_t next_offset = 2UL + fsm->sii_offset + cat_size;
597 
598  EC_SLAVE_DBG(slave, 1, "Found category type %u with size %u."
599  " Proceeding to offset %zd.\n",
600  cat_type, cat_size, (ssize_t)next_offset);
601 
602  if (next_offset >= EC_MAX_SII_SIZE) {
603  EC_SLAVE_WARN(slave, "SII size exceeds %u words"
604  " (0xffff limiter missing?).\n", EC_MAX_SII_SIZE);
605  // cut off category data...
607  goto alloc_sii;
608  }
609  fsm->sii_offset = next_offset;
610  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
612  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
613  return;
614  }
615 
616  slave->sii_nwords = fsm->sii_offset + 1;
617 
618 alloc_sii:
619  if (slave->sii_words) {
620  EC_SLAVE_WARN(slave, "Freeing old SII data...\n");
621  kfree(slave->sii_words);
622  }
623 
624  if (!(slave->sii_words =
625  (uint16_t *) kmalloc(slave->sii_nwords * 2, GFP_KERNEL))) {
626  EC_SLAVE_ERR(slave, "Failed to allocate %zu words of SII data.\n",
627  slave->sii_nwords);
628  slave->sii_nwords = 0;
629  slave->error_flag = 1;
631  return;
632  }
633 
634  // Start fetching SII contents
635 
637  fsm->sii_offset = 0x0000;
638  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
640  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
641 }
642 
643 /****************************************************************************/
644 
651 {
652  ec_slave_t *slave = fsm->slave;
653  uint16_t *cat_word, cat_type, cat_size;
654 
655  if (ec_fsm_sii_exec(&fsm->fsm_sii)) return;
656 
657  if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
658  fsm->slave->error_flag = 1;
660  EC_SLAVE_ERR(slave, "Failed to fetch SII contents.\n");
661  return;
662  }
663 
664  // 2 words fetched
665 
666  if (fsm->sii_offset + 2 <= slave->sii_nwords) { // 2 words fit
667  memcpy(slave->sii_words + fsm->sii_offset, fsm->fsm_sii.value, 4);
668  } else { // copy the last word
669  memcpy(slave->sii_words + fsm->sii_offset, fsm->fsm_sii.value, 2);
670  }
671 
672  if (fsm->sii_offset + 2 < slave->sii_nwords) {
673  // fetch the next 2 words
674  fsm->sii_offset += 2;
675  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
677  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
678  return;
679  }
680 
681  // Evaluate SII contents
682 
684 
685  slave->sii.alias =
686  EC_READ_U16(slave->sii_words + 0x0004);
687  slave->effective_alias = slave->sii.alias;
688  slave->sii.vendor_id =
689  EC_READ_U32(slave->sii_words + 0x0008);
690  slave->sii.product_code =
691  EC_READ_U32(slave->sii_words + 0x000A);
692  slave->sii.revision_number =
693  EC_READ_U32(slave->sii_words + 0x000C);
694  slave->sii.serial_number =
695  EC_READ_U32(slave->sii_words + 0x000E);
696  slave->sii.boot_rx_mailbox_offset =
697  EC_READ_U16(slave->sii_words + 0x0014);
698  slave->sii.boot_rx_mailbox_size =
699  EC_READ_U16(slave->sii_words + 0x0015);
700  slave->sii.boot_tx_mailbox_offset =
701  EC_READ_U16(slave->sii_words + 0x0016);
702  slave->sii.boot_tx_mailbox_size =
703  EC_READ_U16(slave->sii_words + 0x0017);
704  slave->sii.std_rx_mailbox_offset =
705  EC_READ_U16(slave->sii_words + 0x0018);
706  slave->sii.std_rx_mailbox_size =
707  EC_READ_U16(slave->sii_words + 0x0019);
708  slave->sii.std_tx_mailbox_offset =
709  EC_READ_U16(slave->sii_words + 0x001A);
710  slave->sii.std_tx_mailbox_size =
711  EC_READ_U16(slave->sii_words + 0x001B);
712  slave->sii.mailbox_protocols =
713  EC_READ_U16(slave->sii_words + 0x001C);
714  if (slave->sii.mailbox_protocols) {
715  int need_delim = 0;
716  uint16_t all = EC_MBOX_AOE | EC_MBOX_COE | EC_MBOX_FOE |
718  if ((slave->sii.mailbox_protocols & all) &&
719  slave->master->debug_level >= 1) {
720  EC_SLAVE_DBG(slave, 1, "Slave announces to support ");
721  if (slave->sii.mailbox_protocols & EC_MBOX_AOE) {
722  printk(KERN_CONT "AoE");
723  need_delim = 1;
724  }
725  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
726  if (need_delim) {
727  printk(KERN_CONT ", ");
728  }
729  printk(KERN_CONT "CoE");
730  need_delim = 1;
731  }
732  if (slave->sii.mailbox_protocols & EC_MBOX_FOE) {
733  if (need_delim) {
734  printk(KERN_CONT ", ");
735  }
736  printk(KERN_CONT "FoE");
737  need_delim = 1;
738  }
739  if (slave->sii.mailbox_protocols & EC_MBOX_SOE) {
740  if (need_delim) {
741  printk(KERN_CONT ", ");
742  }
743  printk(KERN_CONT "SoE");
744  need_delim = 1;
745  }
746  if (slave->sii.mailbox_protocols & EC_MBOX_VOE) {
747  if (need_delim) {
748  printk(KERN_CONT ", ");
749  }
750  printk(KERN_CONT "VoE");
751  need_delim = 1;
752  }
753  printk(KERN_CONT ".\n");
754  }
755  if (slave->sii.mailbox_protocols & ~all) {
756  EC_SLAVE_DBG(slave, 1, "Slave announces to support unknown"
757  " mailbox protocols 0x%04X.",
758  slave->sii.mailbox_protocols & ~all);
759  }
760  }
761  else {
762  EC_SLAVE_DBG(slave, 1, "Slave announces to support no mailbox"
763  " protocols.");
764  }
765 
766  if (slave->sii.boot_rx_mailbox_offset == 0xffff ||
767  slave->sii.boot_rx_mailbox_size == 0xffff ||
768  slave->sii.boot_tx_mailbox_offset == 0xffff ||
769  slave->sii.boot_tx_mailbox_size == 0xffff ||
770  slave->sii.std_rx_mailbox_offset == 0xffff ||
771  slave->sii.std_rx_mailbox_size == 0xffff ||
772  slave->sii.std_tx_mailbox_offset == 0xffff ||
773  slave->sii.std_tx_mailbox_size == 0xffff) {
774  slave->sii.mailbox_protocols = 0x0000;
775  EC_SLAVE_ERR(slave, "Invalid mailbox settings in SII."
776  " Disabling mailbox communication.");
777  }
778 
780  // sii does not contain category data
782  return;
783  }
784 
785  if (slave->sii_nwords < EC_FIRST_SII_CATEGORY_OFFSET + 1) {
786  EC_SLAVE_ERR(slave, "Unexpected end of SII data:"
787  " First category header missing.\n");
788  goto end;
789  }
790 
791  // evaluate category data
792  cat_word = slave->sii_words + EC_FIRST_SII_CATEGORY_OFFSET;
793  while (EC_READ_U16(cat_word) != 0xFFFF) {
794 
795  // type and size words must fit
796  if (cat_word + 2 - slave->sii_words > slave->sii_nwords) {
797  EC_SLAVE_ERR(slave, "Unexpected end of SII data:"
798  " Category header incomplete.\n");
799  goto end;
800  }
801 
802  cat_type = EC_READ_U16(cat_word) & 0x7FFF;
803  cat_size = EC_READ_U16(cat_word + 1);
804  cat_word += 2;
805 
806  if (cat_word + cat_size - slave->sii_words > slave->sii_nwords) {
807  EC_SLAVE_WARN(slave, "Unexpected end of SII data:"
808  " Category data incomplete.\n");
809  goto end;
810  }
811 
812  switch (cat_type) {
813  case 0x000A:
814  if (ec_slave_fetch_sii_strings(slave, (uint8_t *) cat_word,
815  cat_size * 2))
816  goto end;
817  break;
818  case 0x001E:
819  if (ec_slave_fetch_sii_general(slave, (uint8_t *) cat_word,
820  cat_size * 2))
821  goto end;
822  break;
823  case 0x0028:
824  break;
825  case 0x0029:
826  if (ec_slave_fetch_sii_syncs(slave, (uint8_t *) cat_word,
827  cat_size * 2))
828  goto end;
829  break;
830  case 0x0032:
831  if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
832  cat_size * 2, EC_DIR_INPUT)) // TxPDO
833  goto end;
834  break;
835  case 0x0033:
836  if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word,
837  cat_size * 2, EC_DIR_OUTPUT)) // RxPDO
838  goto end;
839  break;
840  default:
841  EC_SLAVE_DBG(slave, 1, "Unknown category type 0x%04X.\n",
842  cat_type);
843  }
844 
845  cat_word += cat_size;
846  if (cat_word - slave->sii_words >= slave->sii_nwords) {
847  EC_SLAVE_WARN(slave, "Unexpected end of SII data:"
848  " Next category header missing.\n");
849  goto end;
850  }
851  }
852 
853 #ifdef EC_REGALIAS
854  ec_fsm_slave_scan_enter_regalias(fsm);
855 #else
856  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
858  } else {
860  }
861 #endif
862  return;
863 
864 end:
865  EC_SLAVE_ERR(slave, "Failed to analyze category data.\n");
866  fsm->slave->error_flag = 1;
868 }
869 
870 /****************************************************************************/
871 
872 #ifdef EC_REGALIAS
873 
876 void ec_fsm_slave_scan_enter_regalias(
877  ec_fsm_slave_scan_t *fsm
878  )
879 {
880  ec_datagram_t *datagram = fsm->datagram;
881  ec_slave_t *slave = fsm->slave;
882 
883  // read alias from register
884  EC_SLAVE_DBG(slave, 1, "Reading alias from register.\n");
885  ec_datagram_fprd(datagram, slave->station_address, 0x0012, 2);
886  ec_datagram_zero(datagram);
887  fsm->retries = EC_FSM_RETRIES;
888  fsm->state = ec_fsm_slave_scan_state_regalias;
889 }
890 
891 /****************************************************************************/
892 
895 void ec_fsm_slave_scan_state_regalias(
896  ec_fsm_slave_scan_t *fsm
897  )
898 {
899  ec_datagram_t *datagram = fsm->datagram;
900  ec_slave_t *slave = fsm->slave;
901 
902  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
903  return;
904 
905  if (datagram->state != EC_DATAGRAM_RECEIVED) {
907  EC_SLAVE_ERR(slave, "Failed to receive register alias datagram: ");
908  ec_datagram_print_state(datagram);
909  return;
910  }
911 
912  if (datagram->working_counter != 1) {
913  EC_SLAVE_DBG(slave, 1, "Failed to read register alias.\n");
914  } else {
915  slave->effective_alias = EC_READ_U16(datagram->data);
916  EC_SLAVE_DBG(slave, 1, "Read alias %u from register.\n",
917  slave->effective_alias);
918  }
919 
920  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
922  } else {
924  }
925 }
926 
927 #endif // defined EC_REGALIAS
928 
929 /****************************************************************************/
930 
934  ec_fsm_slave_scan_t *fsm
935  )
936 {
937  ec_slave_t *slave = fsm->slave;
938  uint8_t current_state = slave->current_state & EC_SLAVE_STATE_MASK;
939 
940  if (current_state != EC_SLAVE_STATE_PREOP
941  && current_state != EC_SLAVE_STATE_SAFEOP
942  && current_state != EC_SLAVE_STATE_OP) {
943  if (slave->master->debug_level) {
944  char str[EC_STATE_STRING_SIZE];
945  ec_state_string(current_state, str, 0);
946  EC_SLAVE_DBG(slave, 0, "Slave is not in the state"
947  " to do mailbox com (%s), setting to PREOP.\n", str);
948  }
949 
954  } else {
955  EC_SLAVE_DBG(slave, 1, "Reading mailbox"
956  " sync manager configuration.\n");
957 
958  /* Scan current sync manager configuration to get configured mailbox
959  * sizes. */
960  ec_datagram_fprd(fsm->datagram, slave->station_address, 0x0800,
961  EC_SYNC_PAGE_SIZE * 2);
962  fsm->retries = EC_FSM_RETRIES;
964  }
965 }
966 
967 /****************************************************************************/
968 
972  ec_fsm_slave_scan_t *fsm
973  )
974 {
976  return;
977 
980  return;
981  }
982 
984 }
985 
986 /****************************************************************************/
987 
991  ec_fsm_slave_scan_t *fsm
992  )
993 {
994  ec_datagram_t *datagram = fsm->datagram;
995  ec_slave_t *slave = fsm->slave;
996  uint16_t tx_offset, tx_size, rx_offset, rx_size;
997 
998  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
999  return;
1000 
1001  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1003  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1004  " configuration datagram: ");
1005  ec_datagram_print_state(datagram);
1006  return;
1007  }
1008 
1009  if (datagram->working_counter != 1) {
1010  fsm->slave->error_flag = 1;
1012  EC_SLAVE_ERR(slave, "Failed to read DL status: ");
1013  ec_datagram_print_wc_error(datagram);
1014  return;
1015  }
1016 
1017  rx_offset = EC_READ_U16(datagram->data);
1018  rx_size = EC_READ_U16(datagram->data + 2);
1019  tx_offset = EC_READ_U16(datagram->data + 8);
1020  tx_size = EC_READ_U16(datagram->data + 10);
1021 
1022  if (rx_size == 0xffff) {
1024  slave->sii.mailbox_protocols = 0x0000;
1025  EC_SLAVE_ERR(slave, "Invalid RX mailbox size (%u) configured."
1026  " Disabling mailbox communication.", rx_size);
1027  return;
1028  }
1029 
1030  if (tx_size == 0xffff) {
1032  slave->sii.mailbox_protocols = 0x0000;
1033  EC_SLAVE_ERR(slave, "Invalid TX mailbox size (%u) configured."
1034  " Disabling mailbox communication.", tx_size);
1035  return;
1036  }
1037 
1038  slave->configured_rx_mailbox_offset = rx_offset;
1039  slave->configured_rx_mailbox_size = rx_size;
1040  slave->configured_tx_mailbox_offset = tx_offset;
1041  slave->configured_tx_mailbox_size = tx_size;
1042 
1043  EC_SLAVE_DBG(slave, 1, "Mailbox configuration:\n");
1044  EC_SLAVE_DBG(slave, 1, " RX offset=0x%04x size=%u\n",
1047  EC_SLAVE_DBG(slave, 1, " TX offset=0x%04x size=%u\n",
1050 
1052 }
1053 
1054 /****************************************************************************/
1055 
1059  ec_fsm_slave_scan_t *fsm
1060  )
1061 {
1062  ec_slave_t *slave = fsm->slave;
1063 
1064  EC_SLAVE_DBG(slave, 1, "Scanning PDO assignment and mapping.\n");
1066  ec_fsm_pdo_start_reading(fsm->fsm_pdo, slave);
1067  ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram); // execute immediately
1068 }
1069 
1070 /****************************************************************************/
1071 
1075  ec_fsm_slave_scan_t *fsm
1076  )
1077 {
1078  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
1079  return;
1080  }
1081 
1082  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
1084  return;
1085  }
1086 
1087  // reading PDO configuration finished
1089 }
1090 
1091 /*****************************************************************************
1092  * Common state functions
1093  ****************************************************************************/
1094 
1098  ec_fsm_slave_scan_t *fsm
1099  )
1100 {
1101 }
1102 
1103 /****************************************************************************/
1104 
1108  ec_fsm_slave_scan_t *fsm
1109  )
1110 {
1111 }
1112 
1113 /****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
ec_slave_t * slave
Slave the FSM runs on.
CANopen over EtherCAT.
Definition: globals.h:146
uint16_t ring_position
Ring position.
Definition: slave.h:175
uint32_t revision_number
Revision number.
Definition: slave.h:129
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:131
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:89
void ec_fsm_slave_scan_enter_assign_sii(ec_fsm_slave_scan_t *fsm)
Enter slave scan state ASSIGN_SII.
#define EC_SLAVE_STATE_MASK
Slave state mask.
Definition: globals.h:117
ec_sii_t sii
Extracted SII data.
Definition: slave.h:215
int ec_fsm_pdo_exec(ec_fsm_pdo_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_pdo.c:156
void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm, ec_slave_t *slave)
Start slave configuration state machine.
ec_datagram_t * datagram
Datagram used in the state machine.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:193
uint16_t base_build
Build number.
Definition: slave.h:198
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:98
OP (mailbox communication and input/output update)
Definition: globals.h:132
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:191
void ec_fsm_slave_scan_init(ec_fsm_slave_scan_t *fsm, ec_datagram_t *datagram, ec_fsm_slave_config_t *fsm_slave_config, ec_fsm_pdo_t *fsm_pdo)
Constructor.
size_t ec_state_string(uint8_t, char *, uint8_t)
Prints slave states in clear text.
Definition: module.c:399
ec_slave_port_t ports[EC_MAX_PORTS]
Ports.
Definition: slave.h:179
ec_slave_state_t current_state
Current application state.
Definition: slave.h:184
ec_slave_port_link_t link
Port link status.
Definition: slave.h:112
void ec_fsm_slave_scan_state_preop(ec_fsm_slave_scan_t *)
Slave scan state: PREOP.
Servo-Profile over EtherCAT.
Definition: globals.h:148
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:82
void ec_fsm_slave_scan_state_assign_sii(ec_fsm_slave_scan_t *)
Slave scan state: ASSIGN_SII.
EtherCAT datagram.
Definition: datagram.h:79
uint32_t serial_number
Serial number.
Definition: slave.h:130
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2699
void ec_fsm_slave_scan_state_dc_times(ec_fsm_slave_scan_t *)
Slave scan state: DC TIMES.
uint16_t working_counter
Working counter.
Definition: datagram.h:91
void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *)
Slave scan state: START.
Acknowledge/Error bit (no actual state)
Definition: globals.h:134
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:134
int ec_slave_fetch_sii_strings(ec_slave_t *slave, const uint8_t *data, size_t data_size)
Fetches data from a STRING category.
Definition: slave.c:316
Sent (still in the queue).
Definition: datagram.h:69
void ec_fsm_sii_init(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_sii.c:66
EtherCAT slave scanning state machine.
uint16_t station_address
Configured station address.
Definition: slave.h:176
#define EC_MAX_SII_SIZE
Maximum SII size in words, to avoid infinite reading.
Definition: globals.h:57
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:136
#define EC_MAX_FMMUS
Maximum number of FMMUs per slave.
Definition: globals.h:92
uint8_t base_type
Slave type.
Definition: slave.h:196
int ec_fsm_slave_scan_exec(ec_fsm_slave_scan_t *fsm)
Executes the current state of the state machine.
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:137
EtherCAT master structure.
SAFEOP (mailbox communication and input update)
Definition: globals.h:130
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:133
ec_fsm_slave_config_t * fsm_slave_config
Slave configuration state machine to use.
EtherCAT slave.
Definition: slave.h:168
void ec_fsm_slave_scan_state_pdos(ec_fsm_slave_scan_t *)
Slave scan state: PDOS.
int ec_datagram_apwr(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APWR datagram.
Definition: datagram.c:202
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:170
ec_datagram_state_t state
State.
Definition: datagram.h:92
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine to use.
void ec_fsm_slave_scan_state_base(ec_fsm_slave_scan_t *)
Slave scan state: BASE.
void ec_slave_clear_sync_managers(ec_slave_t *slave)
Clear the sync manager array.
Definition: slave.c:259
Use configured addresses.
Definition: fsm_sii.h:42
uint16_t * sii_words
Complete SII image.
Definition: slave.h:211
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:139
void ec_fsm_pdo_start_reading(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start reading the PDO configuration.
Definition: fsm_pdo.c:111
void ec_fsm_slave_scan_state_sii_data(ec_fsm_slave_scan_t *)
Slave scan state: SII DATA.
ec_fsm_sii_t fsm_sii
SII state machine.
unsigned int debug_level
Master debug level.
Definition: master.h:271
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:68
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:594
ec_slave_dc_range_t base_dc_range
DC range.
Definition: slave.h:203
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:135
uint8_t base_fmmu_bit_operation
FMMU bit operation is supported.
Definition: slave.h:201
void ec_fsm_slave_scan_enter_pdos(ec_fsm_slave_scan_t *)
Enter slave scan state PDOS.
int ec_fsm_slave_scan_running(const ec_fsm_slave_scan_t *fsm)
uint16_t alias
Configured station alias.
Definition: slave.h:126
void ec_fsm_slave_scan_state_sync(ec_fsm_slave_scan_t *)
Slave scan state: SYNC.
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2716
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:199
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:187
File-Access over EtherCAT.
Definition: globals.h:147
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2627
ec_slave_port_desc_t desc
Port descriptors.
Definition: slave.h:111
Finite state machine for scanning an EtherCAT slave.
ec_master_t * master
Master owning the slave.
Definition: slave.h:170
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:290
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:204
unsigned int retries
Retries on datagram timeout.
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition: datagram.c:265
Values read by the master.
Definition: ecrt.h:504
PDO configuration state machine.
Definition: fsm_pdo.h:46
#define EC_FIRST_SII_CATEGORY_OFFSET
Word offset of first SII category.
Definition: globals.h:86
uint8_t base_revision
Revision.
Definition: slave.h:197
32 bit.
Definition: globals.h:173
void ec_fsm_sii_read(ec_fsm_sii_t *fsm, ec_slave_t *slave, uint16_t word_offset, ec_fsm_sii_addressing_t mode)
Initializes the SII read state machine.
Definition: fsm_sii.c:90
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:80
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:172
uint16_t effective_alias
Effective alias address.
Definition: slave.h:177
void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *)
Slave scan state: DATALINK.
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition: fsm_sii.c:129
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:144
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2611
Finite state machine to configure an EtherCAT slave.
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:557
Mailbox functionality.
int ec_slave_fetch_sii_syncs(ec_slave_t *slave, const uint8_t *data, size_t data_size)
Fetches data from a SYNC MANAGER category.
Definition: slave.c:423
#define EC_STATE_STRING_SIZE
Minimum size of a buffer used with ec_state_string().
Definition: globals.h:54
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:132
#define EC_MAX_PORTS
Maximum number of slave ports.
Definition: ecrt.h:273
int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm)
Executes the current state of the state machine.
void(* state)(ec_fsm_slave_scan_t *)
State function.
Queued for sending.
Definition: datagram.h:68
void ec_fsm_slave_scan_state_error(ec_fsm_slave_scan_t *)
State: ERROR.
uint32_t receive_time
Port receive times for delay measurement.
Definition: slave.h:114
Timed out (dequeued).
Definition: datagram.h:71
uint16_t sii_offset
SII offset in words.
void ec_slave_request_state(ec_slave_t *slave, ec_slave_state_t state)
Request a slave state and resets the error flag.
Definition: slave.c:300
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:189
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:202
void ec_fsm_slave_scan_start(ec_fsm_slave_scan_t *fsm, ec_slave_t *slave)
Start slave scan state machine.
size_t sii_nwords
Size of the SII contents in words.
Definition: slave.h:212
uint8_t * data
Datagram payload.
Definition: datagram.h:86
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:200
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2595
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_scan_clear(ec_fsm_slave_scan_t *fsm)
Destructor.
EtherCAT slave configuration structure.
void ec_fsm_slave_scan_state_end(ec_fsm_slave_scan_t *)
State: END.
void ec_fsm_slave_scan_state_dc_cap(ec_fsm_slave_scan_t *)
Slave scan state: DC CAPABILITIES.
void ec_fsm_slave_scan_enter_sii_size(ec_fsm_slave_scan_t *fsm)
Enter slave scan state SII_SIZE.
uint32_t product_code
Vendor-specific product code.
Definition: slave.h:128
PREOP state (mailbox communication, no IO)
Definition: globals.h:126
Values written by the master.
Definition: ecrt.h:503
void ec_fsm_slave_scan_enter_preop(ec_fsm_slave_scan_t *)
Enter slave scan state PREOP.
Received (dequeued).
Definition: datagram.h:70
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:185
void ec_fsm_slave_scan_state_address(ec_fsm_slave_scan_t *)
Slave scan state: ADDRESS.
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:138
void ec_fsm_slave_scan_state_state(ec_fsm_slave_scan_t *)
Slave scan state: STATE.
Vendor specific.
Definition: globals.h:149
int ec_slave_fetch_sii_pdos(ec_slave_t *slave, const uint8_t *data, size_t data_size, ec_direction_t dir)
Fetches data from a [RT]xPDO category.
Definition: slave.c:489
#define EC_MAX_SYNC_MANAGERS
Maximum number of sync managers per slave.
Definition: ecrt.h:264
int ec_slave_fetch_sii_general(ec_slave_t *slave, const uint8_t *data, size_t data_size)
Fetches data from a GENERAL category.
Definition: slave.c:372
ADS over EtherCAT.
Definition: globals.h:144
uint32_t vendor_id
Vendor ID.
Definition: slave.h:127
void ec_fsm_slave_scan_enter_datalink(ec_fsm_slave_scan_t *)
Slave scan entry function: DATALINK.
void ec_fsm_slave_scan_state_sii_size(ec_fsm_slave_scan_t *)
Slave scan state: SII SIZE.
int ec_fsm_slave_scan_success(const ec_fsm_slave_scan_t *fsm)
uint8_t value[4]
raw SII value (32bit)
Definition: fsm_sii.h:62