IgH EtherCAT Master  1.7.0
fsm_slave_scan.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2026 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 
38 // prototypes for private methods
44 #ifdef EC_REGALIAS
45 void ec_fsm_slave_scan_enter_regalias(ec_fsm_slave_scan_t *);
46 #endif
49 
50 /****************************************************************************/
51 
59 #ifdef EC_SII_ASSIGN
61 #endif
65 #ifdef EC_REGALIAS
66 void ec_fsm_slave_scan_state_regalias(ec_fsm_slave_scan_t *);
67 #endif
71 
74 
75 /****************************************************************************/
76 
80  ec_fsm_slave_scan_t *fsm,
81  ec_datagram_t *datagram,
82  ec_fsm_slave_config_t *fsm_slave_config,
84  ec_fsm_pdo_t *fsm_pdo
85  )
86 {
87  fsm->slave = NULL;
88  fsm->datagram = datagram;
89  fsm->fsm_slave_config = fsm_slave_config;
90  fsm->fsm_pdo = fsm_pdo;
91 
92  fsm->retries = 0;
93  fsm->state = NULL;
94  fsm->sii_offset = 0;
95 
96  // init sub state machines
97  ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram);
98 }
99 
100 /****************************************************************************/
101 
105  ec_fsm_slave_scan_t *fsm
106  )
107 {
108  // clear sub state machines
109  ec_fsm_sii_clear(&fsm->fsm_sii);
110 }
111 
112 /****************************************************************************/
113 
119  ec_fsm_slave_scan_t *fsm,
120  ec_slave_t *slave
121  )
122 {
123  fsm->slave = slave;
125 }
126 
127 /****************************************************************************/
128 
134  const ec_fsm_slave_scan_t *fsm
135  )
136 {
137  return fsm->state != ec_fsm_slave_scan_state_end
139 }
140 
141 /****************************************************************************/
142 
151  ec_fsm_slave_scan_t *fsm
152  )
153 {
154  if (fsm->datagram->state == EC_DATAGRAM_SENT
155  || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
156  // datagram was not sent or received yet.
157  return ec_fsm_slave_scan_running(fsm);
158  }
159 
160  fsm->state(fsm);
161  return ec_fsm_slave_scan_running(fsm);
162 }
163 
164 /****************************************************************************/
165 
171  const ec_fsm_slave_scan_t *fsm
172  )
173 {
174  return fsm->state == ec_fsm_slave_scan_state_end;
175 }
176 
177 /*****************************************************************************
178  * slave scan state machine
179  ****************************************************************************/
180 
188  ec_fsm_slave_scan_t *fsm
189  )
190 {
191  // write station address
192  ec_datagram_apwr(fsm->datagram, fsm->slave->ring_position, 0x0010, 2);
194  fsm->retries = EC_FSM_RETRIES;
196 }
197 
198 /****************************************************************************/
199 
205  ec_fsm_slave_scan_t *fsm
206  )
207 {
208  ec_datagram_t *datagram = fsm->datagram;
209 
210  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
211  return;
212 
213  if (datagram->state != EC_DATAGRAM_RECEIVED) {
215  EC_SLAVE_ERR(fsm->slave,
216  "Failed to receive station address datagram: ");
217  ec_datagram_print_state(datagram);
218  return;
219  }
220 
221  if (datagram->working_counter != 1) {
222  fsm->slave->error_flag = 1;
224  EC_SLAVE_ERR(fsm->slave, "Failed to write station address: ");
225  ec_datagram_print_wc_error(datagram);
226  return;
227  }
228 
229  // Read AL state
230  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0130, 2);
231  ec_datagram_zero(datagram);
232  fsm->retries = EC_FSM_RETRIES;
234 }
235 
236 /****************************************************************************/
237 
243  ec_fsm_slave_scan_t *fsm
244  )
245 {
246  ec_datagram_t *datagram = fsm->datagram;
247  ec_slave_t *slave = fsm->slave;
248 
249  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
250  return;
251 
252  if (datagram->state != EC_DATAGRAM_RECEIVED) {
254  EC_SLAVE_ERR(slave, "Failed to receive AL state datagram: ");
255  ec_datagram_print_state(datagram);
256  return;
257  }
258 
259  if (datagram->working_counter != 1) {
260  fsm->slave->error_flag = 1;
262  EC_SLAVE_ERR(slave, "Failed to read AL state: ");
263  ec_datagram_print_wc_error(datagram);
264  return;
265  }
266 
267  slave->current_state = EC_READ_U8(datagram->data);
268  if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
269  char state_str[EC_STATE_STRING_SIZE];
270  ec_state_string(slave->current_state, state_str, 0);
271  EC_SLAVE_WARN(slave, "Slave has state error bit set (%s)!\n",
272  state_str);
273  }
274 
275  // read base data
276  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0000, 12);
277  ec_datagram_zero(datagram);
278  fsm->retries = EC_FSM_RETRIES;
280 }
281 
282 /****************************************************************************/
283 
287  ec_fsm_slave_scan_t *fsm
288  )
289 {
290  ec_datagram_t *datagram = fsm->datagram;
291  ec_slave_t *slave = fsm->slave;
292  u8 octet;
293  int i;
294 
295  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
296  return;
297 
298  if (datagram->state != EC_DATAGRAM_RECEIVED) {
300  EC_SLAVE_ERR(slave, "Failed to receive base data datagram: ");
301  ec_datagram_print_state(datagram);
302  return;
303  }
304 
305  if (datagram->working_counter != 1) {
306  fsm->slave->error_flag = 1;
308  EC_SLAVE_ERR(slave, "Failed to read base data: ");
309  ec_datagram_print_wc_error(datagram);
310  return;
311  }
312 
313  slave->base_type = EC_READ_U8 (datagram->data);
314  slave->base_revision = EC_READ_U8 (datagram->data + 1);
315  slave->base_build = EC_READ_U16(datagram->data + 2);
316 
317  slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4);
318  if (slave->base_fmmu_count > EC_MAX_FMMUS) {
319  EC_SLAVE_WARN(slave, "Slave has more FMMUs (%u) than the master can"
320  " handle (%u).\n", slave->base_fmmu_count, EC_MAX_FMMUS);
321  slave->base_fmmu_count = EC_MAX_FMMUS;
322  }
323 
324  slave->base_sync_count = EC_READ_U8(datagram->data + 5);
325  if (slave->base_sync_count > EC_MAX_SYNC_MANAGERS) {
326  EC_SLAVE_WARN(slave, "Slave provides more sync managers (%u)"
327  " than the master can handle (%u).\n",
330  }
331 
332  octet = EC_READ_U8(datagram->data + 7);
333  for (i = 0; i < EC_MAX_PORTS; i++) {
334  slave->ports[i].desc = (octet >> (2 * i)) & 0x03;
335  }
336 
337  octet = EC_READ_U8(datagram->data + 8);
338  slave->base_fmmu_bit_operation = octet & 0x01;
339  slave->base_dc_supported = (octet >> 2) & 0x01;
340  slave->base_dc_range = ((octet >> 3) & 0x01) ? EC_DC_64 : EC_DC_32;
341 
342  if (slave->base_dc_supported) {
343  // read DC capabilities
344  ec_datagram_fprd(datagram, slave->station_address, 0x0910,
345  slave->base_dc_range == EC_DC_64 ? 8 : 4);
346  ec_datagram_zero(datagram);
347  fsm->retries = EC_FSM_RETRIES;
349  } else {
351  }
352 }
353 
354 /****************************************************************************/
355 
361  ec_fsm_slave_scan_t *fsm
362  )
363 {
364  ec_datagram_t *datagram = fsm->datagram;
365  ec_slave_t *slave = fsm->slave;
366 
367  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
368  return;
369 
370  if (datagram->state != EC_DATAGRAM_RECEIVED) {
372  EC_SLAVE_ERR(slave, "Failed to receive system time datagram: ");
373  ec_datagram_print_state(datagram);
374  return;
375  }
376 
377  if (datagram->working_counter == 1) {
378  slave->has_dc_system_time = 1;
379  EC_SLAVE_DBG(slave, 1, "Slave has the System Time register.\n");
380  } else if (datagram->working_counter == 0) {
381  EC_SLAVE_DBG(slave, 1, "Slave has no System Time register; delay "
382  "measurement only.\n");
383  } else {
384  fsm->slave->error_flag = 1;
386  EC_SLAVE_ERR(slave, "Failed to determine, if system time register is "
387  "supported: ");
388  ec_datagram_print_wc_error(datagram);
389  return;
390  }
391 
392  // read DC port receive times
393  ec_datagram_fprd(datagram, slave->station_address, 0x0900, 16);
394  ec_datagram_zero(datagram);
395  fsm->retries = EC_FSM_RETRIES;
397 }
398 
399 /****************************************************************************/
400 
406  ec_fsm_slave_scan_t *fsm
407  )
408 {
409  ec_datagram_t *datagram = fsm->datagram;
410  ec_slave_t *slave = fsm->slave;
411  int i;
412 
413  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
414  return;
415 
416  if (datagram->state != EC_DATAGRAM_RECEIVED) {
418  EC_SLAVE_ERR(slave, "Failed to receive system time datagram: ");
419  ec_datagram_print_state(datagram);
420  return;
421  }
422 
423  if (datagram->working_counter != 1) {
424  fsm->slave->error_flag = 1;
426  EC_SLAVE_ERR(slave, "Failed to get DC receive times: ");
427  ec_datagram_print_wc_error(datagram);
428  return;
429  }
430 
431  for (i = 0; i < EC_MAX_PORTS; i++) {
432  slave->ports[i].receive_time = EC_READ_U32(datagram->data + 4 * i);
433  }
434 
436 }
437 
438 /****************************************************************************/
439 
445  ec_fsm_slave_scan_t *fsm
446  )
447 {
448  ec_datagram_t *datagram = fsm->datagram;
449  ec_slave_t *slave = fsm->slave;
450 
451  // read data link status
452  ec_datagram_fprd(datagram, slave->station_address, 0x0110, 2);
453  ec_datagram_zero(datagram);
454  fsm->retries = EC_FSM_RETRIES;
456 }
457 
458 /****************************************************************************/
459 
463  ec_fsm_slave_scan_t *fsm
464  )
465 {
466  // Start fetching SII size
467 
468  EC_SLAVE_DBG(fsm->slave, 1, "Determining SII size.\n");
469 
470  fsm->sii_offset = EC_FIRST_SII_CATEGORY_OFFSET; // first category header
471  ec_fsm_sii_read(&fsm->fsm_sii, fsm->slave, fsm->sii_offset,
474  fsm->state(fsm); // execute state immediately
475 }
476 
477 /****************************************************************************/
478 
479 #ifdef EC_SII_ASSIGN
480 
484  ec_fsm_slave_scan_t *fsm
485  )
486 {
487  ec_datagram_t *datagram = fsm->datagram;
488  ec_slave_t *slave = fsm->slave;
489 
490  EC_SLAVE_DBG(slave, 1, "Assigning SII access to EtherCAT.\n");
491 
492  // assign SII to ECAT
493  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 1);
494  EC_WRITE_U8(datagram->data, 0x00); // EtherCAT
495  fsm->retries = EC_FSM_RETRIES;
497 }
498 
499 #endif
500 
501 /****************************************************************************/
502 
506  ec_fsm_slave_scan_t *fsm
507  )
508 {
509  // Start fetching identification (alias/vendor/product/revision/serial)
510  // to check for possible SII cache hits
511 
512  EC_SLAVE_DBG(fsm->slave, 1, "Loading SII identification words.\n");
513 
515  ec_fsm_sii_read(&fsm->fsm_sii, fsm->slave, fsm->sii_offset,
518  fsm->state(fsm); // execute state immediately
519 }
520 
521 /****************************************************************************/
522 
528  ec_fsm_slave_scan_t *fsm
529  )
530 {
531  ec_datagram_t *datagram = fsm->datagram;
532  ec_slave_t *slave = fsm->slave;
533  uint16_t dl_status;
534  unsigned int i;
535 
536  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
537  return;
538 
539  if (datagram->state != EC_DATAGRAM_RECEIVED) {
541  EC_SLAVE_ERR(slave, "Failed to receive DL status datagram: ");
542  ec_datagram_print_state(datagram);
543  return;
544  }
545 
546  if (datagram->working_counter != 1) {
547  fsm->slave->error_flag = 1;
549  EC_SLAVE_ERR(slave, "Failed to read DL status: ");
550  ec_datagram_print_wc_error(datagram);
551  return;
552  }
553 
554  dl_status = EC_READ_U16(datagram->data);
555  for (i = 0; i < EC_MAX_PORTS; i++) {
556  slave->ports[i].link.link_up =
557  dl_status & (1 << (4 + i)) ? 1 : 0;
558  slave->ports[i].link.loop_closed =
559  dl_status & (1 << (8 + i * 2)) ? 1 : 0;
560  slave->ports[i].link.signal_detected =
561  dl_status & (1 << (9 + i * 2)) ? 1 : 0;
562  }
563 
564 #ifdef EC_SII_ASSIGN
566 #else
567  if (fsm->slave->master->sii_caching != EC_SII_DISABLE_CACHING) {
569  }
570  else {
572  }
573 #endif
574 }
575 
576 /****************************************************************************/
577 
578 #ifdef EC_SII_ASSIGN
579 
585  ec_fsm_slave_scan_t *fsm
586  )
587 {
588  ec_datagram_t *datagram = fsm->datagram;
589  ec_slave_t *slave = fsm->slave;
590 
591  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
592  return;
593  }
594 
595  if (datagram->state != EC_DATAGRAM_RECEIVED) {
596  EC_SLAVE_WARN(slave, "Failed to receive SII assignment datagram: ");
597  ec_datagram_print_state(datagram);
598  // Try to go on, probably assignment is correct
599  goto continue_with_sii_size;
600  }
601 
602  if (datagram->working_counter != 1) {
603  EC_SLAVE_WARN(slave, "Failed to assign SII to EtherCAT: ");
604  ec_datagram_print_wc_error(datagram);
605  // Try to go on, probably assignment is correct
606  }
607 
608 continue_with_sii_size:
609  if (fsm->slave->master->sii_caching != EC_SII_DISABLE_CACHING) {
611  }
612  else {
614  }
615 }
616 
617 #endif
618 
619 /****************************************************************************/
620 
626  ec_fsm_slave_scan_t *fsm
627  )
628 {
629  ec_slave_t *slave = fsm->slave;
630  unsigned int words_fitting;
631  int words_to_copy;
632  uint32_t vendor, product, revision, serial;
633  ec_sii_page_t *cached;
634 
635  if (ec_fsm_sii_exec(&fsm->fsm_sii)) {
636  return;
637  }
638 
639  if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
640  fsm->slave->error_flag = 1;
642  EC_SLAVE_ERR(slave, "Failed to fetch SII identification.\n");
643  return;
644  }
645 
646  if (fsm->sii_offset == EC_SII_WORD_OFFSET_ALIAS) {
647  // First step: Fetch alias from 0x0004, then go to 0x0008
648  // unfortunately it makes no sense to read through, if only 2 words
649  // are read in parallel (depends on the slave)
650  slave->sii.alias = EC_READ_U16(fsm->fsm_sii.value);
651  slave->effective_alias = slave->sii.alias;
652 
653  EC_SLAVE_DBG(slave, 1, "Alias %u\n", slave->sii.alias);
654 
655  // Continue with vendor ID
657  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
659  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
660  return;
661  }
662 
663  // Vendor ID and following
664  words_fitting = EC_NUM_SII_IDENT_WORDS + EC_SII_WORD_OFFSET_VENDOR
665  - fsm->sii_offset;
666  words_to_copy = min(words_fitting, fsm->fsm_sii.read_word_count);
667  memcpy(fsm->sii_ident + (fsm->sii_offset - EC_SII_WORD_OFFSET_VENDOR) * 2,
668  fsm->fsm_sii.value, words_to_copy * 2);
669 
671  + fsm->fsm_sii.read_word_count < EC_NUM_SII_IDENT_WORDS) {
672  // fetch the remaining words
673  fsm->sii_offset += fsm->fsm_sii.read_word_count;
674  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
676  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
677  return;
678  }
679 
680  // All identification words read
681 
682  vendor = EC_READ_U32(fsm->sii_ident);
683  product = EC_READ_U32(fsm->sii_ident + 4);
684  revision = EC_READ_U32(fsm->sii_ident + 8);
685  serial = EC_READ_U32(fsm->sii_ident + 12);
686 
687  EC_SLAVE_DBG(slave, 1,
688  "Identification 0x%08X / 0x%08X / 0x%08X / 0x%08X\n",
689  vendor, product, revision, serial);
690 
691  cached = ec_master_find_cached_sii_page(slave->master, vendor,
692  product, revision, serial, slave->sii.alias);
693  if (cached) {
694  int ret;
695 
696  EC_SLAVE_DBG(slave, 1, "Found matching SII page in cache.\n");
697 
698  ret = ec_sii_page_copy(&slave->sii_page, cached);
699  if (ret) {
700  EC_SLAVE_ERR(slave, "Failed to copy cached SII page.\n");
701  fsm->slave->error_flag = 1;
703  return;
704  }
705 
707 
708  // Evaluate the (cached) SII contents...
709  if (ec_slave_analyze_sii_data(slave)) {
710  EC_SLAVE_ERR(slave, "Failed to analyze category data.\n");
711  fsm->slave->error_flag = 1;
713  return;
714  }
715 
716 #ifdef EC_REGALIAS
717  ec_fsm_slave_scan_enter_regalias(fsm);
718 #else
719  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
721  } else {
723  }
724 #endif
725  return;
726  }
727 
728  EC_SLAVE_DBG(slave, 1, "No matching SII page found in cache.\n");
729  // We will have to read it out by ourselves. Sigh...
731 }
732 
733 /****************************************************************************/
734 
740  ec_fsm_slave_scan_t *fsm
741  )
742 {
743  ec_slave_t *slave = fsm->slave;
744  uint16_t cat_type, cat_size;
745  size_t word_count = 0;
746 
747  if (ec_fsm_sii_exec(&fsm->fsm_sii))
748  return;
749 
750  if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
751  fsm->slave->error_flag = 1;
753  EC_SLAVE_ERR(slave, "Failed to determine SII content size:"
754  " Reading word offset 0x%04x failed. Assuming %u words.\n",
756  word_count = EC_FIRST_SII_CATEGORY_OFFSET;
757  goto alloc_sii;
758  }
759 
760  cat_type = EC_READ_U16(fsm->fsm_sii.value);
761  cat_size = EC_READ_U16(fsm->fsm_sii.value + 2);
762 
763  if (cat_type != 0xFFFF) { // not the last category
764  off_t next_offset = 2UL + fsm->sii_offset + cat_size;
765 
766  EC_SLAVE_DBG(slave, 1, "Found category type %u with size %u."
767  " Proceeding to offset %zd.\n",
768  cat_type, cat_size, (ssize_t)next_offset);
769 
770  if (next_offset >= EC_MAX_SII_SIZE) {
771  EC_SLAVE_WARN(slave, "SII size exceeds %u words"
772  " (0xffff limiter missing?).\n", EC_MAX_SII_SIZE);
773  // cut off category data...
774  word_count = EC_FIRST_SII_CATEGORY_OFFSET;
775  goto alloc_sii;
776  }
777  fsm->sii_offset = next_offset;
778  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
780  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
781  return;
782  }
783 
784  word_count = fsm->sii_offset + 1;
785 
786 alloc_sii:
787  if (ec_sii_page_alloc(&slave->sii_page, word_count)) {
788  EC_SLAVE_ERR(slave, "Failed to allocate %zu words of SII data.\n",
789  word_count);
790  slave->error_flag = 1;
792  return;
793  }
794 
795  // Start fetching SII contents
796 
798  fsm->sii_offset = 0x0000;
799  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
801  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
802 }
803 
804 /****************************************************************************/
805 
811  ec_fsm_slave_scan_t *fsm
812  )
813 {
814  ec_slave_t *slave = fsm->slave;
815  unsigned int words_fitting;
816  int words_to_copy;
817 
818  if (ec_fsm_sii_exec(&fsm->fsm_sii)) return;
819 
820  if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
821  fsm->slave->error_flag = 1;
823  EC_SLAVE_ERR(slave, "Failed to fetch SII contents.\n");
824  return;
825  }
826 
827  // Did we get 2 or 4 words?
828  words_fitting = slave->sii_page.word_count - fsm->sii_offset;
829  words_to_copy = min(words_fitting, fsm->fsm_sii.read_word_count);
830  memcpy(slave->sii_page.words + fsm->sii_offset, fsm->fsm_sii.value,
831  words_to_copy * 2);
832 
833  if (fsm->sii_offset + fsm->fsm_sii.read_word_count
834  < slave->sii_page.word_count) {
835  // fetch the next words
836  fsm->sii_offset += fsm->fsm_sii.read_word_count;
837  ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset,
839  ec_fsm_sii_exec(&fsm->fsm_sii); // execute state immediately
840  return;
841  }
842 
844 
845  // All words read. Evaluate the SII contents...
846  if (ec_slave_analyze_sii_data(slave)) {
847  EC_SLAVE_ERR(slave, "Failed to analyze category data.\n");
848  fsm->slave->error_flag = 1;
850  }
851 
852  // Add the page that we just read to the cache
853  ec_master_cache_sii_page(slave->master, &slave->sii_page);
854 
855 #ifdef EC_REGALIAS
856  ec_fsm_slave_scan_enter_regalias(fsm);
857 #else
858  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
860  } else {
862  }
863 #endif
864 }
865 
866 /****************************************************************************/
867 
868 #ifdef EC_REGALIAS
869 
872 void ec_fsm_slave_scan_enter_regalias(
873  ec_fsm_slave_scan_t *fsm
874  )
875 {
876  ec_datagram_t *datagram = fsm->datagram;
877  ec_slave_t *slave = fsm->slave;
878 
879  // read alias from register
880  EC_SLAVE_DBG(slave, 1, "Reading alias from register.\n");
881  ec_datagram_fprd(datagram, slave->station_address, 0x0012, 2);
882  ec_datagram_zero(datagram);
883  fsm->retries = EC_FSM_RETRIES;
884  fsm->state = ec_fsm_slave_scan_state_regalias;
885 }
886 
887 /****************************************************************************/
888 
891 void ec_fsm_slave_scan_state_regalias(
892  ec_fsm_slave_scan_t *fsm
893  )
894 {
895  ec_datagram_t *datagram = fsm->datagram;
896  ec_slave_t *slave = fsm->slave;
897 
898  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
899  return;
900 
901  if (datagram->state != EC_DATAGRAM_RECEIVED) {
903  EC_SLAVE_ERR(slave, "Failed to receive register alias datagram: ");
904  ec_datagram_print_state(datagram);
905  return;
906  }
907 
908  if (datagram->working_counter != 1) {
909  EC_SLAVE_DBG(slave, 1, "Failed to read register alias.\n");
910  } else {
911  slave->effective_alias = EC_READ_U16(datagram->data);
912  EC_SLAVE_DBG(slave, 1, "Read alias %u from register.\n",
913  slave->effective_alias);
914  }
915 
916  if (slave->sii.mailbox_protocols & EC_MBOX_COE) {
918  } else {
920  }
921 }
922 
923 #endif // defined EC_REGALIAS
924 
925 /****************************************************************************/
926 
930  ec_fsm_slave_scan_t *fsm
931  )
932 {
933  ec_slave_t *slave = fsm->slave;
934  uint8_t current_state = slave->current_state & EC_SLAVE_STATE_MASK;
935 
936  if (current_state != EC_SLAVE_STATE_PREOP
937  && current_state != EC_SLAVE_STATE_SAFEOP
938  && current_state != EC_SLAVE_STATE_OP) {
939  if (slave->master->debug_level) {
940  char str[EC_STATE_STRING_SIZE];
941  ec_state_string(current_state, str, 0);
942  EC_SLAVE_DBG(slave, 0, "Slave is not in the state"
943  " to do mailbox com (%s), setting to PREOP.\n", str);
944  }
945 
950  } else {
951  EC_SLAVE_DBG(slave, 1, "Reading mailbox"
952  " sync manager configuration.\n");
953 
954  /* Scan current sync manager configuration to get configured mailbox
955  * sizes. */
956  ec_datagram_fprd(fsm->datagram, slave->station_address, 0x0800,
957  EC_SYNC_PAGE_SIZE * 2);
958  fsm->retries = EC_FSM_RETRIES;
960  }
961 }
962 
963 /****************************************************************************/
964 
968  ec_fsm_slave_scan_t *fsm
969  )
970 {
972  return;
973 
976  return;
977  }
978 
980 }
981 
982 /****************************************************************************/
983 
987  ec_fsm_slave_scan_t *fsm
988  )
989 {
990  ec_datagram_t *datagram = fsm->datagram;
991  ec_slave_t *slave = fsm->slave;
992  uint16_t tx_offset, tx_size, rx_offset, rx_size;
993 
994  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
995  return;
996 
997  if (datagram->state != EC_DATAGRAM_RECEIVED) {
999  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1000  " configuration datagram: ");
1001  ec_datagram_print_state(datagram);
1002  return;
1003  }
1004 
1005  if (datagram->working_counter != 1) {
1006  fsm->slave->error_flag = 1;
1008  EC_SLAVE_ERR(slave, "Failed to read DL status: ");
1009  ec_datagram_print_wc_error(datagram);
1010  return;
1011  }
1012 
1013  rx_offset = EC_READ_U16(datagram->data);
1014  rx_size = EC_READ_U16(datagram->data + 2);
1015  tx_offset = EC_READ_U16(datagram->data + 8);
1016  tx_size = EC_READ_U16(datagram->data + 10);
1017 
1018  if (rx_size == 0xffff) {
1020  slave->sii.mailbox_protocols = 0x0000;
1021  EC_SLAVE_ERR(slave, "Invalid RX mailbox size (%u) configured."
1022  " Disabling mailbox communication.", rx_size);
1023  return;
1024  }
1025 
1026  if (tx_size == 0xffff) {
1028  slave->sii.mailbox_protocols = 0x0000;
1029  EC_SLAVE_ERR(slave, "Invalid TX mailbox size (%u) configured."
1030  " Disabling mailbox communication.", tx_size);
1031  return;
1032  }
1033 
1034  slave->configured_rx_mailbox_offset = rx_offset;
1035  slave->configured_rx_mailbox_size = rx_size;
1036  slave->configured_tx_mailbox_offset = tx_offset;
1037  slave->configured_tx_mailbox_size = tx_size;
1038 
1039  EC_SLAVE_DBG(slave, 1, "Mailbox configuration:\n");
1040  EC_SLAVE_DBG(slave, 1, " RX offset=0x%04x size=%u\n",
1043  EC_SLAVE_DBG(slave, 1, " TX offset=0x%04x size=%u\n",
1046 
1048 }
1049 
1050 /****************************************************************************/
1051 
1055  ec_fsm_slave_scan_t *fsm
1056  )
1057 {
1058  ec_slave_t *slave = fsm->slave;
1059  ec_pdo_mode_t assign_mode = EC_PDO_MODE_DEFAULT;
1060  ec_pdo_mode_t config_mode = EC_PDO_MODE_DEFAULT;
1061  const ec_slave_config_t *sc;
1062 
1063  // Look up a not-yet-attached configuration for this slave (attaching
1064  // only happens after the whole bus has been scanned) to find out if
1065  // the application requested non-default PDO scanning behavior.
1066  if ((sc = ec_master_find_config_for_slave(slave->master, slave))) {
1067  assign_mode = sc->pdo_assign_mode;
1068  config_mode = sc->pdo_config_mode;
1069  }
1070 
1071  if (assign_mode == EC_PDO_MODE_FIXED
1072  || assign_mode == EC_PDO_MODE_WRITE) {
1073  if (config_mode == EC_PDO_MODE_FIXED
1074  || config_mode == EC_PDO_MODE_WRITE) {
1075  EC_SLAVE_DBG(slave, 1, "Skipping PDO scanning"
1076  " (fixed PDO assignment/configuration).\n");
1078  return;
1079  }
1080  }
1081 
1082  EC_SLAVE_DBG(slave, 1, "Scanning PDO assignment and mapping.\n");
1084  ec_fsm_pdo_start_reading(fsm->fsm_pdo, slave, assign_mode, config_mode);
1085  ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram); // execute immediately
1086 }
1087 
1088 /****************************************************************************/
1089 
1093  ec_fsm_slave_scan_t *fsm
1094  )
1095 {
1096  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
1097  return;
1098  }
1099 
1100  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
1102  return;
1103  }
1104 
1105  // reading PDO configuration finished
1107 }
1108 
1109 /*****************************************************************************
1110  * Common state functions
1111  ****************************************************************************/
1112 
1116  ec_fsm_slave_scan_t *fsm
1117  )
1118 {
1119 }
1120 
1121 /****************************************************************************/
1122 
1126  ec_fsm_slave_scan_t *fsm
1127  )
1128 {
1129 }
1130 
1131 /****************************************************************************/
#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:152
uint16_t ring_position
Ring position.
Definition: slave.h:176
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:95
void ec_fsm_slave_scan_enter_assign_sii(ec_fsm_slave_scan_t *)
Enter slave scan state ASSIGN_SII.
int ec_slave_analyze_sii_data(ec_slave_t *slave)
Analyzes SII data.
Definition: slave.c:323
#define EC_SLAVE_STATE_MASK
Slave state mask.
Definition: globals.h:123
int ec_sii_page_copy(ec_sii_page_t *page, const ec_sii_page_t *from)
Copy contents from other page.
Definition: sii_page.c:100
ec_sii_t sii
Extracted SII data.
Definition: slave.h:217
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:171
Neither read nor write via CoE.
Definition: ecrt.h:552
size_t word_count
Size of the SII contents in words.
Definition: sii_page.h:61
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.
ec_sii_page_origin_t origin
Page origin.
Definition: sii_page.h:58
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:194
uint16_t base_build
Build number.
Definition: slave.h:199
ec_pdo_mode_t
PDO handling mode.
Definition: ecrt.h:551
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:99
OP (mailbox communication and input/output update)
Definition: globals.h:138
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:192
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:405
ec_slave_port_t ports[EC_MAX_PORTS]
Ports.
Definition: slave.h:180
#define EC_SII_WORD_OFFSET_ALIAS
Word offset of alias address.
Definition: globals.h:89
ec_slave_state_t current_state
Current application state.
Definition: slave.h:185
uint8_t sii_ident[EC_NUM_SII_IDENT_WORDS *2]
Temporary storage for slave identification objects.
ec_slave_port_link_t link
Port link status.
Definition: slave.h:113
void ec_fsm_slave_scan_state_preop(ec_fsm_slave_scan_t *)
Slave scan state: PREOP.
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:83
void ec_fsm_slave_scan_state_assign_sii(ec_fsm_slave_scan_t *)
Slave scan state: ASSIGN_SII.
EtherCAT datagram.
Definition: datagram.h:79
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3298
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:93
void ec_fsm_slave_scan_enter_sii_ident(ec_fsm_slave_scan_t *)
Enter slave scan state SII ident.
void ec_fsm_slave_scan_state_start(ec_fsm_slave_scan_t *)
Slave scan state: START.
ec_slave_config_t * ec_master_find_config_for_slave(ec_master_t *master, const ec_slave_t *slave)
Finds the slave configuration that will be attached to the given slave.
Definition: master.c:1896
Acknowledge/Error bit (no actual state)
Definition: globals.h:140
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
ec_pdo_mode_t pdo_config_mode
Whether/how to read resp.
Definition: slave_config.h:129
EtherCAT slave scanning state machine.
uint16_t station_address
Configured station address.
Definition: slave.h:177
#define EC_MAX_SII_SIZE
Maximum SII size in words, to avoid infinite reading.
Definition: globals.h:57
#define EC_MAX_FMMUS
Maximum number of FMMUs per slave.
Definition: globals.h:98
uint8_t base_type
Slave type.
Definition: slave.h:197
int ec_fsm_slave_scan_exec(ec_fsm_slave_scan_t *fsm)
Executes the current state of the state machine.
Global definitions and macros.
void ec_fsm_slave_scan_state_sii_ident(ec_fsm_slave_scan_t *)
Slave scan state: SII ident.
Completely read via SII.
Definition: sii_page.h:39
EtherCAT master structure.
SAFEOP (mailbox communication and input update)
Definition: globals.h:136
ec_fsm_slave_config_t * fsm_slave_config
Slave configuration state machine to use.
EtherCAT slave.
Definition: slave.h:169
ec_sii_page_t * ec_master_find_cached_sii_page(const ec_master_t *master, uint32_t vendor_id, uint32_t product_code, uint32_t revision, uint32_t serial, uint16_t alias)
Find a matching cached SII page.
Definition: master.c:2371
Taken from cache.
Definition: sii_page.h:40
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:210
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
unsigned int read_word_count
Number of words that have been read.
Definition: fsm_sii.h:63
ec_datagram_state_t state
State.
Definition: datagram.h:94
ec_pdo_mode_t pdo_assign_mode
Whether/how to read resp.
Definition: slave_config.h:126
Slave information interface memory page.
Definition: sii_page.h:47
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.
int ec_master_cache_sii_page(ec_master_t *master, const ec_sii_page_t *page)
Add an SII page to the cache.
Definition: master.c:2399
Use configured addresses.
Definition: fsm_sii.h:42
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:140
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:277
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:69
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
ec_slave_dc_range_t base_dc_range
DC range.
Definition: slave.h:204
uint8_t base_fmmu_bit_operation
FMMU bit operation is supported.
Definition: slave.h:202
int ec_sii_page_alloc(ec_sii_page_t *page, size_t word_count)
Free page memory.
Definition: sii_page.c:76
void ec_fsm_pdo_start_reading(ec_fsm_pdo_t *fsm, ec_slave_t *slave, ec_pdo_mode_t assign_mode, ec_pdo_mode_t config_mode)
Start reading the PDO configuration.
Definition: fsm_pdo.c:120
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 *)
uint16_t alias
Configured station alias.
Definition: slave.h:127
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:3315
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:200
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:188
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3222
ec_slave_port_desc_t desc
Port descriptors.
Definition: slave.h:112
Finite state machine for scanning an EtherCAT slave.
ec_master_t * master
Master owning the slave.
Definition: slave.h:171
#define EC_SII_WORD_OFFSET_VENDOR
Word offset of vendor ID.
Definition: globals.h:92
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:298
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:205
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:273
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:198
32 bit.
Definition: globals.h:179
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:91
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:81
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:187
Write the configured state via CoE every time the slave is configured, without reading the current st...
Definition: ecrt.h:555
uint16_t effective_alias
Effective alias address.
Definition: slave.h:178
uint8_t value[8]
raw SII value (32 bit / 64 bit)
Definition: fsm_sii.h:62
void ec_fsm_slave_scan_state_datalink(ec_fsm_slave_scan_t *)
Slave scan state: DATALINK.
unsigned int sii_caching
SII caching mode.
Definition: master.h:279
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition: fsm_sii.c:131
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:146
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3206
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:565
Mailbox functionality.
#define EC_STATE_STRING_SIZE
Minimum size of a buffer used with ec_state_string().
Definition: globals.h:54
#define EC_MAX_PORTS
Maximum number of slave ports.
Definition: ecrt.h:294
uint16_t * words
Complete SII image.
Definition: sii_page.h:60
#define EC_PDO_MODE_DEFAULT
Default PDO handling mode: read via CoE while scanning, and unconditionally (re-)write via CoE every ...
Definition: ecrt.h:575
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.
ec_sii_page_t sii_page
The SII contents, either fetched or taken from the cache.
Definition: slave.h:212
uint32_t receive_time
Port receive times for delay measurement.
Definition: slave.h:115
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:308
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:190
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:203
void ec_fsm_slave_scan_start(ec_fsm_slave_scan_t *fsm, ec_slave_t *slave)
Start slave scan state machine.
uint8_t * data
Datagram payload.
Definition: datagram.h:88
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:201
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3190
EtherCAT slave configuration.
Definition: slave_config.h:111
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 *)
Enter slave scan state SII_SIZE.
PREOP state (mailbox communication, no IO)
Definition: globals.h:132
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:186
void ec_fsm_slave_scan_state_address(ec_fsm_slave_scan_t *)
Slave scan state: ADDRESS.
void ec_fsm_slave_scan_state_state(ec_fsm_slave_scan_t *)
Slave scan state: STATE.
#define EC_MAX_SYNC_MANAGERS
Maximum number of sync managers per slave.
Definition: ecrt.h:285
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)