IgH EtherCAT Master  1.5.3
fsm_slave_config.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright (C) 2006-2023 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  *
22  * The license mentioned above concerns the source code only. Using the
23  * EtherCAT technology and brand is only permitted in compliance with the
24  * industrial property and similar rights of Beckhoff Automation GmbH.
25  *
26  *****************************************************************************/
27 
33 /*****************************************************************************/
34 
35 #include <asm/div64.h>
36 
37 #include "globals.h"
38 #include "master.h"
39 #include "mailbox.h"
40 #include "slave_config.h"
41 #include "fsm_slave_config.h"
42 
43 /*****************************************************************************/
44 
50 #define EC_DC_MAX_SYNC_DIFF_NS 10000
51 
54 #define EC_DC_SYNC_WAIT_MS 5000
55 
58 #define EC_DC_START_OFFSET 100000000ULL
59 
60 /*****************************************************************************/
61 
68 #ifdef EC_SII_ASSIGN
70 #endif
72 #ifdef EC_SII_ASSIGN
74 #endif
90 
95 #ifdef EC_SII_ASSIGN
97 #endif
111 
114 
116 
117 /*****************************************************************************/
118 
122  ec_fsm_slave_config_t *fsm,
123  ec_datagram_t *datagram,
124  ec_fsm_change_t *fsm_change,
125  ec_fsm_coe_t *fsm_coe,
126  ec_fsm_soe_t *fsm_soe,
127  ec_fsm_pdo_t *fsm_pdo
128  )
129 {
132 
133  fsm->datagram = datagram;
134  fsm->fsm_change = fsm_change;
135  fsm->fsm_coe = fsm_coe;
136  fsm->fsm_soe = fsm_soe;
137  fsm->fsm_pdo = fsm_pdo;
138 
139  fsm->wait_ms = 0;
140 }
141 
142 /*****************************************************************************/
143 
148  )
149 {
152 }
153 
154 /*****************************************************************************/
155 
159  ec_fsm_slave_config_t *fsm,
160  ec_slave_t *slave
161  )
162 {
163  fsm->slave = slave;
165 }
166 
167 /*****************************************************************************/
168 
173  const ec_fsm_slave_config_t *fsm
174  )
175 {
176  return fsm->state != ec_fsm_slave_config_state_end
178 }
179 
180 /*****************************************************************************/
181 
191  )
192 {
193  if (fsm->datagram->state == EC_DATAGRAM_SENT
194  || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
195  // datagram was not sent or received yet.
196  return ec_fsm_slave_config_running(fsm);
197  }
198 
199  fsm->state(fsm);
200  return ec_fsm_slave_config_running(fsm);
201 }
202 
203 /*****************************************************************************/
204 
209  const ec_fsm_slave_config_t *fsm
210  )
211 {
212  return fsm->state == ec_fsm_slave_config_state_end;
213 }
214 
215 /******************************************************************************
216  * Slave configuration state machine
217  *****************************************************************************/
218 
223  )
224 {
225  EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
227 }
228 
229 /*****************************************************************************/
230 
235  )
236 {
240 }
241 
242 /*****************************************************************************/
243 
248  )
249 {
250  ec_slave_t *slave = fsm->slave;
251  ec_datagram_t *datagram = fsm->datagram;
252 
253  if (ec_fsm_change_exec(fsm->fsm_change)) return;
254 
255  if (!ec_fsm_change_success(fsm->fsm_change)) {
256  if (!fsm->fsm_change->spontaneous_change)
257  slave->error_flag = 1;
259  return;
260  }
261 
262  EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
263 
264  if (!slave->base_fmmu_count) { // skip FMMU configuration
266  return;
267  }
268 
269  EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
270 
271  // clear FMMU configurations
272  ec_datagram_fpwr(datagram, slave->station_address,
273  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
274  ec_datagram_zero(datagram);
275  fsm->retries = EC_FSM_RETRIES;
277 }
278 
279 /*****************************************************************************/
280 
285  )
286 {
287  ec_datagram_t *datagram = fsm->datagram;
288 
289  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
290  return;
291 
292  if (datagram->state != EC_DATAGRAM_RECEIVED) {
294  EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
295  return;
296  }
297 
298  if (datagram->working_counter != 1) {
299  fsm->slave->error_flag = 1;
301  EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
302  ec_datagram_print_wc_error(datagram);
303  return;
304  }
305 
307 }
308 
309 /*****************************************************************************/
310 
315  )
316 {
317  ec_slave_t *slave = fsm->slave;
318  ec_datagram_t *datagram = fsm->datagram;
319  size_t sync_size;
320 
321  if (!slave->base_sync_count) {
322  // no sync managers
324  return;
325  }
326 
327  EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
328 
329  sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
330 
331  // clear sync manager configurations
332  ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
333  ec_datagram_zero(datagram);
334  fsm->retries = EC_FSM_RETRIES;
336 }
337 
338 /*****************************************************************************/
339 
344  )
345 {
346  ec_datagram_t *datagram = fsm->datagram;
347 
348  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
349  return;
350 
351  if (datagram->state != EC_DATAGRAM_RECEIVED) {
353  EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
354  " clearing datagram.\n");
355  return;
356  }
357 
358  if (datagram->working_counter != 1) {
359  fsm->slave->error_flag = 1;
361  EC_SLAVE_ERR(fsm->slave,
362  "Failed to clear sync manager configurations: ");
363  ec_datagram_print_wc_error(datagram);
364  return;
365  }
366 
368 }
369 
370 /*****************************************************************************/
371 
376  )
377 {
378  ec_slave_t *slave = fsm->slave;
379  ec_datagram_t *datagram = fsm->datagram;
380 
381  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
383  return;
384  }
385 
386  EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
387 
388  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
389  ec_datagram_zero(datagram);
390  fsm->retries = EC_FSM_RETRIES;
392 }
393 
394 /*****************************************************************************/
395 
400  )
401 {
402  ec_datagram_t *datagram = fsm->datagram;
403 
404  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
405  return;
406 
407  if (datagram->state != EC_DATAGRAM_RECEIVED) {
409  EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
410  " clearing datagram.\n");
411  return;
412  }
413 
414  if (datagram->working_counter != 1) {
415  // clearing the DC assignment does not succeed on simple slaves
416  EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
417  ec_datagram_print_wc_error(datagram);
418  }
419 
421 }
422 
423 /*****************************************************************************/
424 
429  )
430 {
431  ec_slave_t *slave = fsm->slave;
432  ec_datagram_t *datagram = fsm->datagram;
433  unsigned int i;
434 
435  // slave is now in INIT
436  if (slave->current_state == slave->requested_state) {
437  fsm->state = ec_fsm_slave_config_state_end; // successful
438  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
439  return;
440  }
441 
442  if (!slave->sii.mailbox_protocols) {
443  // no mailbox protocols supported
444  EC_SLAVE_DBG(slave, 1, "Slave does not support"
445  " mailbox communication.\n");
446 #ifdef EC_SII_ASSIGN
448 #else
450 #endif
451  return;
452  }
453 
454  EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
455 
456  if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
457  ec_sync_t sync;
458 
459  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
460  EC_SYNC_PAGE_SIZE * 2);
461  ec_datagram_zero(datagram);
462 
463  ec_sync_init(&sync, slave);
465  sync.control_register = 0x26;
466  sync.enable = 1;
467  ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
468  EC_DIR_INVALID, // use default direction
469  0, // no PDO xfer
470  datagram->data);
474  slave->sii.boot_rx_mailbox_size;
475 
476  ec_sync_init(&sync, slave);
478  sync.control_register = 0x22;
479  sync.enable = 1;
480  ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
481  EC_DIR_INVALID, // use default direction
482  0, // no PDO xfer
483  datagram->data + EC_SYNC_PAGE_SIZE);
487  slave->sii.boot_tx_mailbox_size;
488 
489  } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
490  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
491  EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
492  ec_datagram_zero(datagram);
493 
494  for (i = 0; i < 2; i++) {
495  ec_sync_page(&slave->sii.syncs[i], i,
496  slave->sii.syncs[i].default_length,
497  NULL, // use default sync manager configuration
498  0, // no PDO xfer
499  datagram->data + EC_SYNC_PAGE_SIZE * i);
500  }
501 
503  slave->sii.syncs[0].physical_start_address;
505  slave->sii.syncs[0].default_length;
507  slave->sii.syncs[1].physical_start_address;
509  slave->sii.syncs[1].default_length;
510  } else { // no mailbox sync manager configurations provided
511  ec_sync_t sync;
512 
513  EC_SLAVE_DBG(slave, 1, "Slave does not provide"
514  " mailbox sync manager configurations.\n");
515 
516  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
517  EC_SYNC_PAGE_SIZE * 2);
518  ec_datagram_zero(datagram);
519 
520  ec_sync_init(&sync, slave);
522  sync.control_register = 0x26;
523  sync.enable = 1;
524  ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
525  NULL, // use default sync manager configuration
526  0, // no PDO xfer
527  datagram->data);
529  slave->sii.std_rx_mailbox_offset;
531  slave->sii.std_rx_mailbox_size;
532 
533  ec_sync_init(&sync, slave);
535  sync.control_register = 0x22;
536  sync.enable = 1;
537  ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
538  NULL, // use default sync manager configuration
539  0, // no PDO xfer
540  datagram->data + EC_SYNC_PAGE_SIZE);
542  slave->sii.std_tx_mailbox_offset;
544  slave->sii.std_tx_mailbox_size;
545  }
546 
547  fsm->take_time = 1;
548 
549  fsm->retries = EC_FSM_RETRIES;
551 }
552 
553 /*****************************************************************************/
554 
561  )
562 {
563  ec_datagram_t *datagram = fsm->datagram;
564  ec_slave_t *slave = fsm->slave;
565 
566  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
567  return;
568 
569  if (datagram->state != EC_DATAGRAM_RECEIVED) {
571  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
572  " configuration datagram: ");
573  ec_datagram_print_state(datagram);
574  return;
575  }
576 
577  if (fsm->take_time) {
578  fsm->take_time = 0;
579  fsm->jiffies_start = datagram->jiffies_sent;
580  }
581 
582  /* Because the sync manager configurations are cleared during the last
583  * cycle, some slaves do not immediately respond to the mailbox sync
584  * manager configuration datagram. Therefore, resend the datagram for
585  * a certain time, if the slave does not respond.
586  */
587  if (datagram->working_counter == 0) {
588  unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
589 
590  if (diff >= HZ) {
591  slave->error_flag = 1;
593  EC_SLAVE_ERR(slave, "Timeout while configuring"
594  " mailbox sync managers.\n");
595  return;
596  } else {
597  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
598  (unsigned int) diff * 1000 / HZ);
599  }
600 
601  // send configuration datagram again
602  fsm->retries = EC_FSM_RETRIES;
603  return;
604  }
605  else if (datagram->working_counter != 1) {
606  slave->error_flag = 1;
608  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
609  ec_datagram_print_wc_error(datagram);
610  return;
611  }
612 
613 #ifdef EC_SII_ASSIGN
615 #else
617 #endif
618 }
619 
620 /*****************************************************************************/
621 
622 #ifdef EC_SII_ASSIGN
623 
628  )
629 {
630  ec_datagram_t *datagram = fsm->datagram;
631  ec_slave_t *slave = fsm->slave;
632 
634  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
635 
636  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
637  EC_WRITE_U8(datagram->data, 0x01); // PDI
638  fsm->retries = EC_FSM_RETRIES;
640  }
641  else {
643  }
644 }
645 
646 /*****************************************************************************/
647 
652  )
653 {
654  ec_datagram_t *datagram = fsm->datagram;
655  ec_slave_t *slave = fsm->slave;
656 
657  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
658  return;
659  }
660 
661  if (datagram->state != EC_DATAGRAM_RECEIVED) {
662  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
663  ec_datagram_print_state(datagram);
664  goto cont_preop;
665  }
666 
667  if (datagram->working_counter != 1) {
668  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
669  ec_datagram_print_wc_error(datagram);
670  }
671 
672 cont_preop:
674 }
675 
676 #endif
677 
678 /*****************************************************************************/
679 
684  )
685 {
687 
691  } else { // BOOT
693  fsm->slave, EC_SLAVE_STATE_BOOT);
694  }
695 
696  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
697 }
698 
699 /*****************************************************************************/
700 
705  )
706 {
707  ec_slave_t *slave = fsm->slave;
708 #ifdef EC_SII_ASSIGN
709  int assign_to_pdi;
710  ec_slave_config_t *config;
711  ec_flag_t *flag;
712 #endif
713 
714  if (ec_fsm_change_exec(fsm->fsm_change)) {
715  return;
716  }
717 
718  if (!ec_fsm_change_success(fsm->fsm_change)) {
719  if (!fsm->fsm_change->spontaneous_change)
720  slave->error_flag = 1;
722  return;
723  }
724 
725  // slave is now in BOOT or PREOP
726  slave->jiffies_preop = fsm->datagram->jiffies_received;
727 
728  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
729  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
730 
731 #ifdef EC_SII_ASSIGN
732  assign_to_pdi = 0;
733  config = fsm->slave->config;
734  if (config) {
735  flag = ec_slave_config_find_flag(config, "AssignToPdi");
736  if (flag) {
737  assign_to_pdi = flag->value;
738  }
739  }
740 
741  if (assign_to_pdi) {
742  EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
743  if (slave->current_state == slave->requested_state) {
744  fsm->state = ec_fsm_slave_config_state_end; // successful
745  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
746  return;
747  }
748 
750  }
751  else {
752  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
753 
754  ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
755  EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
756  fsm->retries = EC_FSM_RETRIES;
758  }
759 #else
760  if (slave->current_state == slave->requested_state) {
761  fsm->state = ec_fsm_slave_config_state_end; // successful
762  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
763  return;
764  }
765 
767 #endif
768 }
769 
770 /*****************************************************************************/
771 
772 #ifdef EC_SII_ASSIGN
773 
778  )
779 {
780  ec_datagram_t *datagram = fsm->datagram;
781  ec_slave_t *slave = fsm->slave;
782 
783  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
784  return;
785  }
786 
787  if (datagram->state != EC_DATAGRAM_RECEIVED) {
788  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
789  ec_datagram_print_state(datagram);
790  goto cont_sdo_conf;
791  }
792 
793  if (datagram->working_counter != 1) {
794  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
795  ec_datagram_print_wc_error(datagram);
796  }
797 
798 cont_sdo_conf:
799  if (slave->current_state == slave->requested_state) {
800  fsm->state = ec_fsm_slave_config_state_end; // successful
801  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
802  return;
803  }
804 
806 }
807 
808 #endif
809 
810 /*****************************************************************************/
811 
816  )
817 {
818  ec_slave_t *slave = fsm->slave;
819 
820  if (!slave->config) {
822  return;
823  }
824 
825  // No CoE configuration to be applied?
826  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
828  return;
829  }
830 
831  // start SDO configuration
833  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
834  ec_sdo_request_t, list);
837  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
838  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
839 }
840 
841 /*****************************************************************************/
842 
847  )
848 {
849  if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
850  return;
851  }
852 
853  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
854  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
855  fsm->slave->error_flag = 1;
857  return;
858  }
859 
860  if (!fsm->slave->config) { // config removed in the meantime
862  return;
863  }
864 
865  // Another SDO to configure?
866  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
867  fsm->request = list_entry(fsm->request->list.next,
868  ec_sdo_request_t, list);
871  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
872  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
873  return;
874  }
875 
876  // All SDOs are now configured.
878 }
879 
880 /*****************************************************************************/
881 
886  )
887 {
888  ec_slave_t *slave = fsm->slave;
889  ec_soe_request_t *req;
890 
891  if (!slave->config) {
893  return;
894  }
895 
896  list_for_each_entry(req, &slave->config->soe_configs, list) {
897  if (req->al_state == EC_AL_STATE_PREOP) {
898  // start SoE configuration
900  fsm->soe_request = req;
903  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
904  &fsm->soe_request_copy);
905  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
906  return;
907  }
908  }
909 
910  // No SoE configuration to be applied in PREOP
912 }
913 
914 /*****************************************************************************/
915 
920  )
921 {
922  ec_slave_t *slave = fsm->slave;
923 
924  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
925  return;
926  }
927 
928  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
929  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
930  fsm->slave->error_flag = 1;
932  return;
933  }
934 
935  if (!fsm->slave->config) { // config removed in the meantime
937  return;
938  }
939 
940  // Another IDN to configure in PREOP?
941  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
942  fsm->soe_request = list_entry(fsm->soe_request->list.next,
943  ec_soe_request_t, list);
944  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
947  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
948  &fsm->soe_request_copy);
949  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
950  return;
951  }
952  }
953 
954  // All PREOP IDNs are now configured.
956 }
957 
958 /*****************************************************************************/
959 
964  )
965 {
966  // Start configuring PDOs
969  fsm->state(fsm); // execute immediately
970 }
971 
972 /*****************************************************************************/
973 
978  )
979 {
980  // TODO check for config here
981 
982  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
983  return;
984  }
985 
986  if (!fsm->slave->config) { // config removed in the meantime
988  return;
989  }
990 
991  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
992  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
993  }
994 
996 }
997 
998 /*****************************************************************************/
999 
1003  ec_fsm_slave_config_t *fsm
1004  )
1005 {
1006  ec_slave_t *slave = fsm->slave;
1007  ec_datagram_t *datagram = fsm->datagram;
1008  ec_slave_config_t *config = slave->config;
1009 
1010  if (config && config->watchdog_divider) {
1011  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1012  config->watchdog_divider);
1013 
1014  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1015  EC_WRITE_U16(datagram->data, config->watchdog_divider);
1016  fsm->retries = EC_FSM_RETRIES;
1018  } else {
1020  }
1021 }
1022 
1023 /*****************************************************************************/
1024 
1028  ec_fsm_slave_config_t *fsm
1029  )
1030 {
1031  ec_datagram_t *datagram = fsm->datagram;
1032  ec_slave_t *slave = fsm->slave;
1033 
1034  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1035  return;
1036 
1037  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1039  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1040  " configuration datagram: ");
1041  ec_datagram_print_state(datagram);
1042  return;
1043  }
1044 
1045  if (datagram->working_counter != 1) {
1046  slave->error_flag = 1;
1047  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1048  ec_datagram_print_wc_error(datagram);
1049  return;
1050  }
1051 
1053 }
1054 
1055 /*****************************************************************************/
1056 
1060  ec_fsm_slave_config_t *fsm
1061  )
1062 {
1063  ec_datagram_t *datagram = fsm->datagram;
1064  ec_slave_t *slave = fsm->slave;
1065  ec_slave_config_t *config = slave->config;
1066 
1067  if (config && config->watchdog_intervals) {
1068  EC_SLAVE_DBG(slave, 1, "Setting process data"
1069  " watchdog intervals to %u.\n", config->watchdog_intervals);
1070 
1071  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1072  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1073 
1074  fsm->retries = EC_FSM_RETRIES;
1076  } else {
1078  }
1079 }
1080 
1081 /*****************************************************************************/
1082 
1087  ec_fsm_slave_config_t *fsm
1088  )
1089 {
1090  ec_datagram_t *datagram = fsm->datagram;
1091  ec_slave_t *slave = fsm->slave;
1092 
1093  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1094  return;
1095 
1096  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1098  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1099  " watchdog configuration datagram: ");
1100  ec_datagram_print_state(datagram);
1101  return;
1102  }
1103 
1104  if (datagram->working_counter != 1) {
1105  EC_SLAVE_WARN(slave, "Failed to set process data"
1106  " watchdog intervals: ");
1107  ec_datagram_print_wc_error(datagram);
1108  }
1109 
1111 }
1112 
1113 /*****************************************************************************/
1114 
1118  ec_fsm_slave_config_t *fsm
1119  )
1120 {
1121  ec_slave_t *slave = fsm->slave;
1122  ec_datagram_t *datagram = fsm->datagram;
1123  unsigned int i, j, offset, num_pdo_syncs;
1124  uint8_t sync_index;
1125  const ec_sync_t *sync;
1126  uint16_t size;
1127 
1128  if (slave->sii.mailbox_protocols) {
1129  offset = 2; // slave has mailboxes
1130  } else {
1131  offset = 0;
1132  }
1133 
1134  if (slave->sii.sync_count <= offset) {
1135  // no PDO sync managers to configure
1137  return;
1138  }
1139 
1140  num_pdo_syncs = slave->sii.sync_count - offset;
1141 
1142  // configure sync managers for process data
1143  ec_datagram_fpwr(datagram, slave->station_address,
1144  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1145  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1146  ec_datagram_zero(datagram);
1147 
1148  for (i = 0; i < num_pdo_syncs; i++) {
1149  const ec_sync_config_t *sync_config;
1150  uint8_t pdo_xfer = 0;
1151  sync_index = i + offset;
1152  sync = &slave->sii.syncs[sync_index];
1153 
1154  if (slave->config) {
1155  const ec_slave_config_t *sc = slave->config;
1156  sync_config = &sc->sync_configs[sync_index];
1157  size = ec_pdo_list_total_size(&sync_config->pdos);
1158 
1159  // determine, if PDOs shall be transferred via this SM
1160  // inthat case, enable sync manager in every case
1161  for (j = 0; j < sc->used_fmmus; j++) {
1162  if (sc->fmmu_configs[j].sync_index == sync_index) {
1163  pdo_xfer = 1;
1164  break;
1165  }
1166  }
1167 
1168  } else {
1169  sync_config = NULL;
1170  size = sync->default_length;
1171  }
1172 
1173  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1174  datagram->data + EC_SYNC_PAGE_SIZE * i);
1175  }
1176 
1177  fsm->retries = EC_FSM_RETRIES;
1179 }
1180 
1181 /*****************************************************************************/
1182 
1186  ec_fsm_slave_config_t *fsm
1187  )
1188 {
1189  ec_datagram_t *datagram = fsm->datagram;
1190  ec_slave_t *slave = fsm->slave;
1191 
1192  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1193  return;
1194 
1195  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1197  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1198  " manager configuration datagram: ");
1199  ec_datagram_print_state(datagram);
1200  return;
1201  }
1202 
1203  if (datagram->working_counter != 1) {
1204  slave->error_flag = 1;
1206  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1207  ec_datagram_print_wc_error(datagram);
1208  return;
1209  }
1210 
1212 }
1213 
1214 /*****************************************************************************/
1215 
1219  ec_fsm_slave_config_t *fsm
1220  )
1221 {
1222  ec_slave_t *slave = fsm->slave;
1223  ec_datagram_t *datagram = fsm->datagram;
1224  unsigned int i;
1225  const ec_fmmu_config_t *fmmu;
1226  const ec_sync_t *sync;
1227 
1228  if (!slave->config) {
1230  return;
1231  }
1232 
1233  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1234  slave->error_flag = 1;
1236  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1237  " than requested (%u).\n", slave->base_fmmu_count,
1238  slave->config->used_fmmus);
1239  return;
1240  }
1241 
1242  if (!slave->base_fmmu_count) { // skip FMMU configuration
1244  return;
1245  }
1246 
1247  // configure FMMUs
1248  ec_datagram_fpwr(datagram, slave->station_address,
1249  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1250  ec_datagram_zero(datagram);
1251  for (i = 0; i < slave->config->used_fmmus; i++) {
1252  fmmu = &slave->config->fmmu_configs[i];
1253  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1254  slave->error_flag = 1;
1256  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1257  " for FMMU!\n");
1258  return;
1259  }
1260  ec_fmmu_config_page(fmmu, sync,
1261  datagram->data + EC_FMMU_PAGE_SIZE * i);
1262  }
1263 
1264  fsm->retries = EC_FSM_RETRIES;
1266 }
1267 
1268 /*****************************************************************************/
1269 
1273  ec_fsm_slave_config_t *fsm
1274  )
1275 {
1276  ec_datagram_t *datagram = fsm->datagram;
1277  ec_slave_t *slave = fsm->slave;
1278 
1279  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1280  return;
1281 
1282  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1284  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1285  ec_datagram_print_state(datagram);
1286  return;
1287  }
1288 
1289  if (datagram->working_counter != 1) {
1290  slave->error_flag = 1;
1292  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1293  ec_datagram_print_wc_error(datagram);
1294  return;
1295  }
1296 
1298 }
1299 
1300 /*****************************************************************************/
1301 
1305  ec_fsm_slave_config_t *fsm
1306  )
1307 {
1308  ec_datagram_t *datagram = fsm->datagram;
1309  ec_slave_t *slave = fsm->slave;
1310  ec_slave_config_t *config = slave->config;
1311 
1312  if (!config) { // config removed in the meantime
1314  return;
1315  }
1316 
1317  if (config->dc_assign_activate) {
1318  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1319  EC_SLAVE_WARN(slave, "Slave seems not to support"
1320  " distributed clocks!\n");
1321  }
1322 
1323  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1324  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1325 
1326  // set DC cycle times
1327  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1328  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1329  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1330  fsm->retries = EC_FSM_RETRIES;
1332  } else {
1333  // DC are unused
1335  }
1336 }
1337 
1338 /*****************************************************************************/
1339 
1343  ec_fsm_slave_config_t *fsm
1344  )
1345 {
1346  ec_datagram_t *datagram = fsm->datagram;
1347  ec_slave_t *slave = fsm->slave;
1348  ec_slave_config_t *config = slave->config;
1349 
1350  if (!config) { // config removed in the meantime
1352  return;
1353  }
1354 
1355  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1356  return;
1357 
1358  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1360  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1361  ec_datagram_print_state(datagram);
1362  return;
1363  }
1364 
1365  if (datagram->working_counter != 1) {
1366  slave->error_flag = 1;
1368  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1369  ec_datagram_print_wc_error(datagram);
1370  return;
1371  }
1372 
1373  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1374 
1375  fsm->jiffies_start = jiffies;
1376  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1377  fsm->retries = EC_FSM_RETRIES;
1379 }
1380 
1381 /*****************************************************************************/
1382 
1386  ec_fsm_slave_config_t *fsm
1387  )
1388 {
1389  ec_datagram_t *datagram = fsm->datagram;
1390  ec_slave_t *slave = fsm->slave;
1391  ec_master_t *master = slave->master;
1392  ec_slave_config_t *config = slave->config;
1393  uint32_t abs_sync_diff;
1394  unsigned long diff_ms;
1395  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1396  ec_sync_signal_t *sync1 = &config->dc_sync[1];
1397  u64 start_time;
1398 
1399  if (!config) { // config removed in the meantime
1401  return;
1402  }
1403 
1404  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1405  return;
1406 
1407  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1409  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1410  ec_datagram_print_state(datagram);
1411  return;
1412  }
1413 
1414  if (datagram->working_counter != 1) {
1415  slave->error_flag = 1;
1417  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1418  ec_datagram_print_wc_error(datagram);
1419  return;
1420  }
1421 
1422  abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1423  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1424 
1425  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1426 
1427  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1428  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1429  diff_ms);
1430  } else {
1431  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1432  diff_ms, abs_sync_diff);
1433 
1434  // check synchrony again
1435  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1436  fsm->retries = EC_FSM_RETRIES;
1437  return;
1438  }
1439  } else {
1440  EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1441  abs_sync_diff, diff_ms);
1442  }
1443 
1444  // set DC start time (roughly in the future, not in-phase)
1445  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1446 
1447  if (sync0->cycle_time) {
1448  // find correct phase
1449  if (master->dc_ref_time) {
1450  u64 diff, start;
1451  u32 remainder, cycle;
1452 
1453  diff = start_time - master->dc_ref_time;
1454  cycle = sync0->cycle_time + sync1->cycle_time;
1455  remainder = do_div(diff, cycle);
1456 
1457  start = start_time + cycle - remainder + sync0->shift_time;
1458 
1459  EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1460  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1461  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1462  EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1463  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1464  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1465  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1466  start_time = start;
1467  } else {
1468  EC_SLAVE_WARN(slave, "No application time supplied."
1469  " Cyclic start time will not be in phase.\n");
1470  }
1471  }
1472 
1473  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1474  " start time to %llu.\n", start_time);
1475 
1476  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1477  EC_WRITE_U64(datagram->data, start_time);
1478  fsm->retries = EC_FSM_RETRIES;
1480 }
1481 
1482 /*****************************************************************************/
1483 
1487  ec_fsm_slave_config_t *fsm
1488  )
1489 {
1490  ec_datagram_t *datagram = fsm->datagram;
1491  ec_slave_t *slave = fsm->slave;
1492  ec_slave_config_t *config = slave->config;
1493 
1494  if (!config) { // config removed in the meantime
1496  return;
1497  }
1498 
1499  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1500  return;
1501 
1502  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1504  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1505  ec_datagram_print_state(datagram);
1506  return;
1507  }
1508 
1509  if (datagram->working_counter != 1) {
1510  slave->error_flag = 1;
1512  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1513  ec_datagram_print_wc_error(datagram);
1514  return;
1515  }
1516 
1517  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1518  config->dc_assign_activate);
1519 
1520  // assign sync unit to EtherCAT or PDI
1521  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1522  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1523  fsm->retries = EC_FSM_RETRIES;
1525 }
1526 
1527 /*****************************************************************************/
1528 
1532  ec_fsm_slave_config_t *fsm
1533  )
1534 {
1535  ec_datagram_t *datagram = fsm->datagram;
1536  ec_slave_t *slave = fsm->slave;
1537 
1538  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1539  return;
1540 
1541  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1543  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1544  ec_datagram_print_state(datagram);
1545  return;
1546  }
1547 
1548  if (datagram->working_counter != 1) {
1549  slave->error_flag = 1;
1551  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1552  ec_datagram_print_wc_error(datagram);
1553  return;
1554  }
1555 
1557 }
1558 
1559 /*****************************************************************************/
1560 
1568  ec_fsm_slave_config_t *fsm
1569  )
1570 {
1571  ec_slave_config_t *config = fsm->slave->config;
1572  fsm->wait_ms = 0UL;
1573  if (config) {
1574  ec_flag_t *flag = ec_slave_config_find_flag(config,
1575  "WaitBeforeSAFEOPms");
1576  if (flag && flag->value > 0) {
1577  fsm->wait_ms = (unsigned long) flag->value;
1578  }
1579  }
1580 
1581  if (fsm->wait_ms > 0) {
1583 
1584  /* dummy read */
1586  0x0600, 1);
1587 
1588  fsm->jiffies_start = jiffies;
1589  }
1590  else {
1592  }
1593 }
1594 
1595 /*****************************************************************************/
1596 
1600  ec_fsm_slave_config_t *fsm
1601  )
1602 {
1603  unsigned long diff = jiffies - fsm->jiffies_start;
1604 
1605  if (diff * 1000 / HZ < fsm->wait_ms) {
1606  return;
1607  }
1608 
1610 }
1611 
1612 /*****************************************************************************/
1613 
1617  ec_fsm_slave_config_t *fsm
1618  )
1619 {
1622  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1623 }
1624 
1625 /*****************************************************************************/
1626 
1630  ec_fsm_slave_config_t *fsm
1631  )
1632 {
1633  ec_slave_t *slave = fsm->slave;
1634 
1635  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1636 
1637  if (!ec_fsm_change_success(fsm->fsm_change)) {
1638  if (!fsm->fsm_change->spontaneous_change)
1639  fsm->slave->error_flag = 1;
1641  return;
1642  }
1643 
1644  // slave is now in SAFEOP
1645 
1646  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1647 
1648  if (fsm->slave->current_state == fsm->slave->requested_state) {
1649  fsm->state = ec_fsm_slave_config_state_end; // successful
1650  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1651  return;
1652  }
1653 
1655 }
1656 
1657 /*****************************************************************************/
1658 
1662  ec_fsm_slave_config_t *fsm
1663  )
1664 {
1665  ec_slave_t *slave = fsm->slave;
1666  ec_soe_request_t *req;
1667 
1668  if (!slave->config) {
1670  return;
1671  }
1672 
1673  list_for_each_entry(req, &slave->config->soe_configs, list) {
1674  if (req->al_state == EC_AL_STATE_SAFEOP) {
1675  // start SoE configuration
1677  fsm->soe_request = req;
1680  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1681  &fsm->soe_request_copy);
1682  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1683  return;
1684  }
1685  }
1686 
1687  // No SoE configuration to be applied in SAFEOP
1689 }
1690 
1691 /*****************************************************************************/
1692 
1696  ec_fsm_slave_config_t *fsm
1697  )
1698 {
1699  ec_slave_t *slave = fsm->slave;
1700 
1701  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1702  return;
1703  }
1704 
1705  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1706  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1707  fsm->slave->error_flag = 1;
1709  return;
1710  }
1711 
1712  if (!fsm->slave->config) { // config removed in the meantime
1714  return;
1715  }
1716 
1717  // Another IDN to configure in SAFEOP?
1718  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1719  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1720  ec_soe_request_t, list);
1721  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1724  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1725  &fsm->soe_request_copy);
1726  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1727  return;
1728  }
1729  }
1730 
1731  // All SAFEOP IDNs are now configured.
1733 }
1734 
1735 /*****************************************************************************/
1736 
1740  ec_fsm_slave_config_t *fsm
1741  )
1742 {
1743  // set state to OP
1746  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1747 }
1748 
1749 /*****************************************************************************/
1750 
1754  ec_fsm_slave_config_t *fsm
1755  )
1756 {
1757  ec_slave_t *slave = fsm->slave;
1758 
1759  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1760 
1761  if (!ec_fsm_change_success(fsm->fsm_change)) {
1762  if (!fsm->fsm_change->spontaneous_change)
1763  slave->error_flag = 1;
1765  return;
1766  }
1767 
1768  // slave is now in OP
1769 
1770  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1771 
1772  fsm->state = ec_fsm_slave_config_state_end; // successful
1773 }
1774 
1775 /*****************************************************************************/
1776 
1780  ec_fsm_slave_config_t *fsm
1781  )
1782 {
1783  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1784  "configuration. Reconfiguring.");
1785 
1786  ec_fsm_slave_config_enter_init(fsm); // reconfigure
1787 }
1788 
1789 /******************************************************************************
1790  * Common state functions
1791  *****************************************************************************/
1792 
1796  ec_fsm_slave_config_t *fsm
1797  )
1798 {
1799 }
1800 
1801 /*****************************************************************************/
1802 
1806  ec_fsm_slave_config_t *fsm
1807  )
1808 {
1809 }
1810 
1811 /*****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
Finite state machines for the Sercos over EtherCAT protocol.
Definition: fsm_soe.h:51
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
Pre-operational.
Definition: ecrt.h:559
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *)
Slave configuration state: BOOT/PREOP.
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:142
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:139
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:89
ec_sii_t sii
Extracted SII data.
Definition: slave.h:223
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:164
void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm, ec_slave_t *slave)
Start slave configuration state machine.
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *)
WATCHDOG entry function.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:201
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *)
Slave configuration state: INIT.
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SAFEOP.
void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *)
Assign SII to PDI.
FMMU configuration.
Definition: fmmu_config.h:46
ec_sdo_request_t * request
SDO request for SDO configuration.
void ec_fsm_slave_config_state_wait_safeop(ec_fsm_slave_config_t *)
Slave configuration state: WAIT SAFEOP.
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *)
Reconfigure the slave starting at INIT.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:106
void ec_fsm_pdo_start_configuration(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start writing the PDO configuration.
Definition: fsm_pdo.c:132
int32_t shift_time
Shift time [ns].
Definition: globals.h:173
OP (mailbox communication and input/output update)
Definition: globals.h:126
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:199
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *)
Slave configuration state: DC CYCLE.
ec_fsm_change_t * fsm_change
State change state machine.
CANopen SDO request.
Definition: sdo_request.h:46
ec_slave_state_t current_state
Current application state.
Definition: slave.h:192
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR DC ASSIGN.
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *)
Slave configuration state: DC START.
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:138
Safe-operational.
Definition: ecrt.h:560
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied in SAFEOP.
EtherCAT datagram.
Definition: datagram.h:87
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2401
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:239
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:122
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:172
void ec_fsm_change_start(ec_fsm_change_t *fsm, ec_slave_t *slave, ec_slave_state_t state)
Starts the change state machine.
Definition: fsm_change.c:90
uint16_t working_counter
Working counter.
Definition: datagram.h:99
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:262
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *)
Slave configuration state: START.
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:142
Sent (still in the queue).
Definition: datagram.h:77
void ec_fmmu_config_page(const ec_fmmu_config_t *fmmu, const ec_sync_t *sync, uint8_t *data)
Initializes an FMMU configuration page.
Definition: fmmu_config.c:76
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *)
Slave configuration state: SYNC.
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *)
Clear the DC assignment.
uint16_t station_address
Configured station address.
Definition: slave.h:184
unsigned int sync_count
Number of sync managers.
Definition: slave.h:166
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:144
void ec_fsm_slave_config_init(ec_fsm_slave_config_t *fsm, ec_datagram_t *datagram, ec_fsm_change_t *fsm_change, ec_fsm_coe_t *fsm_coe, ec_fsm_soe_t *fsm_soe, ec_fsm_pdo_t *fsm_pdo)
Constructor.
void ec_sync_page(const ec_sync_t *sync, uint8_t sync_index, uint16_t data_size, const ec_sync_config_t *sync_config, uint8_t pdo_xfer, uint8_t *data)
Initializes a sync manager configuration page.
Definition: sync.c:94
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:145
ec_al_state_t al_state
AL state (only valid for IDN config).
Definition: soe_request.h:52
EtherCAT master structure.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:137
SAFEOP (mailbox communication and input update)
Definition: globals.h:124
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *)
WATCHDOG_DIVIDER entry function.
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:140
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:141
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_PDI.
EtherCAT slave.
Definition: slave.h:176
void ec_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition: sdo_request.c:76
EtherCAT slave configuration state machine.
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
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
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
void ec_fsm_soe_transfer(ec_fsm_soe_t *fsm, ec_slave_t *slave, ec_soe_request_t *request)
Starts to transfer an IDN to/from a slave.
Definition: fsm_soe.c:128
int ec_fsm_soe_success(const ec_fsm_soe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_soe.c:185
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:135
ec_datagram_state_t state
State.
Definition: datagram.h:100
ec_slave_config_t * config
Current configuration.
Definition: slave.h:190
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2435
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
Slave configutation feature flag.
Definition: flag.h:38
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG_DIVIDER.
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:147
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
Definition: slave_config.c:608
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *)
State: END.
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm)
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
#define EC_DC_START_OFFSET
Time offset (in ns), that is added to cyclic start time.
Sync manager.
Definition: sync.h:47
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:143
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:124
struct list_head list
List item.
Definition: soe_request.h:49
void ec_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition: soe_request.c:77
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR FMMU.
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:49
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:139
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *)
Check for mailbox sync managers to be configured.
ec_datagram_t * datagram
Datagram used in the state machine.
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2418
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:207
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:195
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *)
Check for FMMUs to be configured.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2329
unsigned long wait_ms
Wait time (used to wait before SAFEOP).
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:129
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *)
Check for SDO configurations to be applied.
ec_master_t * master
Master owning the slave.
Definition: slave.h:178
int ec_sdo_request_copy(ec_sdo_request_t *req, const ec_sdo_request_t *other)
Copy another SDO request.
Definition: sdo_request.c:91
void ec_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied.
void(* state)(ec_fsm_slave_config_t *)
State function.
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:212
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *)
Start state change to INIT.
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: PDO_CONF.
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
uint8_t control_register
Control register value.
Definition: sync.h:51
ec_fsm_coe_t * fsm_coe
CoE state machine.
uint16_t watchdog_divider
Watchdog divider as a number of 40ns intervals (see spec.
Definition: slave_config.h:127
PDO configuration state machine.
Definition: fsm_pdo.h:54
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *)
Configure PDO sync managers.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *)
Request SAFEOP state.
ec_fsm_soe_t * fsm_soe
SoE state machine.
struct list_head soe_configs
List of SoE configurations.
Definition: slave_config.h:147
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
unsigned int take_time
Store jiffies after datagram reception.
INIT state (no mailbox communication, no IO)
Definition: globals.h:118
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:180
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.
uint8_t enable
Enable bit.
Definition: sync.h:52
ec_slave_t * slave
Slave the FSM runs on.
Invalid direction.
Definition: ecrt.h:447
void ec_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition: sdo_request.c:54
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *)
Slave configuration state: OP.
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2452
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:140
ec_soe_request_t soe_request_copy
Copied SDO request.
Sync manager configuration.
Definition: sync_config.h:46
int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm)
Executes the current state of the state machine.
struct list_head list
List item.
Definition: sdo_request.h:47
EtherCAT slave sync signal configuration.
Definition: globals.h:171
int ec_fsm_coe_exec(ec_fsm_coe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_coe.c:228
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR SYNC.
Queued for sending.
Definition: datagram.h:76
Timed out (dequeued).
Definition: datagram.h:79
void ec_fsm_slave_config_enter_wait_safeop(ec_fsm_slave_config_t *)
Wait before SAFEOP transition.
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *)
State: ERROR.
int32_t value
Flag value (meaning depends on key).
Definition: flag.h:41
void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *fsm)
Destructor.
u64 app_time
Time of the last ecrt_master_sync() call.
Definition: master.h:238
uint16_t physical_start_address
Physical start address.
Definition: sync.h:49
unsigned long jiffies_preop
Time, the slave went to PREOP.
Definition: slave.h:227
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:197
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:210
uint8_t * data
Datagram payload.
Definition: datagram.h:94
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *)
Slave configuration state: DC ASSIGN.
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:208
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *)
Bring slave to OP.
EtherCAT slave configuration.
Definition: slave_config.h:117
ec_soe_request_t * soe_request
SDO request for SDO configuration.
void ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
Definition: soe_request.c:246
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *)
Check for PDO sync managers to be configured.
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition: soe_request.c:54
EtherCAT slave configuration structure.
int ec_fsm_soe_exec(ec_fsm_soe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_soe.c:150
void ec_fsm_coe_transfer(ec_fsm_coe_t *fsm, ec_slave_t *slave, ec_sdo_request_t *request)
Starts to transfer an SDO to/from a slave.
Definition: fsm_coe.c:205
uint16_t default_length
Data length in bytes.
Definition: sync.h:50
void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_ETHERCAT.
PREOP state (mailbox communication, no IO)
Definition: globals.h:120
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: SDO_CONF.
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG.
Received (dequeued).
Definition: datagram.h:78
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *)
Request PREOP state.
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:193
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:165
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:146
EtherCAT master.
Definition: master.h:194
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:191
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:95
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c:46
void ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:235
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *)
Slave configuration state: DC SYNC CHECK.
#define EC_DC_SYNC_WAIT_MS
Maximum time (in ms) to wait for clock discipline.
Sercos-over-EtherCAT request.
Definition: soe_request.h:48
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
EtherCAT state change FSM.
Definition: fsm_change.h:64
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *)
Check for DC to be configured.
int ec_soe_request_copy(ec_soe_request_t *req, const ec_soe_request_t *other)
Copy another SoE request.
Definition: soe_request.c:90
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:139
unsigned long jiffies_start
For timeout calculations.
Finite state machines for the CANopen over EtherCAT protocol.
Definition: fsm_coe.h:52
ec_sync_t * ec_slave_get_sync(ec_slave_t *slave, uint8_t sync_index)
Get the sync manager given an index.
Definition: slave.c:590
unsigned int retries
Retries on datagram timeout.