IgH EtherCAT Master  1.6.9
fsm_slave_config.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 2006-2024 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
25
26/****************************************************************************/
27
28#include <asm/div64.h>
29
30#include "globals.h"
31#include "master.h"
32#include "mailbox.h"
33#include "slave_config.h"
34#include "fsm_slave_config.h"
35
36/****************************************************************************/
37
43#define EC_DC_MAX_SYNC_DIFF_NS 10000
44
47#define EC_DC_SYNC_WAIT_MS 5000
48
51#define EC_DC_START_OFFSET 100000000ULL
52
53/****************************************************************************/
54
55// prototypes for private methods
57
58/****************************************************************************/
59
66#ifdef EC_SII_ASSIGN
68#endif
70#ifdef EC_SII_ASSIGN
72#endif
89
94#ifdef EC_SII_ASSIGN
96#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 ec_fsm_eoe_t *fsm_eoe
129 )
130{
133
134 fsm->datagram = datagram;
135 fsm->fsm_change = fsm_change;
136 fsm->fsm_coe = fsm_coe;
137 fsm->fsm_soe = fsm_soe;
138 fsm->fsm_pdo = fsm_pdo;
139 fsm->fsm_eoe = fsm_eoe;
140
141 fsm->wait_ms = 0;
142}
143
144/****************************************************************************/
145
155
156/****************************************************************************/
157
162 ec_slave_t *slave
163 )
164{
165 fsm->slave = slave;
167}
168
169/****************************************************************************/
170
181
182/****************************************************************************/
183
193 )
194{
195 if (fsm->datagram->state == EC_DATAGRAM_SENT
196 || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
197 // datagram was not sent or received yet.
198 return ec_fsm_slave_config_running(fsm);
199 }
200
201 fsm->state(fsm);
202 return ec_fsm_slave_config_running(fsm);
203}
204
205/****************************************************************************/
206
211 const ec_fsm_slave_config_t *fsm
212 )
213{
215}
216
217/*****************************************************************************
218 * Slave configuration state machine
219 ****************************************************************************/
220
225 )
226{
227 EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
229}
230
231/****************************************************************************/
232
243
244/****************************************************************************/
245
250 )
251{
252 ec_slave_t *slave = fsm->slave;
253 ec_datagram_t *datagram = fsm->datagram;
254
255 if (ec_fsm_change_exec(fsm->fsm_change)) return;
256
259 slave->error_flag = 1;
261 return;
262 }
263
264 EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
265
266 if (!slave->base_fmmu_count) { // skip FMMU configuration
268 return;
269 }
270
271 EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
272
273 // clear FMMU configurations
274 ec_datagram_fpwr(datagram, slave->station_address,
275 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
276 ec_datagram_zero(datagram);
277 fsm->retries = EC_FSM_RETRIES;
279}
280
281/****************************************************************************/
282
287 )
288{
289 ec_datagram_t *datagram = fsm->datagram;
290
291 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
292 return;
293
294 if (datagram->state != EC_DATAGRAM_RECEIVED) {
296 EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
297 return;
298 }
299
300 if (datagram->working_counter != 1) {
301 fsm->slave->error_flag = 1;
303 EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
305 return;
306 }
307
309}
310
311/****************************************************************************/
312
317 )
318{
319 ec_slave_t *slave = fsm->slave;
320 ec_datagram_t *datagram = fsm->datagram;
321 size_t sync_size;
322
323 if (!slave->base_sync_count) {
324 // no sync managers
326 return;
327 }
328
329 EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
330
331 sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
332
333 // clear sync manager configurations
334 ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
335 ec_datagram_zero(datagram);
336 fsm->retries = EC_FSM_RETRIES;
338}
339
340/****************************************************************************/
341
346 )
347{
348 ec_datagram_t *datagram = fsm->datagram;
349
350 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
351 return;
352
353 if (datagram->state != EC_DATAGRAM_RECEIVED) {
355 EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
356 " clearing datagram.\n");
357 return;
358 }
359
360 if (datagram->working_counter != 1) {
361 fsm->slave->error_flag = 1;
363 EC_SLAVE_ERR(fsm->slave,
364 "Failed to clear sync manager configurations: ");
366 return;
367 }
368
370}
371
372/****************************************************************************/
373
378 )
379{
380 ec_slave_t *slave = fsm->slave;
381 ec_datagram_t *datagram = fsm->datagram;
382
383 if (!slave->base_dc_supported || !slave->has_dc_system_time) {
385 return;
386 }
387
388 EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
389
390 ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
391 ec_datagram_zero(datagram);
392 fsm->retries = EC_FSM_RETRIES;
394}
395
396/****************************************************************************/
397
402 )
403{
404 ec_datagram_t *datagram = fsm->datagram;
405
406 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
407 return;
408
409 if (datagram->state != EC_DATAGRAM_RECEIVED) {
411 EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
412 " clearing datagram.\n");
413 return;
414 }
415
416 if (datagram->working_counter != 1) {
417 // clearing the DC assignment does not succeed on simple slaves
418 EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
420 }
421
423}
424
425/****************************************************************************/
426
431 )
432{
433 ec_slave_t *slave = fsm->slave;
434 ec_datagram_t *datagram = fsm->datagram;
435 unsigned int i;
436
437 // slave is now in INIT
438 if (slave->current_state == slave->requested_state) {
439 fsm->state = ec_fsm_slave_config_state_end; // successful
440 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
441 return;
442 }
443
444 if (!slave->sii.mailbox_protocols) {
445 // no mailbox protocols supported
446 EC_SLAVE_DBG(slave, 1, "Slave does not support"
447 " mailbox communication.\n");
448#ifdef EC_SII_ASSIGN
450#else
452#endif
453 return;
454 }
455
456 EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
457
458 if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
459 ec_sync_t sync;
460
461 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
463 ec_datagram_zero(datagram);
464
465 ec_sync_init(&sync, slave);
467 sync.control_register = 0x26;
468 sync.enable = 1;
469 ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
470 EC_DIR_INVALID, // use default direction
471 0, // no PDO xfer
472 datagram->data);
477
478 ec_sync_init(&sync, slave);
480 sync.control_register = 0x22;
481 sync.enable = 1;
482 ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
483 EC_DIR_INVALID, // use default direction
484 0, // no PDO xfer
485 datagram->data + EC_SYNC_PAGE_SIZE);
490
491 } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
492 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
494 ec_datagram_zero(datagram);
495
496 for (i = 0; i < 2; i++) {
497 ec_sync_page(&slave->sii.syncs[i], i,
498 slave->sii.syncs[i].default_length,
499 NULL, // use default sync manager configuration
500 0, // no PDO xfer
501 datagram->data + EC_SYNC_PAGE_SIZE * i);
502 }
503
507 slave->sii.syncs[0].default_length;
511 slave->sii.syncs[1].default_length;
512 } else { // no mailbox sync manager configurations provided
513 ec_sync_t sync;
514
515 EC_SLAVE_DBG(slave, 1, "Slave does not provide"
516 " mailbox sync manager configurations.\n");
517
518 ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
520 ec_datagram_zero(datagram);
521
522 ec_sync_init(&sync, slave);
524 sync.control_register = 0x26;
525 sync.enable = 1;
526 ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
527 NULL, // use default sync manager configuration
528 0, // no PDO xfer
529 datagram->data);
534
535 ec_sync_init(&sync, slave);
537 sync.control_register = 0x22;
538 sync.enable = 1;
539 ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
540 NULL, // use default sync manager configuration
541 0, // no PDO xfer
542 datagram->data + EC_SYNC_PAGE_SIZE);
547 }
548
549 fsm->take_time = 1;
550
551 fsm->retries = EC_FSM_RETRIES;
553}
554
555/****************************************************************************/
556
563 )
564{
565 ec_datagram_t *datagram = fsm->datagram;
566 ec_slave_t *slave = fsm->slave;
567
568 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
569 return;
570
571 if (datagram->state != EC_DATAGRAM_RECEIVED) {
573 EC_SLAVE_ERR(slave, "Failed to receive sync manager"
574 " configuration datagram: ");
575 ec_datagram_print_state(datagram);
576 return;
577 }
578
579 if (fsm->take_time) {
580 fsm->take_time = 0;
581 fsm->jiffies_start = datagram->jiffies_sent;
582 }
583
584 /* Because the sync manager configurations are cleared during the last
585 * cycle, some slaves do not immediately respond to the mailbox sync
586 * manager configuration datagram. Therefore, resend the datagram for
587 * a certain time, if the slave does not respond.
588 */
589 if (datagram->working_counter == 0) {
590 unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
591
592 if (diff >= HZ) {
593 slave->error_flag = 1;
595 EC_SLAVE_ERR(slave, "Timeout while configuring"
596 " mailbox sync managers.\n");
597 return;
598 } else {
599 EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
600 (unsigned int) diff * 1000 / HZ);
601 }
602
603 // send configuration datagram again
604 fsm->retries = EC_FSM_RETRIES;
605 return;
606 }
607 else if (datagram->working_counter != 1) {
608 slave->error_flag = 1;
610 EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
612 return;
613 }
614
615#ifdef EC_SII_ASSIGN
617#else
619#endif
620}
621
622/****************************************************************************/
623
624#ifdef EC_SII_ASSIGN
625
630 )
631{
632 ec_datagram_t *datagram = fsm->datagram;
633 ec_slave_t *slave = fsm->slave;
634
636 EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
637
638 ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
639 EC_WRITE_U8(datagram->data, 0x01); // PDI
640 fsm->retries = EC_FSM_RETRIES;
642 }
643 else {
645 }
646}
647
648/****************************************************************************/
649
654 )
655{
656 ec_datagram_t *datagram = fsm->datagram;
657 ec_slave_t *slave = fsm->slave;
658
659 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
660 return;
661 }
662
663 if (datagram->state != EC_DATAGRAM_RECEIVED) {
664 EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
665 ec_datagram_print_state(datagram);
666 goto cont_preop;
667 }
668
669 if (datagram->working_counter != 1) {
670 EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
672 }
673
674cont_preop:
676}
677
678#endif
679
680/****************************************************************************/
681
686 )
687{
689
693 } else { // BOOT
696 }
697
698 ec_fsm_change_exec(fsm->fsm_change); // execute immediately
699}
700
701/****************************************************************************/
702
707 )
708{
709 ec_slave_t *slave = fsm->slave;
710#ifdef EC_SII_ASSIGN
711 int assign_to_pdi;
712 ec_slave_config_t *config;
713 ec_flag_t *flag;
714#endif
715
716 if (ec_fsm_change_exec(fsm->fsm_change)) {
717 return;
718 }
719
722 slave->error_flag = 1;
724 return;
725 }
726
727 // slave is now in BOOT or PREOP
729
730 EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
731 slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
732
733#ifdef EC_SII_ASSIGN
734 assign_to_pdi = 0;
735 config = fsm->slave->config;
736 if (config) {
737 flag = ec_slave_config_find_flag(config, "AssignToPdi");
738 if (flag) {
739 assign_to_pdi = flag->value;
740 }
741 }
742
743 if (assign_to_pdi) {
744 EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
745 if (slave->current_state == slave->requested_state) {
746 fsm->state = ec_fsm_slave_config_state_end; // successful
747 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
748 return;
749 }
750
752 }
753 else {
754 EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
755
756 ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
757 EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
758 fsm->retries = EC_FSM_RETRIES;
760 }
761#else
762 if (slave->current_state == slave->requested_state) {
763 fsm->state = ec_fsm_slave_config_state_end; // successful
764 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
765 return;
766 }
767
769#endif
770}
771
772/****************************************************************************/
773
774#ifdef EC_SII_ASSIGN
775
780 )
781{
782 ec_datagram_t *datagram = fsm->datagram;
783 ec_slave_t *slave = fsm->slave;
784
785 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
786 return;
787 }
788
789 if (datagram->state != EC_DATAGRAM_RECEIVED) {
790 EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
791 ec_datagram_print_state(datagram);
792 goto cont_sdo_conf;
793 }
794
795 if (datagram->working_counter != 1) {
796 EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
798 }
799
800cont_sdo_conf:
801 if (slave->current_state == slave->requested_state) {
802 fsm->state = ec_fsm_slave_config_state_end; // successful
803 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
804 return;
805 }
806
808}
809
810#endif
811
812/****************************************************************************/
813
818 )
819{
820 ec_slave_t *slave = fsm->slave;
821
822 if (!slave->config) {
824 return;
825 }
826
827 // No CoE configuration to be applied?
828 if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
830 return;
831 }
832
833 // start SDO configuration
835 fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
836 ec_sdo_request_t, list);
840 ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
841}
842
843/****************************************************************************/
844
849 )
850{
851 if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
852 return;
853 }
854
855 if (!ec_fsm_coe_success(fsm->fsm_coe)) {
856 EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
857 fsm->slave->error_flag = 1;
859 return;
860 }
861
862 if (!fsm->slave->config) { // config removed in the meantime
864 return;
865 }
866
867 // Another SDO to configure?
868 if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
869 fsm->request = list_entry(fsm->request->list.next,
870 ec_sdo_request_t, list);
874 ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
875 return;
876 }
877
878 // All SDOs are now configured.
880}
881
882/****************************************************************************/
883
888 )
889{
890 ec_slave_t *slave = fsm->slave;
891 ec_soe_request_t *req;
892
893 if (!slave->config) {
895 return;
896 }
897
898 list_for_each_entry(req, &slave->config->soe_configs, list) {
899 if (req->al_state == EC_AL_STATE_PREOP) {
900 // start SoE configuration
902 fsm->soe_request = req;
906 &fsm->soe_request_copy);
907 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
908 return;
909 }
910 }
911
912 // No SoE configuration to be applied in PREOP
914}
915
916/****************************************************************************/
917
922 )
923{
924 ec_slave_t *slave = fsm->slave;
925
926 if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
927 return;
928 }
929
930 if (!ec_fsm_soe_success(fsm->fsm_soe)) {
931 EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
932 fsm->slave->error_flag = 1;
934 return;
935 }
936
937 if (!fsm->slave->config) { // config removed in the meantime
939 return;
940 }
941
942 // Another IDN to configure in PREOP?
943 while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
944 fsm->soe_request = list_entry(fsm->soe_request->list.next,
945 ec_soe_request_t, list);
950 &fsm->soe_request_copy);
951 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
952 return;
953 }
954 }
955
956 // All PREOP IDNs are now configured.
958}
959
960/****************************************************************************/
961
966 )
967{
968#ifdef EC_EOE
969 ec_slave_t *slave = fsm->slave;
970 ec_eoe_request_t *request = &slave->config->eoe_ip_param_request;
971
972 if (ec_eoe_request_valid(request)) {
973 EC_SLAVE_DBG(slave, 1, "Setting EoE IP parameters...\n");
974
975 // Start EoE command
977 ec_fsm_eoe_set_ip_param(fsm->fsm_eoe, slave, request);
978 ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram); // execute immediately
979 return;
980 }
981#endif
982
984}
985
986/****************************************************************************/
987
992 )
993{
994#ifdef EC_EOE
995 ec_slave_t *slave = fsm->slave;
996
997 if (ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram)) {
998 return;
999 }
1000
1001 if (ec_fsm_eoe_success(fsm->fsm_eoe)) {
1002 EC_SLAVE_DBG(slave, 1, "Finished setting EoE IP parameters.\n");
1003 }
1004 else {
1005 EC_SLAVE_ERR(slave, "Failed to set EoE IP parameters.\n");
1006 }
1007#endif
1009}
1010
1011/****************************************************************************/
1012
1017 )
1018{
1019 // Start configuring PDOs
1022 fsm->state(fsm); // execute immediately
1023}
1024
1025/****************************************************************************/
1026
1031 )
1032{
1033 // TODO check for config here
1034
1035 if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
1036 return;
1037 }
1038
1039 if (!fsm->slave->config) { // config removed in the meantime
1041 return;
1042 }
1043
1044 if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
1045 EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
1046 }
1047
1049}
1050
1051/****************************************************************************/
1052
1057 )
1058{
1059 ec_slave_t *slave = fsm->slave;
1060 ec_datagram_t *datagram = fsm->datagram;
1061 ec_slave_config_t *config = slave->config;
1062
1063 if (config && config->watchdog_divider) {
1064 EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1065 config->watchdog_divider);
1066
1067 ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1068 EC_WRITE_U16(datagram->data, config->watchdog_divider);
1069 fsm->retries = EC_FSM_RETRIES;
1071 } else {
1073 }
1074}
1075
1076/****************************************************************************/
1077
1082 )
1083{
1084 ec_datagram_t *datagram = fsm->datagram;
1085 ec_slave_t *slave = fsm->slave;
1086
1087 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1088 return;
1089
1090 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1092 EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1093 " configuration datagram: ");
1094 ec_datagram_print_state(datagram);
1095 return;
1096 }
1097
1098 if (datagram->working_counter != 1) {
1099 slave->error_flag = 1;
1100 EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1102 return;
1103 }
1104
1106}
1107
1108/****************************************************************************/
1109
1114 )
1115{
1116 ec_datagram_t *datagram = fsm->datagram;
1117 ec_slave_t *slave = fsm->slave;
1118 ec_slave_config_t *config = slave->config;
1119
1120 if (config && config->watchdog_intervals) {
1121 EC_SLAVE_DBG(slave, 1, "Setting process data"
1122 " watchdog intervals to %u.\n", config->watchdog_intervals);
1123
1124 ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1125 EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1126
1127 fsm->retries = EC_FSM_RETRIES;
1129 } else {
1131 }
1132}
1133
1134/****************************************************************************/
1135
1138
1141 )
1142{
1143 ec_datagram_t *datagram = fsm->datagram;
1144 ec_slave_t *slave = fsm->slave;
1145
1146 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1147 return;
1148
1149 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1151 EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1152 " watchdog configuration datagram: ");
1153 ec_datagram_print_state(datagram);
1154 return;
1155 }
1156
1157 if (datagram->working_counter != 1) {
1158 EC_SLAVE_WARN(slave, "Failed to set process data"
1159 " watchdog intervals: ");
1161 }
1162
1164}
1165
1166/****************************************************************************/
1167
1172 )
1173{
1174 ec_slave_t *slave = fsm->slave;
1175 ec_datagram_t *datagram = fsm->datagram;
1176 unsigned int i, j, offset, num_pdo_syncs;
1177 uint8_t sync_index;
1178 const ec_sync_t *sync;
1179 uint16_t size;
1180
1181 if (slave->sii.mailbox_protocols) {
1182 offset = 2; // slave has mailboxes
1183 } else {
1184 offset = 0;
1185 }
1186
1187 if (slave->sii.sync_count <= offset) {
1188 // no PDO sync managers to configure
1190 return;
1191 }
1192
1193 num_pdo_syncs = slave->sii.sync_count - offset;
1194
1195 // configure sync managers for process data
1196 ec_datagram_fpwr(datagram, slave->station_address,
1197 0x0800 + EC_SYNC_PAGE_SIZE * offset,
1198 EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1199 ec_datagram_zero(datagram);
1200
1201 for (i = 0; i < num_pdo_syncs; i++) {
1202 const ec_sync_config_t *sync_config;
1203 uint8_t pdo_xfer = 0;
1204 sync_index = i + offset;
1205 sync = &slave->sii.syncs[sync_index];
1206
1207 if (slave->config) {
1208 const ec_slave_config_t *sc = slave->config;
1209 sync_config = &sc->sync_configs[sync_index];
1210 size = ec_pdo_list_total_size(&sync_config->pdos);
1211
1212 // determine, if PDOs shall be transferred via this SM
1213 // inthat case, enable sync manager in every case
1214 for (j = 0; j < sc->used_fmmus; j++) {
1215 if (sc->fmmu_configs[j].sync_index == sync_index) {
1216 pdo_xfer = 1;
1217 break;
1218 }
1219 }
1220
1221 } else {
1222 sync_config = NULL;
1223 size = sync->default_length;
1224 }
1225
1226 ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1227 datagram->data + EC_SYNC_PAGE_SIZE * i);
1228 }
1229
1230 fsm->retries = EC_FSM_RETRIES;
1232}
1233
1234/****************************************************************************/
1235
1240 )
1241{
1242 ec_datagram_t *datagram = fsm->datagram;
1243 ec_slave_t *slave = fsm->slave;
1244
1245 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1246 return;
1247
1248 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1250 EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1251 " manager configuration datagram: ");
1252 ec_datagram_print_state(datagram);
1253 return;
1254 }
1255
1256 if (datagram->working_counter != 1) {
1257 slave->error_flag = 1;
1259 EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1261 return;
1262 }
1263
1265}
1266
1267/****************************************************************************/
1268
1273 )
1274{
1275 ec_slave_t *slave = fsm->slave;
1276 ec_datagram_t *datagram = fsm->datagram;
1277 unsigned int i;
1278 const ec_fmmu_config_t *fmmu;
1279 const ec_sync_t *sync;
1280
1281 if (!slave->config) {
1283 return;
1284 }
1285
1286 if (slave->base_fmmu_count < slave->config->used_fmmus) {
1287 slave->error_flag = 1;
1289 EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1290 " than requested (%u).\n", slave->base_fmmu_count,
1291 slave->config->used_fmmus);
1292 return;
1293 }
1294
1295 if (!slave->base_fmmu_count) { // skip FMMU configuration
1297 return;
1298 }
1299
1300 // configure FMMUs
1301 ec_datagram_fpwr(datagram, slave->station_address,
1302 0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1303 ec_datagram_zero(datagram);
1304 for (i = 0; i < slave->config->used_fmmus; i++) {
1305 fmmu = &slave->config->fmmu_configs[i];
1306 if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1307 slave->error_flag = 1;
1309 EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1310 " for FMMU!\n");
1311 return;
1312 }
1313 ec_fmmu_config_page(fmmu, sync,
1314 datagram->data + EC_FMMU_PAGE_SIZE * i);
1315 }
1316
1317 fsm->retries = EC_FSM_RETRIES;
1319}
1320
1321/****************************************************************************/
1322
1327 )
1328{
1329 ec_datagram_t *datagram = fsm->datagram;
1330 ec_slave_t *slave = fsm->slave;
1331
1332 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1333 return;
1334
1335 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1337 EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1338 ec_datagram_print_state(datagram);
1339 return;
1340 }
1341
1342 if (datagram->working_counter != 1) {
1343 slave->error_flag = 1;
1345 EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1347 return;
1348 }
1349
1351}
1352
1353/****************************************************************************/
1354
1359 )
1360{
1361 ec_datagram_t *datagram = fsm->datagram;
1362 ec_slave_t *slave = fsm->slave;
1363 ec_slave_config_t *config = slave->config;
1364
1365 if (!config) { // config removed in the meantime
1367 return;
1368 }
1369
1370 if (config->dc_assign_activate) {
1371 if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1372 EC_SLAVE_WARN(slave, "Slave seems not to support"
1373 " distributed clocks!\n");
1374 }
1375
1376 EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1377 config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1378
1379 // set DC cycle times
1380 ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1381 EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1382 EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1383 fsm->retries = EC_FSM_RETRIES;
1385 } else {
1386 // DC are unused
1388 }
1389}
1390
1391/****************************************************************************/
1392
1397 )
1398{
1399 ec_datagram_t *datagram = fsm->datagram;
1400 ec_slave_t *slave = fsm->slave;
1401 ec_slave_config_t *config = slave->config;
1402
1403 if (!config) { // config removed in the meantime
1405 return;
1406 }
1407
1408 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1409 return;
1410
1411 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1413 EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1414 ec_datagram_print_state(datagram);
1415 return;
1416 }
1417
1418 if (datagram->working_counter != 1) {
1419 slave->error_flag = 1;
1421 EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1423 return;
1424 }
1425
1426 EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1427
1428 fsm->jiffies_start = jiffies;
1429 ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1430 fsm->retries = EC_FSM_RETRIES;
1432}
1433
1434/****************************************************************************/
1435
1440 )
1441{
1442 ec_datagram_t *datagram = fsm->datagram;
1443 ec_slave_t *slave = fsm->slave;
1444 ec_master_t *master = slave->master;
1445 ec_slave_config_t *config = slave->config;
1446 uint32_t abs_sync_diff;
1447 unsigned long diff_ms;
1448 ec_sync_signal_t *sync0 = &config->dc_sync[0];
1449 ec_sync_signal_t *sync1 = &config->dc_sync[1];
1450 u64 start_time;
1451
1452 if (!config) { // config removed in the meantime
1454 return;
1455 }
1456
1457 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1458 return;
1459
1460 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1462 EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1463 ec_datagram_print_state(datagram);
1464 return;
1465 }
1466
1467 if (datagram->working_counter != 1) {
1468 slave->error_flag = 1;
1470 EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1472 return;
1473 }
1474
1475 abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1476 diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1477
1478 if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1479
1480 if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1481 EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1482 diff_ms);
1483 } else {
1484 EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1485 diff_ms, abs_sync_diff);
1486
1487 // check synchrony again
1488 ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1489 fsm->retries = EC_FSM_RETRIES;
1490 return;
1491 }
1492 } else {
1493 EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1494 abs_sync_diff, diff_ms);
1495 }
1496
1497 // set DC start time (roughly in the future, not in-phase)
1498 start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1499
1500 if (sync0->cycle_time) {
1501 // find correct phase
1502 if (master->dc_ref_time) {
1503 u64 diff, start;
1504 u32 remainder, cycle;
1505
1506 diff = start_time - master->dc_ref_time;
1507 cycle = sync0->cycle_time + sync1->cycle_time;
1508 remainder = do_div(diff, cycle);
1509
1510 start = start_time + cycle - remainder + sync0->shift_time;
1511
1512 EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1513 EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1514 EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1515 EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1516 EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1517 EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1518 EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1519 start_time = start;
1520 } else {
1521 EC_SLAVE_WARN(slave, "No application time supplied."
1522 " Cyclic start time will not be in phase.\n");
1523 }
1524 }
1525
1526 EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1527 " start time to %llu.\n", start_time);
1528
1529 ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1530 EC_WRITE_U64(datagram->data, start_time);
1531 fsm->retries = EC_FSM_RETRIES;
1533}
1534
1535/****************************************************************************/
1536
1541 )
1542{
1543 ec_datagram_t *datagram = fsm->datagram;
1544 ec_slave_t *slave = fsm->slave;
1545 ec_slave_config_t *config = slave->config;
1546
1547 if (!config) { // config removed in the meantime
1549 return;
1550 }
1551
1552 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1553 return;
1554
1555 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1557 EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1558 ec_datagram_print_state(datagram);
1559 return;
1560 }
1561
1562 if (datagram->working_counter != 1) {
1563 slave->error_flag = 1;
1565 EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1567 return;
1568 }
1569
1570 EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1571 config->dc_assign_activate);
1572
1573 // assign sync unit to EtherCAT or PDI
1574 ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1575 EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1576 fsm->retries = EC_FSM_RETRIES;
1578}
1579
1580/****************************************************************************/
1581
1586 )
1587{
1588 ec_datagram_t *datagram = fsm->datagram;
1589 ec_slave_t *slave = fsm->slave;
1590
1591 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1592 return;
1593
1594 if (datagram->state != EC_DATAGRAM_RECEIVED) {
1596 EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1597 ec_datagram_print_state(datagram);
1598 return;
1599 }
1600
1601 if (datagram->working_counter != 1) {
1602 slave->error_flag = 1;
1604 EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1606 return;
1607 }
1608
1610}
1611
1612/****************************************************************************/
1613
1622 )
1623{
1624 ec_slave_config_t *config = fsm->slave->config;
1625 fsm->wait_ms = 0UL;
1626 if (config) {
1627 ec_flag_t *flag = ec_slave_config_find_flag(config,
1628 "WaitBeforeSAFEOPms");
1629 if (flag && flag->value > 0) {
1630 fsm->wait_ms = (unsigned long) flag->value;
1631 }
1632 }
1633
1634 if (fsm->wait_ms > 0) {
1636
1637 /* dummy read */
1639 0x0600, 1);
1640
1641 fsm->jiffies_start = jiffies;
1642 }
1643 else {
1645 }
1646}
1647
1648/****************************************************************************/
1649
1654 )
1655{
1656 unsigned long diff = jiffies - fsm->jiffies_start;
1657
1658 if (diff * 1000 / HZ < fsm->wait_ms) {
1659 return;
1660 }
1661
1663}
1664
1665/****************************************************************************/
1666
1677
1678/****************************************************************************/
1679
1684 )
1685{
1686 ec_slave_t *slave = fsm->slave;
1687
1688 if (ec_fsm_change_exec(fsm->fsm_change)) return;
1689
1690 if (!ec_fsm_change_success(fsm->fsm_change)) {
1691 if (!fsm->fsm_change->spontaneous_change)
1692 fsm->slave->error_flag = 1;
1694 return;
1695 }
1696
1697 // slave is now in SAFEOP
1698
1699 EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1700
1701 if (fsm->slave->current_state == fsm->slave->requested_state) {
1702 fsm->state = ec_fsm_slave_config_state_end; // successful
1703 EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1704 return;
1705 }
1706
1708}
1709
1710/****************************************************************************/
1711
1716 )
1717{
1718 ec_slave_t *slave = fsm->slave;
1719 ec_soe_request_t *req;
1720
1721 if (!slave->config) {
1723 return;
1724 }
1725
1726 list_for_each_entry(req, &slave->config->soe_configs, list) {
1727 if (req->al_state == EC_AL_STATE_SAFEOP) {
1728 // start SoE configuration
1730 fsm->soe_request = req;
1734 &fsm->soe_request_copy);
1735 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1736 return;
1737 }
1738 }
1739
1740 // No SoE configuration to be applied in SAFEOP
1742}
1743
1744/****************************************************************************/
1745
1750 )
1751{
1752 ec_slave_t *slave = fsm->slave;
1753
1754 if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1755 return;
1756 }
1757
1758 if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1759 EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1760 fsm->slave->error_flag = 1;
1762 return;
1763 }
1764
1765 if (!fsm->slave->config) { // config removed in the meantime
1767 return;
1768 }
1769
1770 // Another IDN to configure in SAFEOP?
1771 while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1772 fsm->soe_request = list_entry(fsm->soe_request->list.next,
1773 ec_soe_request_t, list);
1778 &fsm->soe_request_copy);
1779 ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1780 return;
1781 }
1782 }
1783
1784 // All SAFEOP IDNs are now configured.
1786}
1787
1788/****************************************************************************/
1789
1794 )
1795{
1796 // set state to OP
1799 ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1800}
1801
1802/****************************************************************************/
1803
1808 )
1809{
1810 ec_slave_t *slave = fsm->slave;
1811
1812 if (ec_fsm_change_exec(fsm->fsm_change)) return;
1813
1814 if (!ec_fsm_change_success(fsm->fsm_change)) {
1815 if (!fsm->fsm_change->spontaneous_change)
1816 slave->error_flag = 1;
1818 return;
1819 }
1820
1821 // slave is now in OP
1822
1823 EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1824
1825 fsm->state = ec_fsm_slave_config_state_end; // successful
1826}
1827
1828/****************************************************************************/
1829
1834 )
1835{
1836 EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1837 "configuration. Reconfiguring.");
1838
1839 ec_fsm_slave_config_enter_init(fsm); // reconfigure
1840}
1841
1842/*****************************************************************************
1843 * Common state functions
1844 ****************************************************************************/
1845
1853
1854/****************************************************************************/
1855
1860 )
1861{
1862}
1863
1864/****************************************************************************/
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition datagram.c:594
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition datagram.c:170
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition datagram.c:557
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition datagram.c:290
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition datagram.c:265
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
@ EC_DATAGRAM_SENT
Sent (still in the queue).
Definition datagram.h:69
@ EC_DATAGRAM_QUEUED
Queued for sending.
Definition datagram.h:68
int ec_eoe_request_valid(const ec_eoe_request_t *req)
Checks if EoE request has something to set.
Definition eoe_request.c:67
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:68
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_change.c: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:123
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition fsm_change.c:157
struct ec_fsm_change ec_fsm_change_t
Definition fsm_change.h:50
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_coe.c:267
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:210
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:233
struct ec_fsm_coe ec_fsm_coe_t
Definition fsm_coe.h:40
int ec_fsm_eoe_exec(ec_fsm_eoe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition fsm_eoe.c:121
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_eoe.c:156
void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *fsm, ec_slave_t *slave, ec_eoe_request_t *request)
Starts to set the EoE IP partameters of a slave.
Definition fsm_eoe.c:104
struct ec_fsm_eoe ec_fsm_eoe_t
Definition fsm_eoe.h:39
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
struct ec_fsm_pdo ec_fsm_pdo_t
Definition fsm_pdo.h:42
void ec_fsm_slave_config_state_wait_safeop(ec_fsm_slave_config_t *)
Slave configuration state: WAIT SAFEOP.
void ec_fsm_slave_config_enter_eoe_ip_param(ec_fsm_slave_config_t *)
EOE_IP_PARAM entry function.
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_state_eoe_ip_param(ec_fsm_slave_config_t *)
Slave configuration state: EOE_IP_PARAM.
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.
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, ec_fsm_eoe_t *fsm_eoe)
Constructor.
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_enter_wait_safeop(ec_fsm_slave_config_t *)
Wait before SAFEOP transition.
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.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *)
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.
struct ec_fsm_slave_config ec_fsm_slave_config_t
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:152
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:130
int ec_fsm_soe_success(const ec_fsm_soe_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_soe.c:187
struct ec_fsm_soe ec_fsm_soe_t
Definition fsm_soe.h:39
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:128
@ EC_SLAVE_STATE_PREOP
PREOP state (mailbox communication, no IO)
Definition globals.h:126
@ EC_SLAVE_STATE_OP
OP (mailbox communication and input/output update)
Definition globals.h:132
@ EC_SLAVE_STATE_SAFEOP
SAFEOP (mailbox communication and input update)
Definition globals.h:130
@ EC_SLAVE_STATE_INIT
INIT state (no mailbox communication, no IO)
Definition globals.h:124
#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
struct ec_slave ec_slave_t
Definition globals.h:310
struct ec_soe_request ec_soe_request_t
Definition ecrt.h:312
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition ecrt.h:3040
struct ec_sdo_request ec_sdo_request_t
Definition ecrt.h:309
struct ec_master ec_master_t
Definition ecrt.h:300
struct ec_slave_config ec_slave_config_t
Definition ecrt.h:303
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition ecrt.h:3074
int ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition ecrt.h:3091
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition ecrt.h:2964
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition ecrt.h:3057
@ EC_AL_STATE_PREOP
Pre-operational.
Definition ecrt.h:617
@ EC_AL_STATE_SAFEOP
Safe-operational.
Definition ecrt.h:618
@ EC_DIR_INVALID
Invalid direction.
Definition ecrt.h:505
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:79
void ec_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition sdo_request.c:48
int ec_sdo_request_copy(ec_sdo_request_t *req, const ec_sdo_request_t *other)
Copy another SDO request.
Definition sdo_request.c:85
void ec_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition sdo_request.c:70
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:600
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition slave.h:98
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition slave.h:68
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition slave.h:82
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
EtherCAT slave configuration structure.
int ec_soe_request_copy(ec_soe_request_t *req, const ec_soe_request_t *other)
Copy another SoE request.
Definition soe_request.c:84
int ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition soe_request.c:48
void ec_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition soe_request.c:71
EtherCAT datagram.
Definition datagram.h:79
uint16_t working_counter
Working counter.
Definition datagram.h:93
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition datagram.h:102
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition datagram.h:98
ec_datagram_state_t state
State.
Definition datagram.h:94
uint8_t * data
Datagram payload.
Definition datagram.h:88
Ethernet-over-EtherCAT set IP parameter request.
Definition eoe_request.h:41
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:38
uint8_t sync_index
Index of sync manager to use.
Definition fmmu_config.h:42
uint8_t spontaneous_change
spontaneous state change detected
Definition fsm_change.h:68
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_eoe_t * fsm_eoe
EoE state machine.
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 wait_ms
Wait time (used to wait before SAFEOP).
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.
u64 app_time
Time of the last ecrt_master_sync() call.
Definition master.h:227
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition master.h:228
struct list_head list
List item.
Definition sdo_request.h:41
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition slave.h:135
ec_sync_t * syncs
SYNC MANAGER categories.
Definition slave.h:157
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition slave.h:138
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition slave.h:134
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition slave.h:139
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition slave.h:133
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition slave.h:137
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition slave.h:132
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition slave.h:136
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition slave.h:131
unsigned int sync_count
Number of sync managers.
Definition slave.h:158
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
struct list_head soe_configs
List of SoE configurations.
struct list_head sdo_configs
List of SDO configurations.
uint16_t watchdog_divider
Watchdog divider as a number of 40ns intervals (see spec.
uint8_t used_fmmus
Number of FMMUs used.
ec_eoe_request_t eoe_ip_param_request
EoE IP parameters.
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition slave.h:189
ec_sii_t sii
Extracted SII data.
Definition slave.h:215
uint8_t base_dc_supported
Distributed clocks are supported.
Definition slave.h:202
ec_slave_config_t * config
Current configuration.
Definition slave.h:182
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition slave.h:191
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition slave.h:199
ec_slave_state_t current_state
Current application state.
Definition slave.h:184
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition slave.h:204
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition slave.h:193
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition slave.h:187
uint8_t base_sync_count
Number of supported sync managers.
Definition slave.h:200
ec_master_t * master
Master owning the slave.
Definition slave.h:170
uint16_t station_address
Configured station address.
Definition slave.h:176
unsigned int error_flag
Stop processing after an error.
Definition slave.h:185
unsigned long jiffies_preop
Time, the slave went to PREOP.
Definition slave.h:219
ec_slave_state_t requested_state
Requested application state.
Definition slave.h:183
ec_al_state_t al_state
AL state (only valid for IDN config).
Definition soe_request.h:44
struct list_head list
List item.
Definition soe_request.h:41
Sync manager configuration.
Definition sync_config.h:38
ec_pdo_list_t pdos
Current PDO assignment.
Definition sync_config.h:41
EtherCAT slave sync signal configuration.
Definition globals.h:180
uint32_t cycle_time
Cycle time [ns].
Definition globals.h:181
int32_t shift_time
Shift time [ns].
Definition globals.h:182
Sync manager.
Definition sync.h:39
uint16_t physical_start_address
Physical start address.
Definition sync.h:41
uint8_t enable
Enable bit.
Definition sync.h:44
uint16_t default_length
Data length in bytes.
Definition sync.h:42
uint8_t control_register
Control register value.
Definition sync.h:43
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:86
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition sync.c:38