IgH EtherCAT Master  1.5.2
fsm_slave_config.c
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
6 *
7 * This file is part of the IgH EtherCAT Master.
8 *
9 * The IgH EtherCAT Master is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version 2, as
11 * published by the Free Software Foundation.
12 *
13 * The IgH EtherCAT Master is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 * Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with the IgH EtherCAT Master; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * ---
23 *
24 * The license mentioned above concerns the source code only. Using the
25 * EtherCAT technology and brand is only permitted in compliance with the
26 * industrial property and similar rights of Beckhoff Automation GmbH.
27 *
28 *****************************************************************************/
29
35/*****************************************************************************/
36
37#include <asm/div64.h>
38
39#include "globals.h"
40#include "master.h"
41#include "mailbox.h"
42#include "slave_config.h"
43#include "fsm_slave_config.h"
44
45/*****************************************************************************/
46
52#define EC_DC_MAX_SYNC_DIFF_NS 10000
53
56#define EC_DC_SYNC_WAIT_MS 5000
57
60#define EC_DC_START_OFFSET 100000000ULL
61
62/*****************************************************************************/
63
70#ifdef EC_SII_ASSIGN
72#endif
74#ifdef EC_SII_ASSIGN
76#endif
91
96#ifdef EC_SII_ASSIGN
98#endif
111
114
116
117/*****************************************************************************/
118
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
140/*****************************************************************************/
141
146 )
147{
150}
151
152/*****************************************************************************/
153
158 ec_slave_t *slave
159 )
160{
161 fsm->slave = slave;
163}
164
165/*****************************************************************************/
166
171 const ec_fsm_slave_config_t *fsm
172 )
173{
176}
177
178/*****************************************************************************/
179
189 )
190{
191 if (fsm->datagram->state == EC_DATAGRAM_SENT
192 || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
193 // datagram was not sent or received yet.
194 return ec_fsm_slave_config_running(fsm);
195 }
196
197 fsm->state(fsm);
198 return ec_fsm_slave_config_running(fsm);
199}
200
201/*****************************************************************************/
202
207 const ec_fsm_slave_config_t *fsm
208 )
209{
211}
212
213/******************************************************************************
214 * Slave configuration state machine
215 *****************************************************************************/
216
221 )
222{
223 EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
225}
226
227/*****************************************************************************/
228
233 )
234{
238}
239
240/*****************************************************************************/
241
246 )
247{
248 ec_slave_t *slave = fsm->slave;
249 ec_datagram_t *datagram = fsm->datagram;
250
251 if (ec_fsm_change_exec(fsm->fsm_change)) return;
252
255 slave->error_flag = 1;
257 return;
258 }
259
260 EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
261
262 if (!slave->base_fmmu_count) { // skip FMMU configuration
264 return;
265 }
266
267 EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
268
269 // clear FMMU configurations
270 ec_datagram_fpwr(datagram, slave->station_address,
271 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
272 ec_datagram_zero(datagram);
273 fsm->retries = EC_FSM_RETRIES;
275}
276
277/*****************************************************************************/
278
283 )
284{
285 ec_datagram_t *datagram = fsm->datagram;
286
287 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
288 return;
289
290 if (datagram->state != EC_DATAGRAM_RECEIVED) {
292 EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
293 return;
294 }
295
296 if (datagram->working_counter != 1) {
297 fsm->slave->error_flag = 1;
299 EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
301 return;
302 }
303
305}
306
307/*****************************************************************************/
308
313 )
314{
315 ec_slave_t *slave = fsm->slave;
316 ec_datagram_t *datagram = fsm->datagram;
317 size_t sync_size;
318
319 if (!slave->base_sync_count) {
320 // no sync managers
322 return;
323 }
324
325 EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
326
327 sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
328
329 // clear sync manager configurations
330 ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
331 ec_datagram_zero(datagram);
332 fsm->retries = EC_FSM_RETRIES;
334}
335
336/*****************************************************************************/
337
342 )
343{
344 ec_datagram_t *datagram = fsm->datagram;
345
346 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
347 return;
348
349 if (datagram->state != EC_DATAGRAM_RECEIVED) {
351 EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
352 " clearing datagram.\n");
353 return;
354 }
355
356 if (datagram->working_counter != 1) {
357 fsm->slave->error_flag = 1;
359 EC_SLAVE_ERR(fsm->slave,
360 "Failed to clear sync manager configurations: ");
362 return;
363 }
364
366}
367
368/*****************************************************************************/
369
374 )
375{
376 ec_slave_t *slave = fsm->slave;
377 ec_datagram_t *datagram = fsm->datagram;
378
379 if (!slave->base_dc_supported || !slave->has_dc_system_time) {
381 return;
382 }
383
384 EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
385
386 ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
387 ec_datagram_zero(datagram);
388 fsm->retries = EC_FSM_RETRIES;
390}
391
392/*****************************************************************************/
393
398 )
399{
400 ec_datagram_t *datagram = fsm->datagram;
401
402 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
403 return;
404
405 if (datagram->state != EC_DATAGRAM_RECEIVED) {
407 EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
408 " clearing datagram.\n");
409 return;
410 }
411
412 if (datagram->working_counter != 1) {
413 // clearing the DC assignment does not succeed on simple slaves
414 EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
416 }
417
419}
420
421/*****************************************************************************/
422
427 )
428{
429 ec_slave_t *slave = fsm->slave;
430 ec_datagram_t *datagram = fsm->datagram;
431 unsigned int i;
432
433 // slave is now in INIT
434 if (slave->current_state == slave->requested_state) {
435 fsm->state = ec_fsm_slave_config_state_end; // successful
436 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
437 return;
438 }
439
440 if (!slave->sii.mailbox_protocols) {
441 // no mailbox protocols supported
442 EC_SLAVE_DBG(slave, 1, "Slave does not support"
443 " mailbox communication.\n");
444#ifdef EC_SII_ASSIGN
446#else
448#endif
449 return;
450 }
451
452 EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
453
454 if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
455 ec_sync_t sync;
456
457 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
459 ec_datagram_zero(datagram);
460
461 ec_sync_init(&sync, slave);
463 sync.control_register = 0x26;
464 sync.enable = 1;
465 ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
466 EC_DIR_INVALID, // use default direction
467 0, // no PDO xfer
468 datagram->data);
473
474 ec_sync_init(&sync, slave);
476 sync.control_register = 0x22;
477 sync.enable = 1;
478 ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
479 EC_DIR_INVALID, // use default direction
480 0, // no PDO xfer
481 datagram->data + EC_SYNC_PAGE_SIZE);
486
487 } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
488 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
490 ec_datagram_zero(datagram);
491
492 for (i = 0; i < 2; i++) {
493 ec_sync_page(&slave->sii.syncs[i], i,
494 slave->sii.syncs[i].default_length,
495 NULL, // use default sync manager configuration
496 0, // no PDO xfer
497 datagram->data + EC_SYNC_PAGE_SIZE * i);
498 }
499
503 slave->sii.syncs[0].default_length;
507 slave->sii.syncs[1].default_length;
508 } else { // no mailbox sync manager configurations provided
509 ec_sync_t sync;
510
511 EC_SLAVE_DBG(slave, 1, "Slave does not provide"
512 " mailbox sync manager configurations.\n");
513
514 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
516 ec_datagram_zero(datagram);
517
518 ec_sync_init(&sync, slave);
520 sync.control_register = 0x26;
521 sync.enable = 1;
522 ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
523 NULL, // use default sync manager configuration
524 0, // no PDO xfer
525 datagram->data);
530
531 ec_sync_init(&sync, slave);
533 sync.control_register = 0x22;
534 sync.enable = 1;
535 ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
536 NULL, // use default sync manager configuration
537 0, // no PDO xfer
538 datagram->data + EC_SYNC_PAGE_SIZE);
543 }
544
545 fsm->take_time = 1;
546
547 fsm->retries = EC_FSM_RETRIES;
549}
550
551/*****************************************************************************/
552
559 )
560{
561 ec_datagram_t *datagram = fsm->datagram;
562 ec_slave_t *slave = fsm->slave;
563
564 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
565 return;
566
567 if (datagram->state != EC_DATAGRAM_RECEIVED) {
569 EC_SLAVE_ERR(slave, "Failed to receive sync manager"
570 " configuration datagram: ");
571 ec_datagram_print_state(datagram);
572 return;
573 }
574
575 if (fsm->take_time) {
576 fsm->take_time = 0;
577 fsm->jiffies_start = datagram->jiffies_sent;
578 }
579
580 /* Because the sync manager configurations are cleared during the last
581 * cycle, some slaves do not immediately respond to the mailbox sync
582 * manager configuration datagram. Therefore, resend the datagram for
583 * a certain time, if the slave does not respond.
584 */
585 if (datagram->working_counter == 0) {
586 unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
587
588 if (diff >= HZ) {
589 slave->error_flag = 1;
591 EC_SLAVE_ERR(slave, "Timeout while configuring"
592 " mailbox sync managers.\n");
593 return;
594 } else {
595 EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
596 (unsigned int) diff * 1000 / HZ);
597 }
598
599 // send configuration datagram again
600 fsm->retries = EC_FSM_RETRIES;
601 return;
602 }
603 else if (datagram->working_counter != 1) {
604 slave->error_flag = 1;
606 EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
608 return;
609 }
610
611#ifdef EC_SII_ASSIGN
613#else
615#endif
616}
617
618/*****************************************************************************/
619
620#ifdef EC_SII_ASSIGN
621
626 )
627{
628 ec_datagram_t *datagram = fsm->datagram;
629 ec_slave_t *slave = fsm->slave;
630
632 EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
633
634 ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
635 EC_WRITE_U8(datagram->data, 0x01); // PDI
636 fsm->retries = EC_FSM_RETRIES;
638 }
639 else {
641 }
642}
643
644/*****************************************************************************/
645
650 )
651{
652 ec_datagram_t *datagram = fsm->datagram;
653 ec_slave_t *slave = fsm->slave;
654
655 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
656 return;
657 }
658
659 if (datagram->state != EC_DATAGRAM_RECEIVED) {
660 EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
661 ec_datagram_print_state(datagram);
662 goto cont_preop;
663 }
664
665 if (datagram->working_counter != 1) {
666 EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
668 }
669
670cont_preop:
672}
673
674#endif
675
676/*****************************************************************************/
677
682 )
683{
685
689 } else { // BOOT
692 }
693
694 ec_fsm_change_exec(fsm->fsm_change); // execute immediately
695}
696
697/*****************************************************************************/
698
703 )
704{
705 ec_slave_t *slave = fsm->slave;
706#ifdef EC_SII_ASSIGN
707 int assign_to_pdi;
708 ec_slave_config_t *config;
709 ec_flag_t *flag;
710#endif
711
712 if (ec_fsm_change_exec(fsm->fsm_change)) {
713 return;
714 }
715
718 slave->error_flag = 1;
720 return;
721 }
722
723 // slave is now in BOOT or PREOP
725
726 EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
727 slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
728
729#ifdef EC_SII_ASSIGN
730 assign_to_pdi = 0;
731 config = fsm->slave->config;
732 if (config) {
733 flag = ec_slave_config_find_flag(config, "AssignToPdi");
734 if (flag) {
735 assign_to_pdi = flag->value;
736 }
737 }
738
739 if (assign_to_pdi) {
740 EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
741 if (slave->current_state == slave->requested_state) {
742 fsm->state = ec_fsm_slave_config_state_end; // successful
743 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
744 return;
745 }
746
748 }
749 else {
750 EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
751
752 ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
753 EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
754 fsm->retries = EC_FSM_RETRIES;
756 }
757#else
758 if (slave->current_state == slave->requested_state) {
759 fsm->state = ec_fsm_slave_config_state_end; // successful
760 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
761 return;
762 }
763
765#endif
766}
767
768/*****************************************************************************/
769
770#ifdef EC_SII_ASSIGN
771
776 )
777{
778 ec_datagram_t *datagram = fsm->datagram;
779 ec_slave_t *slave = fsm->slave;
780
781 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
782 return;
783 }
784
785 if (datagram->state != EC_DATAGRAM_RECEIVED) {
786 EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
787 ec_datagram_print_state(datagram);
788 goto cont_sdo_conf;
789 }
790
791 if (datagram->working_counter != 1) {
792 EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
794 }
795
796cont_sdo_conf:
797 if (slave->current_state == slave->requested_state) {
798 fsm->state = ec_fsm_slave_config_state_end; // successful
799 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
800 return;
801 }
802
804}
805
806#endif
807
808/*****************************************************************************/
809
814 )
815{
816 ec_slave_t *slave = fsm->slave;
817
818 if (!slave->config) {
820 return;
821 }
822
823 // No CoE configuration to be applied?
824 if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
826 return;
827 }
828
829 // start SDO configuration
831 fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
832 ec_sdo_request_t, list);
836 ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
837}
838
839/*****************************************************************************/
840
845 )
846{
847 if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
848 return;
849 }
850
851 if (!ec_fsm_coe_success(fsm->fsm_coe)) {
852 EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
853 fsm->slave->error_flag = 1;
855 return;
856 }
857
858 if (!fsm->slave->config) { // config removed in the meantime
860 return;
861 }
862
863 // Another SDO to configure?
864 if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
865 fsm->request = list_entry(fsm->request->list.next,
866 ec_sdo_request_t, list);
870 ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
871 return;
872 }
873
874 // All SDOs are now configured.
876}
877
878/*****************************************************************************/
879
884 )
885{
886 ec_slave_t *slave = fsm->slave;
887 ec_soe_request_t *req;
888
889 if (!slave->config) {
891 return;
892 }
893
894 list_for_each_entry(req, &slave->config->soe_configs, list) {
895 if (req->al_state == EC_AL_STATE_PREOP) {
896 // start SoE configuration
898 fsm->soe_request = req;
902 &fsm->soe_request_copy);
903 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
904 return;
905 }
906 }
907
908 // No SoE configuration to be applied in PREOP
910}
911
912/*****************************************************************************/
913
918 )
919{
920 ec_slave_t *slave = fsm->slave;
921
922 if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
923 return;
924 }
925
926 if (!ec_fsm_soe_success(fsm->fsm_soe)) {
927 EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
928 fsm->slave->error_flag = 1;
930 return;
931 }
932
933 if (!fsm->slave->config) { // config removed in the meantime
935 return;
936 }
937
938 // Another IDN to configure in PREOP?
939 while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
940 fsm->soe_request = list_entry(fsm->soe_request->list.next,
941 ec_soe_request_t, list);
946 &fsm->soe_request_copy);
947 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
948 return;
949 }
950 }
951
952 // All PREOP IDNs are now configured.
954}
955
956/*****************************************************************************/
957
962 )
963{
964 // Start configuring PDOs
967 fsm->state(fsm); // execute immediately
968}
969
970/*****************************************************************************/
971
976 )
977{
978 // TODO check for config here
979
980 if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
981 return;
982 }
983
984 if (!fsm->slave->config) { // config removed in the meantime
986 return;
987 }
988
989 if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
990 EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
991 }
992
994}
995
996/*****************************************************************************/
997
1002 )
1003{
1004 ec_slave_t *slave = fsm->slave;
1005 ec_datagram_t *datagram = fsm->datagram;
1006 ec_slave_config_t *config = slave->config;
1007
1008 if (config && config->watchdog_divider) {
1009 EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1010 config->watchdog_divider);
1011
1012 ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1013 EC_WRITE_U16(datagram->data, config->watchdog_divider);
1014 fsm->retries = EC_FSM_RETRIES;
1016 } else {
1018 }
1019}
1020
1021/*****************************************************************************/
1022
1027 )
1028{
1029 ec_datagram_t *datagram = fsm->datagram;
1030 ec_slave_t *slave = fsm->slave;
1031
1032 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1033 return;
1034
1035 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1037 EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1038 " configuration datagram: ");
1039 ec_datagram_print_state(datagram);
1040 return;
1041 }
1042
1043 if (datagram->working_counter != 1) {
1044 slave->error_flag = 1;
1045 EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1047 return;
1048 }
1049
1051}
1052
1053/*****************************************************************************/
1054
1059 )
1060{
1061 ec_datagram_t *datagram = fsm->datagram;
1062 ec_slave_t *slave = fsm->slave;
1063 ec_slave_config_t *config = slave->config;
1064
1065 if (config && config->watchdog_intervals) {
1066 EC_SLAVE_DBG(slave, 1, "Setting process data"
1067 " watchdog intervals to %u.\n", config->watchdog_intervals);
1068
1069 ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1070 EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1071
1072 fsm->retries = EC_FSM_RETRIES;
1074 } else {
1076 }
1077}
1078
1079/*****************************************************************************/
1080
1086 )
1087{
1088 ec_datagram_t *datagram = fsm->datagram;
1089 ec_slave_t *slave = fsm->slave;
1090
1091 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1092 return;
1093
1094 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1096 EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1097 " watchdog configuration datagram: ");
1098 ec_datagram_print_state(datagram);
1099 return;
1100 }
1101
1102 if (datagram->working_counter != 1) {
1103 EC_SLAVE_WARN(slave, "Failed to set process data"
1104 " watchdog intervals: ");
1106 }
1107
1109}
1110
1111/*****************************************************************************/
1112
1117 )
1118{
1119 ec_slave_t *slave = fsm->slave;
1120 ec_datagram_t *datagram = fsm->datagram;
1121 unsigned int i, j, offset, num_pdo_syncs;
1122 uint8_t sync_index;
1123 const ec_sync_t *sync;
1124 uint16_t size;
1125
1126 if (slave->sii.mailbox_protocols) {
1127 offset = 2; // slave has mailboxes
1128 } else {
1129 offset = 0;
1130 }
1131
1132 if (slave->sii.sync_count <= offset) {
1133 // no PDO sync managers to configure
1135 return;
1136 }
1137
1138 num_pdo_syncs = slave->sii.sync_count - offset;
1139
1140 // configure sync managers for process data
1141 ec_datagram_fpwr(datagram, slave->station_address,
1142 0x0800 + EC_SYNC_PAGE_SIZE * offset,
1143 EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1144 ec_datagram_zero(datagram);
1145
1146 for (i = 0; i < num_pdo_syncs; i++) {
1147 const ec_sync_config_t *sync_config;
1148 uint8_t pdo_xfer = 0;
1149 sync_index = i + offset;
1150 sync = &slave->sii.syncs[sync_index];
1151
1152 if (slave->config) {
1153 const ec_slave_config_t *sc = slave->config;
1154 sync_config = &sc->sync_configs[sync_index];
1155 size = ec_pdo_list_total_size(&sync_config->pdos);
1156
1157 // determine, if PDOs shall be transferred via this SM
1158 // inthat case, enable sync manager in every case
1159 for (j = 0; j < sc->used_fmmus; j++) {
1160 if (sc->fmmu_configs[j].sync_index == sync_index) {
1161 pdo_xfer = 1;
1162 break;
1163 }
1164 }
1165
1166 } else {
1167 sync_config = NULL;
1168 size = sync->default_length;
1169 }
1170
1171 ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1172 datagram->data + EC_SYNC_PAGE_SIZE * i);
1173 }
1174
1175 fsm->retries = EC_FSM_RETRIES;
1177}
1178
1179/*****************************************************************************/
1180
1185 )
1186{
1187 ec_datagram_t *datagram = fsm->datagram;
1188 ec_slave_t *slave = fsm->slave;
1189
1190 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1191 return;
1192
1193 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1195 EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1196 " manager configuration datagram: ");
1197 ec_datagram_print_state(datagram);
1198 return;
1199 }
1200
1201 if (datagram->working_counter != 1) {
1202 slave->error_flag = 1;
1204 EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1206 return;
1207 }
1208
1210}
1211
1212/*****************************************************************************/
1213
1218 )
1219{
1220 ec_slave_t *slave = fsm->slave;
1221 ec_datagram_t *datagram = fsm->datagram;
1222 unsigned int i;
1223 const ec_fmmu_config_t *fmmu;
1224 const ec_sync_t *sync;
1225
1226 if (!slave->config) {
1228 return;
1229 }
1230
1231 if (slave->base_fmmu_count < slave->config->used_fmmus) {
1232 slave->error_flag = 1;
1234 EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1235 " than requested (%u).\n", slave->base_fmmu_count,
1236 slave->config->used_fmmus);
1237 return;
1238 }
1239
1240 if (!slave->base_fmmu_count) { // skip FMMU configuration
1242 return;
1243 }
1244
1245 // configure FMMUs
1246 ec_datagram_fpwr(datagram, slave->station_address,
1247 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1248 ec_datagram_zero(datagram);
1249 for (i = 0; i < slave->config->used_fmmus; i++) {
1250 fmmu = &slave->config->fmmu_configs[i];
1251 if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1252 slave->error_flag = 1;
1254 EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1255 " for FMMU!\n");
1256 return;
1257 }
1258 ec_fmmu_config_page(fmmu, sync,
1259 datagram->data + EC_FMMU_PAGE_SIZE * i);
1260 }
1261
1262 fsm->retries = EC_FSM_RETRIES;
1264}
1265
1266/*****************************************************************************/
1267
1272 )
1273{
1274 ec_datagram_t *datagram = fsm->datagram;
1275 ec_slave_t *slave = fsm->slave;
1276
1277 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1278 return;
1279
1280 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1282 EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1283 ec_datagram_print_state(datagram);
1284 return;
1285 }
1286
1287 if (datagram->working_counter != 1) {
1288 slave->error_flag = 1;
1290 EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1292 return;
1293 }
1294
1296}
1297
1298/*****************************************************************************/
1299
1304 )
1305{
1306 ec_datagram_t *datagram = fsm->datagram;
1307 ec_slave_t *slave = fsm->slave;
1308 ec_slave_config_t *config = slave->config;
1309
1310 if (!config) { // config removed in the meantime
1312 return;
1313 }
1314
1315 if (config->dc_assign_activate) {
1316 if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1317 EC_SLAVE_WARN(slave, "Slave seems not to support"
1318 " distributed clocks!\n");
1319 }
1320
1321 EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1322 config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1323
1324 // set DC cycle times
1325 ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1326 EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1327 EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1328 fsm->retries = EC_FSM_RETRIES;
1330 } else {
1331 // DC are unused
1333 }
1334}
1335
1336/*****************************************************************************/
1337
1342 )
1343{
1344 ec_datagram_t *datagram = fsm->datagram;
1345 ec_slave_t *slave = fsm->slave;
1346 ec_slave_config_t *config = slave->config;
1347
1348 if (!config) { // config removed in the meantime
1350 return;
1351 }
1352
1353 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1354 return;
1355
1356 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1358 EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1359 ec_datagram_print_state(datagram);
1360 return;
1361 }
1362
1363 if (datagram->working_counter != 1) {
1364 slave->error_flag = 1;
1366 EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1368 return;
1369 }
1370
1371 EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1372
1373 fsm->jiffies_start = jiffies;
1374 ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1375 fsm->retries = EC_FSM_RETRIES;
1377}
1378
1379/*****************************************************************************/
1380
1385 )
1386{
1387 ec_datagram_t *datagram = fsm->datagram;
1388 ec_slave_t *slave = fsm->slave;
1389 ec_master_t *master = slave->master;
1390 ec_slave_config_t *config = slave->config;
1391 uint32_t abs_sync_diff;
1392 unsigned long diff_ms;
1393 ec_sync_signal_t *sync0 = &config->dc_sync[0];
1394 ec_sync_signal_t *sync1 = &config->dc_sync[1];
1395 u64 start_time;
1396
1397 if (!config) { // config removed in the meantime
1399 return;
1400 }
1401
1402 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1403 return;
1404
1405 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1407 EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1408 ec_datagram_print_state(datagram);
1409 return;
1410 }
1411
1412 if (datagram->working_counter != 1) {
1413 slave->error_flag = 1;
1415 EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1417 return;
1418 }
1419
1420 abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1421 diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1422
1423 if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1424
1425 if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1426 EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1427 diff_ms);
1428 } else {
1429 EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1430 diff_ms, abs_sync_diff);
1431
1432 // check synchrony again
1433 ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1434 fsm->retries = EC_FSM_RETRIES;
1435 return;
1436 }
1437 } else {
1438 EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1439 abs_sync_diff, diff_ms);
1440 }
1441
1442 // set DC start time (roughly in the future, not in-phase)
1443 start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1444
1445 if (sync0->cycle_time) {
1446 // find correct phase
1447 if (master->dc_ref_time) {
1448 u64 diff, start;
1449 u32 remainder, cycle;
1450
1451 diff = start_time - master->dc_ref_time;
1452 cycle = sync0->cycle_time + sync1->cycle_time;
1453 remainder = do_div(diff, cycle);
1454
1455 start = start_time + cycle - remainder + sync0->shift_time;
1456
1457 EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1458 EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1459 EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1460 EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1461 EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1462 EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1463 EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1464 start_time = start;
1465 } else {
1466 EC_SLAVE_WARN(slave, "No application time supplied."
1467 " Cyclic start time will not be in phase.\n");
1468 }
1469 }
1470
1471 EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1472 " start time to %llu.\n", start_time);
1473
1474 ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1475 EC_WRITE_U64(datagram->data, start_time);
1476 fsm->retries = EC_FSM_RETRIES;
1478}
1479
1480/*****************************************************************************/
1481
1486 )
1487{
1488 ec_datagram_t *datagram = fsm->datagram;
1489 ec_slave_t *slave = fsm->slave;
1490 ec_slave_config_t *config = slave->config;
1491
1492 if (!config) { // config removed in the meantime
1494 return;
1495 }
1496
1497 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1498 return;
1499
1500 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1502 EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1503 ec_datagram_print_state(datagram);
1504 return;
1505 }
1506
1507 if (datagram->working_counter != 1) {
1508 slave->error_flag = 1;
1510 EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1512 return;
1513 }
1514
1515 EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1516 config->dc_assign_activate);
1517
1518 // assign sync unit to EtherCAT or PDI
1519 ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1520 EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1521 fsm->retries = EC_FSM_RETRIES;
1523}
1524
1525/*****************************************************************************/
1526
1531 )
1532{
1533 ec_datagram_t *datagram = fsm->datagram;
1534 ec_slave_t *slave = fsm->slave;
1535
1536 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1537 return;
1538
1539 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1541 EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1542 ec_datagram_print_state(datagram);
1543 return;
1544 }
1545
1546 if (datagram->working_counter != 1) {
1547 slave->error_flag = 1;
1549 EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1551 return;
1552 }
1553
1555}
1556
1557/*****************************************************************************/
1558
1563 )
1564{
1567 ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1568}
1569
1570/*****************************************************************************/
1571
1576 )
1577{
1578 ec_slave_t *slave = fsm->slave;
1579
1580 if (ec_fsm_change_exec(fsm->fsm_change)) return;
1581
1582 if (!ec_fsm_change_success(fsm->fsm_change)) {
1583 if (!fsm->fsm_change->spontaneous_change)
1584 fsm->slave->error_flag = 1;
1586 return;
1587 }
1588
1589 // slave is now in SAFEOP
1590
1591 EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1592
1593 if (fsm->slave->current_state == fsm->slave->requested_state) {
1594 fsm->state = ec_fsm_slave_config_state_end; // successful
1595 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1596 return;
1597 }
1598
1600}
1601
1602/*****************************************************************************/
1603
1608 )
1609{
1610 ec_slave_t *slave = fsm->slave;
1611 ec_soe_request_t *req;
1612
1613 if (!slave->config) {
1615 return;
1616 }
1617
1618 list_for_each_entry(req, &slave->config->soe_configs, list) {
1619 if (req->al_state == EC_AL_STATE_SAFEOP) {
1620 // start SoE configuration
1622 fsm->soe_request = req;
1626 &fsm->soe_request_copy);
1627 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1628 return;
1629 }
1630 }
1631
1632 // No SoE configuration to be applied in SAFEOP
1634}
1635
1636/*****************************************************************************/
1637
1642 )
1643{
1644 ec_slave_t *slave = fsm->slave;
1645
1646 if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1647 return;
1648 }
1649
1650 if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1651 EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1652 fsm->slave->error_flag = 1;
1654 return;
1655 }
1656
1657 if (!fsm->slave->config) { // config removed in the meantime
1659 return;
1660 }
1661
1662 // Another IDN to configure in SAFEOP?
1663 while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1664 fsm->soe_request = list_entry(fsm->soe_request->list.next,
1665 ec_soe_request_t, list);
1670 &fsm->soe_request_copy);
1671 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1672 return;
1673 }
1674 }
1675
1676 // All SAFEOP IDNs are now configured.
1678}
1679
1680/*****************************************************************************/
1681
1686 )
1687{
1688 // set state to OP
1691 ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1692}
1693
1694/*****************************************************************************/
1695
1700 )
1701{
1702 ec_slave_t *slave = fsm->slave;
1703
1704 if (ec_fsm_change_exec(fsm->fsm_change)) return;
1705
1706 if (!ec_fsm_change_success(fsm->fsm_change)) {
1707 if (!fsm->fsm_change->spontaneous_change)
1708 slave->error_flag = 1;
1710 return;
1711 }
1712
1713 // slave is now in OP
1714
1715 EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1716
1717 fsm->state = ec_fsm_slave_config_state_end; // successful
1718}
1719
1720/*****************************************************************************/
1721
1726 )
1727{
1728 EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1729 "configuration. Reconfiguring.");
1730
1731 ec_fsm_slave_config_enter_init(fsm); // reconfigure
1732}
1733
1734/******************************************************************************
1735 * Common state functions
1736 *****************************************************************************/
1737
1742 )
1743{
1744}
1745
1746/*****************************************************************************/
1747
1752 )
1753{
1754}
1755
1756/*****************************************************************************/
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
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
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
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition: datagram.h:78
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition: datagram.h:79
@ EC_DATAGRAM_SENT
Sent (still in the queue).
Definition: datagram.h:77
@ EC_DATAGRAM_QUEUED
Queued for sending.
Definition: datagram.h:76
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
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:139
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
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:124
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_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
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_pdo_start_configuration(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start writing the PDO configuration.
Definition: fsm_pdo.c:132
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
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:180
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.
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *)
Slave configuration state: START.
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *)
Configure PDO sync managers.
void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm, ec_slave_t *slave)
Start slave configuration state machine.
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *)
Slave configuration state: INIT.
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR FMMU.
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *)
Check for PDO sync managers to be configured.
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *)
Slave configuration state: DC ASSIGN.
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *)
Request SAFEOP state.
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SAFEOP.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *)
Reconfigure the slave starting at INIT.
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *)
Request PREOP state.
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG_DIVIDER.
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *)
Clear the DC assignment.
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *)
Check for SDO configurations to be applied.
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *)
Check for FMMUs to be configured.
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *)
State: ERROR.
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG.
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: SDO_CONF.
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *)
Slave configuration state: SYNC.
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *)
Slave configuration state: DC CYCLE.
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *)
Assign SII to PDI.
#define EC_DC_SYNC_WAIT_MS
Maximum time (in ms) to wait for clock discipline.
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *)
Check for DC to be configured.
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *)
Bring slave to OP.
void ec_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied.
void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *fsm)
Destructor.
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_end(ec_fsm_slave_config_t *)
State: END.
int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm)
Executes the current state of the state machine.
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR SYNC.
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *)
Slave configuration state: DC SYNC CHECK.
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *)
Slave configuration state: DC START.
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *)
Check for mailbox sync managers to be configured.
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_PDI.
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *)
WATCHDOG_DIVIDER entry function.
void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_ETHERCAT.
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied in SAFEOP.
#define EC_DC_START_OFFSET
Time offset (in ns), that is added to cyclic start time.
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: PDO_CONF.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *)
Start state change to INIT.
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *)
Slave configuration state: BOOT/PREOP.
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *)
WATCHDOG entry function.
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *)
Slave configuration state: OP.
EtherCAT slave configuration state machine.
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_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
Global definitions and macros.
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:89
@ EC_SLAVE_STATE_BOOT
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:122
@ EC_SLAVE_STATE_PREOP
PREOP state (mailbox communication, no IO)
Definition: globals.h:120
@ EC_SLAVE_STATE_OP
OP (mailbox communication and input/output update)
Definition: globals.h:126
@ EC_SLAVE_STATE_SAFEOP
SAFEOP (mailbox communication and input update)
Definition: globals.h:124
@ EC_SLAVE_STATE_INIT
INIT state (no mailbox communication, no IO)
Definition: globals.h:118
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:95
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2266
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2300
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2317
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2194
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2283
void ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:235
@ EC_AL_STATE_PREOP
Pre-operational.
Definition: ecrt.h:543
@ EC_AL_STATE_SAFEOP
Safe-operational.
Definition: ecrt.h:544
@ EC_DIR_INVALID
Invalid direction.
Definition: ecrt.h:431
Mailbox functionality.
EtherCAT master structure.
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_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition: sdo_request.c:56
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_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition: sdo_request.c:76
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
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:106
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
Definition: slave_config.c:580
EtherCAT slave configuration structure.
void ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
Definition: soe_request.c:245
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
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition: soe_request.c:56
void ec_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition: soe_request.c:77
EtherCAT datagram.
Definition: datagram.h:87
uint16_t working_counter
Working counter.
Definition: datagram.h:99
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
ec_datagram_state_t state
State.
Definition: datagram.h:100
uint8_t * data
Datagram payload.
Definition: datagram.h:94
Slave configutation feature flag.
Definition: flag.h:38
int32_t value
Flag value (meaning depends on key).
Definition: flag.h:41
FMMU configuration.
Definition: fmmu_config.h:46
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
EtherCAT state change FSM.
Definition: fsm_change.h:65
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
Finite state machines for the CANopen over EtherCAT protocol.
Definition: fsm_coe.h:52
PDO configuration state machine.
Definition: fsm_pdo.h:55
Finite state machine to configure an EtherCAT slave.
ec_fsm_change_t * fsm_change
State change state machine.
ec_sdo_request_t * request
SDO request for SDO configuration.
void(* state)(ec_fsm_slave_config_t *)
State function.
ec_fsm_soe_t * fsm_soe
SoE state machine.
ec_sdo_request_t request_copy
Copied SDO request.
ec_datagram_t * datagram
Datagram used in the state machine.
ec_fsm_coe_t * fsm_coe
CoE state machine.
unsigned int retries
Retries on datagram timeout.
ec_soe_request_t * soe_request
SDO request for SDO configuration.
unsigned int take_time
Store jiffies after datagram reception.
ec_slave_t * slave
Slave the FSM runs on.
unsigned long jiffies_start
For timeout calculations.
ec_soe_request_t soe_request_copy
Copied SDO request.
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
Finite state machines for the Sercos over EtherCAT protocol.
Definition: fsm_soe.h:51
EtherCAT master.
Definition: master.h:194
u64 app_time
Time of the last ecrt_master_sync() call.
Definition: master.h:238
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:239
CANopen SDO request.
Definition: sdo_request.h:48
struct list_head list
List item.
Definition: sdo_request.h:49
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:143
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
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:142
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:147
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:141
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:145
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:140
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:144
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:139
unsigned int sync_count
Number of sync managers.
Definition: slave.h:166
EtherCAT slave configuration.
Definition: slave_config.h:119
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:137
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:141
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:131
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:139
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:142
struct list_head soe_configs
List of SoE configurations.
Definition: slave_config.h:148
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:144
uint16_t watchdog_divider
Watchdog divider as a number of 40ns intervals (see spec.
Definition: slave_config.h:129
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:140
EtherCAT slave.
Definition: slave.h:177
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:197
ec_sii_t sii
Extracted SII data.
Definition: slave.h:223
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:210
ec_slave_config_t * config
Current configuration.
Definition: slave.h:190
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:199
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:207
ec_slave_state_t current_state
Current application state.
Definition: slave.h:192
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:212
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:201
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:195
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:208
ec_master_t * master
Master owning the slave.
Definition: slave.h:178
uint16_t station_address
Configured station address.
Definition: slave.h:184
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:193
unsigned long jiffies_preop
Time, the slave went to PREOP.
Definition: slave.h:227
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:191
Sercos-over-EtherCAT request.
Definition: soe_request.h:48
struct list_head list
List item.
Definition: soe_request.h:49
ec_al_state_t al_state
AL state (only valid for IDN config).
Definition: soe_request.h:52
Sync manager configuration.
Definition: sync_config.h:46
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:49
EtherCAT slave sync signal configuration.
Definition: globals.h:171
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:172
int32_t shift_time
Shift time [ns].
Definition: globals.h:173
Sync manager.
Definition: sync.h:47
uint16_t physical_start_address
Physical start address.
Definition: sync.h:49
uint8_t enable
Enable bit.
Definition: sync.h:52
uint16_t default_length
Data length in bytes.
Definition: sync.h:50
uint8_t control_register
Control register value.
Definition: sync.h:51
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
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c:46