IgH EtherCAT Master  1.7.0
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 
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 
122  ec_fsm_slave_config_t *fsm,
123  ec_datagram_t *datagram,
124  ec_fsm_change_t *fsm_change,
125  ec_fsm_coe_t *fsm_coe,
126  ec_fsm_soe_t *fsm_soe,
127  ec_fsm_pdo_t *fsm_pdo,
128  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 
150  )
151 {
154 }
155 
156 /****************************************************************************/
157 
161  ec_fsm_slave_config_t *fsm,
162  ec_slave_t *slave
163  )
164 {
165  fsm->slave = slave;
167 }
168 
169 /****************************************************************************/
170 
175  const ec_fsm_slave_config_t *fsm
176  )
177 {
178  return fsm->state != ec_fsm_slave_config_state_end
180 }
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 {
214  return fsm->state == ec_fsm_slave_config_state_end;
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 
237  )
238 {
242 }
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 
257  if (!ec_fsm_change_success(fsm->fsm_change)) {
258  if (!fsm->fsm_change->spontaneous_change)
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: ");
304  ec_datagram_print_wc_error(datagram);
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: ");
365  ec_datagram_print_wc_error(datagram);
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: ");
419  ec_datagram_print_wc_error(datagram);
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,
462  EC_SYNC_PAGE_SIZE * 2);
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);
476  slave->sii.boot_rx_mailbox_size;
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);
489  slave->sii.boot_tx_mailbox_size;
490 
491  } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
492  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
493  EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
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 
505  slave->sii.syncs[0].physical_start_address;
507  slave->sii.syncs[0].default_length;
509  slave->sii.syncs[1].physical_start_address;
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,
519  EC_SYNC_PAGE_SIZE * 2);
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);
531  slave->sii.std_rx_mailbox_offset;
533  slave->sii.std_rx_mailbox_size;
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);
544  slave->sii.std_tx_mailbox_offset;
546  slave->sii.std_tx_mailbox_size;
547  }
548 
549  // allocate memory for mailbox response data
550  ec_slave_mbox_prealloc(slave);
551 
552  fsm->take_time = 1;
553 
554  fsm->retries = EC_FSM_RETRIES;
556 }
557 
558 /****************************************************************************/
559 
566  )
567 {
568  ec_datagram_t *datagram = fsm->datagram;
569  ec_slave_t *slave = fsm->slave;
570 
571  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
572  return;
573 
574  if (datagram->state != EC_DATAGRAM_RECEIVED) {
576  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
577  " configuration datagram: ");
578  ec_datagram_print_state(datagram);
579  return;
580  }
581 
582  if (fsm->take_time) {
583  fsm->take_time = 0;
584  fsm->jiffies_start = datagram->jiffies_sent;
585  }
586 
587  /* Because the sync manager configurations are cleared during the last
588  * cycle, some slaves do not immediately respond to the mailbox sync
589  * manager configuration datagram. Therefore, resend the datagram for
590  * a certain time, if the slave does not respond.
591  */
592  if (datagram->working_counter == 0) {
593  unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
594 
595  if (diff >= HZ) {
596  slave->error_flag = 1;
598  EC_SLAVE_ERR(slave, "Timeout while configuring"
599  " mailbox sync managers.\n");
600  return;
601  } else {
602  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
603  (unsigned int) diff * 1000 / HZ);
604  }
605 
606  // send configuration datagram again
607  fsm->retries = EC_FSM_RETRIES;
608  return;
609  }
610  else if (datagram->working_counter != 1) {
611  slave->error_flag = 1;
613  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
614  ec_datagram_print_wc_error(datagram);
615  return;
616  }
617 
618 #ifdef EC_SII_ASSIGN
620 #else
622 #endif
623 }
624 
625 /****************************************************************************/
626 
627 #ifdef EC_SII_ASSIGN
628 
633  )
634 {
635  ec_datagram_t *datagram = fsm->datagram;
636  ec_slave_t *slave = fsm->slave;
637 
639  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
640 
641  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
642  EC_WRITE_U8(datagram->data, 0x01); // PDI
643  fsm->retries = EC_FSM_RETRIES;
645  }
646  else {
648  }
649 }
650 
651 /****************************************************************************/
652 
657  )
658 {
659  ec_datagram_t *datagram = fsm->datagram;
660  ec_slave_t *slave = fsm->slave;
661 
662  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
663  return;
664  }
665 
666  if (datagram->state != EC_DATAGRAM_RECEIVED) {
667  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
668  ec_datagram_print_state(datagram);
669  goto cont_preop;
670  }
671 
672  if (datagram->working_counter != 1) {
673  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
674  ec_datagram_print_wc_error(datagram);
675  }
676 
677 cont_preop:
679 }
680 
681 #endif
682 
683 /****************************************************************************/
684 
689  )
690 {
692 
696  } else { // BOOT
698  fsm->slave, EC_SLAVE_STATE_BOOT);
699  }
700 
701  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
702 }
703 
704 /****************************************************************************/
705 
710  )
711 {
712  ec_slave_t *slave = fsm->slave;
713 #ifdef EC_SII_ASSIGN
714  int assign_to_pdi;
715  ec_slave_config_t *config;
716  ec_flag_t *flag;
717 #endif
718 
719  if (ec_fsm_change_exec(fsm->fsm_change)) {
720  return;
721  }
722 
723  if (!ec_fsm_change_success(fsm->fsm_change)) {
724  if (!fsm->fsm_change->spontaneous_change)
725  slave->error_flag = 1;
727  return;
728  }
729 
730  // slave is now in BOOT or PREOP
731  slave->jiffies_preop = fsm->datagram->jiffies_received;
732 
733  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
734  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
735 
736 #ifdef EC_SII_ASSIGN
737  assign_to_pdi = 0;
738  config = fsm->slave->config;
739  if (config) {
740  flag = ec_slave_config_find_flag(config, "AssignToPdi");
741  if (flag) {
742  assign_to_pdi = flag->value;
743  }
744  }
745 
746  if (assign_to_pdi) {
747  EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
748  if (slave->current_state == slave->requested_state) {
749  fsm->state = ec_fsm_slave_config_state_end; // successful
750  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
751  return;
752  }
753 
755  }
756  else {
757  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
758 
759  ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
760  EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
761  fsm->retries = EC_FSM_RETRIES;
763  }
764 #else
765  if (slave->current_state == slave->requested_state) {
766  fsm->state = ec_fsm_slave_config_state_end; // successful
767  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
768  return;
769  }
770 
772 #endif
773 }
774 
775 /****************************************************************************/
776 
777 #ifdef EC_SII_ASSIGN
778 
783  )
784 {
785  ec_datagram_t *datagram = fsm->datagram;
786  ec_slave_t *slave = fsm->slave;
787 
788  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
789  return;
790  }
791 
792  if (datagram->state != EC_DATAGRAM_RECEIVED) {
793  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
794  ec_datagram_print_state(datagram);
795  goto cont_sdo_conf;
796  }
797 
798  if (datagram->working_counter != 1) {
799  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
800  ec_datagram_print_wc_error(datagram);
801  }
802 
803 cont_sdo_conf:
804  if (slave->current_state == slave->requested_state) {
805  fsm->state = ec_fsm_slave_config_state_end; // successful
806  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
807  return;
808  }
809 
811 }
812 
813 #endif
814 
815 /****************************************************************************/
816 
821  )
822 {
823  ec_slave_t *slave = fsm->slave;
824 
825  if (!slave->config) {
827  return;
828  }
829 
830  // No CoE configuration to be applied?
831  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
833  return;
834  }
835 
836  // start SDO configuration
838  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
839  ec_sdo_request_t, list);
842  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
843  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
844 }
845 
846 /****************************************************************************/
847 
852  )
853 {
854  if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
855  return;
856  }
857 
858  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
859  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
860  fsm->slave->error_flag = 1;
862  return;
863  }
864 
865  if (!fsm->slave->config) { // config removed in the meantime
867  return;
868  }
869 
870  // Another SDO to configure?
871  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
872  fsm->request = list_entry(fsm->request->list.next,
873  ec_sdo_request_t, list);
876  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
877  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
878  return;
879  }
880 
881  // All SDOs are now configured.
883 }
884 
885 /****************************************************************************/
886 
891  )
892 {
893  ec_slave_t *slave = fsm->slave;
894  ec_soe_request_t *req;
895 
896  if (!slave->config) {
898  return;
899  }
900 
901  list_for_each_entry(req, &slave->config->soe_configs, list) {
902  if (req->al_state == EC_AL_STATE_PREOP) {
903  // start SoE configuration
905  fsm->soe_request = req;
908  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
909  &fsm->soe_request_copy);
910  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
911  return;
912  }
913  }
914 
915  // No SoE configuration to be applied in PREOP
917 }
918 
919 /****************************************************************************/
920 
925  )
926 {
927  ec_slave_t *slave = fsm->slave;
928 
929  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
930  return;
931  }
932 
933  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
934  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
935  fsm->slave->error_flag = 1;
937  return;
938  }
939 
940  if (!fsm->slave->config) { // config removed in the meantime
942  return;
943  }
944 
945  // Another IDN to configure in PREOP?
946  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
947  fsm->soe_request = list_entry(fsm->soe_request->list.next,
948  ec_soe_request_t, list);
949  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
952  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
953  &fsm->soe_request_copy);
954  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
955  return;
956  }
957  }
958 
959  // All PREOP IDNs are now configured.
961 }
962 
963 /****************************************************************************/
964 
969  )
970 {
971 #ifdef EC_EOE
972  ec_slave_t *slave = fsm->slave;
973  ec_eoe_request_t *request = &slave->config->eoe_ip_param_request;
974 
975  if (ec_eoe_request_valid(request)) {
976  EC_SLAVE_DBG(slave, 1, "Setting EoE IP parameters...\n");
977 
978  // Start EoE command
980  ec_fsm_eoe_set_ip_param(fsm->fsm_eoe, slave, request);
981  ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram); // execute immediately
982  return;
983  }
984 #endif
985 
987 }
988 
989 /****************************************************************************/
990 
995  )
996 {
997 #ifdef EC_EOE
998  ec_slave_t *slave = fsm->slave;
999 
1000  if (ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram)) {
1001  return;
1002  }
1003 
1004  if (ec_fsm_eoe_success(fsm->fsm_eoe)) {
1005  EC_SLAVE_DBG(slave, 1, "Finished setting EoE IP parameters.\n");
1006  }
1007  else {
1008  EC_SLAVE_ERR(slave, "Failed to set EoE IP parameters.\n");
1009  }
1010 #endif
1012 }
1013 
1014 /****************************************************************************/
1015 
1019  ec_fsm_slave_config_t *fsm
1020  )
1021 {
1022  // Start configuring PDOs
1025  fsm->state(fsm); // execute immediately
1026 }
1027 
1028 /****************************************************************************/
1029 
1033  ec_fsm_slave_config_t *fsm
1034  )
1035 {
1036  // TODO(fp) check for config here
1037 
1038  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
1039  return;
1040  }
1041 
1042  if (!fsm->slave->config) { // config removed in the meantime
1044  return;
1045  }
1046 
1047  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
1048  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
1049  }
1050 
1052 }
1053 
1054 /****************************************************************************/
1055 
1059  ec_fsm_slave_config_t *fsm
1060  )
1061 {
1062  ec_slave_t *slave = fsm->slave;
1063  ec_datagram_t *datagram = fsm->datagram;
1064  ec_slave_config_t *config = slave->config;
1065 
1066  if (config && config->watchdog_divider) {
1067  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1068  config->watchdog_divider);
1069 
1070  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1071  EC_WRITE_U16(datagram->data, config->watchdog_divider);
1072  fsm->retries = EC_FSM_RETRIES;
1074  } else {
1076  }
1077 }
1078 
1079 /****************************************************************************/
1080 
1084  ec_fsm_slave_config_t *fsm
1085  )
1086 {
1087  ec_datagram_t *datagram = fsm->datagram;
1088  ec_slave_t *slave = fsm->slave;
1089 
1090  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1091  return;
1092 
1093  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1095  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1096  " configuration datagram: ");
1097  ec_datagram_print_state(datagram);
1098  return;
1099  }
1100 
1101  if (datagram->working_counter != 1) {
1102  slave->error_flag = 1;
1103  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1104  ec_datagram_print_wc_error(datagram);
1105  return;
1106  }
1107 
1109 }
1110 
1111 /****************************************************************************/
1112 
1116  ec_fsm_slave_config_t *fsm
1117  )
1118 {
1119  ec_datagram_t *datagram = fsm->datagram;
1120  ec_slave_t *slave = fsm->slave;
1121  ec_slave_config_t *config = slave->config;
1122 
1123  if (config && config->watchdog_intervals) {
1124  EC_SLAVE_DBG(slave, 1, "Setting process data"
1125  " watchdog intervals to %u.\n", config->watchdog_intervals);
1126 
1127  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1128  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1129 
1130  fsm->retries = EC_FSM_RETRIES;
1132  } else {
1134  }
1135 }
1136 
1137 /****************************************************************************/
1138 
1143  ec_fsm_slave_config_t *fsm
1144  )
1145 {
1146  ec_datagram_t *datagram = fsm->datagram;
1147  ec_slave_t *slave = fsm->slave;
1148 
1149  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1150  return;
1151 
1152  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1154  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1155  " watchdog configuration datagram: ");
1156  ec_datagram_print_state(datagram);
1157  return;
1158  }
1159 
1160  if (datagram->working_counter != 1) {
1161  EC_SLAVE_WARN(slave, "Failed to set process data"
1162  " watchdog intervals: ");
1163  ec_datagram_print_wc_error(datagram);
1164  }
1165 
1167 }
1168 
1169 /****************************************************************************/
1170 
1174  ec_fsm_slave_config_t *fsm
1175  )
1176 {
1177  ec_slave_t *slave = fsm->slave;
1178  ec_datagram_t *datagram = fsm->datagram;
1179  unsigned int i, j, offset, num_pdo_syncs;
1180  uint8_t sync_index;
1181  const ec_sync_t *sync;
1182  uint16_t size;
1183 
1184  if (slave->sii.mailbox_protocols) {
1185  offset = 2; // slave has mailboxes
1186  } else {
1187  offset = 0;
1188  }
1189 
1190  if (slave->sii.sync_count <= offset) {
1191  // no PDO sync managers to configure
1193  return;
1194  }
1195 
1196  num_pdo_syncs = slave->sii.sync_count - offset;
1197 
1198  // configure sync managers for process data
1199  ec_datagram_fpwr(datagram, slave->station_address,
1200  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1201  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1202  ec_datagram_zero(datagram);
1203 
1204  for (i = 0; i < num_pdo_syncs; i++) {
1205  const ec_sync_config_t *sync_config;
1206  uint8_t pdo_xfer = 0;
1207  sync_index = i + offset;
1208  sync = &slave->sii.syncs[sync_index];
1209 
1210  if (slave->config) {
1211  const ec_slave_config_t *sc = slave->config;
1212  sync_config = &sc->sync_configs[sync_index];
1213  size = ec_pdo_list_total_size(&sync_config->pdos);
1214 
1215  // determine, if PDOs shall be transferred via this SM
1216  // inthat case, enable sync manager in every case
1217  for (j = 0; j < sc->used_fmmus; j++) {
1218  if (sc->fmmu_configs[j].sync_index == sync_index) {
1219  pdo_xfer = 1;
1220  break;
1221  }
1222  }
1223 
1224  } else {
1225  sync_config = NULL;
1226  size = sync->default_length;
1227  }
1228 
1229  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1230  datagram->data + EC_SYNC_PAGE_SIZE * i);
1231  }
1232 
1233  fsm->retries = EC_FSM_RETRIES;
1235 }
1236 
1237 /****************************************************************************/
1238 
1242  ec_fsm_slave_config_t *fsm
1243  )
1244 {
1245  ec_datagram_t *datagram = fsm->datagram;
1246  ec_slave_t *slave = fsm->slave;
1247 
1248  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1249  return;
1250 
1251  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1253  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1254  " manager configuration datagram: ");
1255  ec_datagram_print_state(datagram);
1256  return;
1257  }
1258 
1259  if (datagram->working_counter != 1) {
1260  slave->error_flag = 1;
1262  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1263  ec_datagram_print_wc_error(datagram);
1264  return;
1265  }
1266 
1268 }
1269 
1270 /****************************************************************************/
1271 
1275  ec_fsm_slave_config_t *fsm
1276  )
1277 {
1278  ec_slave_t *slave = fsm->slave;
1279  ec_datagram_t *datagram = fsm->datagram;
1280  unsigned int i;
1281  const ec_fmmu_config_t *fmmu;
1282  const ec_sync_t *sync;
1283 
1284  if (!slave->config) {
1286  return;
1287  }
1288 
1289  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1290  slave->error_flag = 1;
1292  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1293  " than requested (%u).\n", slave->base_fmmu_count,
1294  slave->config->used_fmmus);
1295  return;
1296  }
1297 
1298  if (!slave->base_fmmu_count) { // skip FMMU configuration
1300  return;
1301  }
1302 
1303  // configure FMMUs
1304  ec_datagram_fpwr(datagram, slave->station_address,
1305  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1306  ec_datagram_zero(datagram);
1307  for (i = 0; i < slave->config->used_fmmus; i++) {
1308  fmmu = &slave->config->fmmu_configs[i];
1309  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1310  slave->error_flag = 1;
1312  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1313  " for FMMU!\n");
1314  return;
1315  }
1316  ec_fmmu_config_page(fmmu, sync,
1317  datagram->data + EC_FMMU_PAGE_SIZE * i);
1318  }
1319 
1320  fsm->retries = EC_FSM_RETRIES;
1322 }
1323 
1324 /****************************************************************************/
1325 
1329  ec_fsm_slave_config_t *fsm
1330  )
1331 {
1332  ec_datagram_t *datagram = fsm->datagram;
1333  ec_slave_t *slave = fsm->slave;
1334 
1335  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1336  return;
1337 
1338  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1340  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1341  ec_datagram_print_state(datagram);
1342  return;
1343  }
1344 
1345  if (datagram->working_counter != 1) {
1346  slave->error_flag = 1;
1348  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1349  ec_datagram_print_wc_error(datagram);
1350  return;
1351  }
1352 
1354 }
1355 
1356 /****************************************************************************/
1357 
1361  ec_fsm_slave_config_t *fsm
1362  )
1363 {
1364  ec_datagram_t *datagram = fsm->datagram;
1365  ec_slave_t *slave = fsm->slave;
1366  ec_slave_config_t *config = slave->config;
1367 
1368  if (!config) { // config removed in the meantime
1370  return;
1371  }
1372 
1373  if (config->dc_assign_activate) {
1374  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1375  EC_SLAVE_WARN(slave, "Slave seems not to support"
1376  " distributed clocks!\n");
1377  }
1378 
1379  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1380  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1381 
1382  // set DC cycle times
1383  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1384  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1385  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1386  fsm->retries = EC_FSM_RETRIES;
1388  } else {
1389  // DC are unused
1391  }
1392 }
1393 
1394 /****************************************************************************/
1395 
1399  ec_fsm_slave_config_t *fsm
1400  )
1401 {
1402  ec_datagram_t *datagram = fsm->datagram;
1403  ec_slave_t *slave = fsm->slave;
1404  ec_slave_config_t *config = slave->config;
1405 
1406  if (!config) { // config removed in the meantime
1408  return;
1409  }
1410 
1411  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1412  return;
1413 
1414  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1416  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1417  ec_datagram_print_state(datagram);
1418  return;
1419  }
1420 
1421  if (datagram->working_counter != 1) {
1422  slave->error_flag = 1;
1424  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1425  ec_datagram_print_wc_error(datagram);
1426  return;
1427  }
1428 
1429  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1430 
1431  fsm->jiffies_start = jiffies;
1432  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1433  fsm->retries = EC_FSM_RETRIES;
1435 }
1436 
1437 /****************************************************************************/
1438 
1442  ec_fsm_slave_config_t *fsm
1443  )
1444 {
1445  ec_datagram_t *datagram = fsm->datagram;
1446  ec_slave_t *slave = fsm->slave;
1447  ec_master_t *master = slave->master;
1448  ec_slave_config_t *config = slave->config;
1449  uint32_t abs_sync_diff;
1450  unsigned long diff_ms;
1451  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1452  ec_sync_signal_t *sync1 = &config->dc_sync[1];
1453  u64 start_time;
1454 
1455  if (!config) { // config removed in the meantime
1457  return;
1458  }
1459 
1460  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1461  return;
1462 
1463  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1465  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1466  ec_datagram_print_state(datagram);
1467  return;
1468  }
1469 
1470  if (datagram->working_counter != 1) {
1471  slave->error_flag = 1;
1473  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1474  ec_datagram_print_wc_error(datagram);
1475  return;
1476  }
1477 
1478  abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1479  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1480 
1481  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1482  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1483  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1484  diff_ms);
1485  } else {
1486  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1487  diff_ms, abs_sync_diff);
1488 
1489  // check synchrony again
1490  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1491  fsm->retries = EC_FSM_RETRIES;
1492  return;
1493  }
1494  } else {
1495  EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1496  abs_sync_diff, diff_ms);
1497  }
1498 
1499  // set DC start time (roughly in the future, not in-phase)
1500  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1501 
1502  if (sync0->cycle_time) {
1503  // find correct phase
1504  if (master->dc_ref_time) {
1505  u64 diff, start;
1506  u32 remainder, cycle;
1507 
1508  diff = start_time - master->dc_ref_time;
1509  cycle = sync0->cycle_time + sync1->cycle_time;
1510  remainder = do_div(diff, cycle);
1511 
1512  start = start_time + cycle - remainder + sync0->shift_time;
1513 
1514  EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1515  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1516  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1517  EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1518  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1519  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1520  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1521  start_time = start;
1522  } else {
1523  EC_SLAVE_WARN(slave, "No application time supplied."
1524  " Cyclic start time will not be in phase.\n");
1525  }
1526  }
1527 
1528  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1529  " start time to %llu.\n", start_time);
1530 
1531  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1532  EC_WRITE_U64(datagram->data, start_time);
1533  fsm->retries = EC_FSM_RETRIES;
1535 }
1536 
1537 /****************************************************************************/
1538 
1542  ec_fsm_slave_config_t *fsm
1543  )
1544 {
1545  ec_datagram_t *datagram = fsm->datagram;
1546  ec_slave_t *slave = fsm->slave;
1547  ec_slave_config_t *config = slave->config;
1548 
1549  if (!config) { // config removed in the meantime
1551  return;
1552  }
1553 
1554  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1555  return;
1556 
1557  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1559  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1560  ec_datagram_print_state(datagram);
1561  return;
1562  }
1563 
1564  if (datagram->working_counter != 1) {
1565  slave->error_flag = 1;
1567  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1568  ec_datagram_print_wc_error(datagram);
1569  return;
1570  }
1571 
1572  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1573  config->dc_assign_activate);
1574 
1575  // assign sync unit to EtherCAT or PDI
1576  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1577  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1578  fsm->retries = EC_FSM_RETRIES;
1580 }
1581 
1582 /****************************************************************************/
1583 
1587  ec_fsm_slave_config_t *fsm
1588  )
1589 {
1590  ec_datagram_t *datagram = fsm->datagram;
1591  ec_slave_t *slave = fsm->slave;
1592 
1593  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1594  return;
1595 
1596  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1598  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1599  ec_datagram_print_state(datagram);
1600  return;
1601  }
1602 
1603  if (datagram->working_counter != 1) {
1604  slave->error_flag = 1;
1606  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1607  ec_datagram_print_wc_error(datagram);
1608  return;
1609  }
1610 
1612 }
1613 
1614 /****************************************************************************/
1615 
1623  ec_fsm_slave_config_t *fsm
1624  )
1625 {
1626  ec_slave_config_t *config = fsm->slave->config;
1627  fsm->wait_ms = 0UL;
1628  if (config) {
1629  ec_flag_t *flag = ec_slave_config_find_flag(config,
1630  "WaitBeforeSAFEOPms");
1631  if (flag && flag->value > 0) {
1632  fsm->wait_ms = (unsigned long) flag->value;
1633  }
1634  }
1635 
1636  if (fsm->wait_ms > 0) {
1638 
1639  /* dummy read */
1641  0x0600, 1);
1642 
1643  fsm->jiffies_start = jiffies;
1644  }
1645  else {
1647  }
1648 }
1649 
1650 /****************************************************************************/
1651 
1655  ec_fsm_slave_config_t *fsm
1656  )
1657 {
1658  unsigned long diff = jiffies - fsm->jiffies_start;
1659 
1660  if (diff * 1000 / HZ < fsm->wait_ms) {
1661  return;
1662  }
1663 
1665 }
1666 
1667 /****************************************************************************/
1668 
1672  ec_fsm_slave_config_t *fsm
1673  )
1674 {
1677  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1678 }
1679 
1680 /****************************************************************************/
1681 
1685  ec_fsm_slave_config_t *fsm
1686  )
1687 {
1688  ec_slave_t *slave = fsm->slave;
1689 
1690  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1691 
1692  if (!ec_fsm_change_success(fsm->fsm_change)) {
1693  if (!fsm->fsm_change->spontaneous_change)
1694  fsm->slave->error_flag = 1;
1696  return;
1697  }
1698 
1699  // slave is now in SAFEOP
1700 
1701  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1702 
1703  if (fsm->slave->current_state == fsm->slave->requested_state) {
1704  fsm->state = ec_fsm_slave_config_state_end; // successful
1705  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1706  return;
1707  }
1708 
1710 }
1711 
1712 /****************************************************************************/
1713 
1717  ec_fsm_slave_config_t *fsm
1718  )
1719 {
1720  ec_slave_t *slave = fsm->slave;
1721  ec_soe_request_t *req;
1722 
1723  if (!slave->config) {
1725  return;
1726  }
1727 
1728  list_for_each_entry(req, &slave->config->soe_configs, list) {
1729  if (req->al_state == EC_AL_STATE_SAFEOP) {
1730  // start SoE configuration
1732  fsm->soe_request = req;
1735  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1736  &fsm->soe_request_copy);
1737  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1738  return;
1739  }
1740  }
1741 
1742  // No SoE configuration to be applied in SAFEOP
1744 }
1745 
1746 /****************************************************************************/
1747 
1751  ec_fsm_slave_config_t *fsm
1752  )
1753 {
1754  ec_slave_t *slave = fsm->slave;
1755 
1756  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1757  return;
1758  }
1759 
1760  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1761  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1762  fsm->slave->error_flag = 1;
1764  return;
1765  }
1766 
1767  if (!fsm->slave->config) { // config removed in the meantime
1769  return;
1770  }
1771 
1772  // Another IDN to configure in SAFEOP?
1773  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1774  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1775  ec_soe_request_t, list);
1776  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1779  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1780  &fsm->soe_request_copy);
1781  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1782  return;
1783  }
1784  }
1785 
1786  // All SAFEOP IDNs are now configured.
1788 }
1789 
1790 /****************************************************************************/
1791 
1795  ec_fsm_slave_config_t *fsm
1796  )
1797 {
1798  // set state to OP
1801  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1802 }
1803 
1804 /****************************************************************************/
1805 
1809  ec_fsm_slave_config_t *fsm
1810  )
1811 {
1812  ec_slave_t *slave = fsm->slave;
1813 
1814  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1815 
1816  if (!ec_fsm_change_success(fsm->fsm_change)) {
1817  if (!fsm->fsm_change->spontaneous_change)
1818  slave->error_flag = 1;
1820  return;
1821  }
1822 
1823  // slave is now in OP
1824 
1825  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1826 
1827  fsm->state = ec_fsm_slave_config_state_end; // successful
1828 }
1829 
1830 /****************************************************************************/
1831 
1835  ec_fsm_slave_config_t *fsm
1836  )
1837 {
1838  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1839  "configuration. Reconfiguring.");
1840 
1841  ec_fsm_slave_config_enter_init(fsm); // reconfigure
1842 }
1843 
1844 /*****************************************************************************
1845  * Common state functions
1846  ****************************************************************************/
1847 
1851  ec_fsm_slave_config_t *fsm
1852  )
1853 {
1854 }
1855 
1856 /****************************************************************************/
1857 
1861  ec_fsm_slave_config_t *fsm
1862  )
1863 {
1864 }
1865 
1866 /****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
Finite state machines for the Sercos over EtherCAT protocol.
Definition: fsm_soe.h:44
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:122
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:101
Pre-operational.
Definition: ecrt.h:671
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *)
Slave configuration state: BOOT/PREOP.
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:143
uint16_t boot_rx_mailbox_offset
Bootstrap rx mailbox address.
Definition: slave.h:133
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:95
ec_sii_t sii
Extracted SII data.
Definition: slave.h:218
int ec_fsm_pdo_exec(ec_fsm_pdo_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_pdo.c:171
void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm, ec_slave_t *slave)
Start slave configuration state machine.
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:68
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *)
WATCHDOG entry function.
int ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:232
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:195
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *)
Slave configuration state: INIT.
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SAFEOP.
void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *)
Assign SII to PDI.
FMMU configuration.
Definition: fmmu_config.h:38
ec_sdo_request_t * request
SDO request for SDO configuration.
void ec_fsm_slave_config_state_wait_safeop(ec_fsm_slave_config_t *)
Slave configuration state: WAIT SAFEOP.
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *)
Reconfigure the slave starting at INIT.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:100
void ec_fsm_pdo_start_configuration(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start writing the PDO configuration.
Definition: fsm_pdo.c:139
int32_t shift_time
Shift time [ns].
Definition: globals.h:187
void ec_fsm_slave_config_enter_eoe_ip_param(ec_fsm_slave_config_t *)
EOE_IP_PARAM entry function.
OP (mailbox communication and input/output update)
Definition: globals.h:138
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:193
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *)
Slave configuration state: DC CYCLE.
ec_fsm_change_t * fsm_change
State change state machine.
CANopen SDO request.
Definition: sdo_request.h:40
ec_slave_state_t current_state
Current application state.
Definition: slave.h:186
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR DC ASSIGN.
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *)
Slave configuration state: DC START.
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:139
Safe-operational.
Definition: ecrt.h:672
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:84
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied in SAFEOP.
EtherCAT datagram.
Definition: datagram.h:81
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
void ec_slave_mbox_prealloc(ec_slave_t *slave)
Allocates the mailbox response buffers of a slave.
Definition: mailbox.c:100
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3353
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:237
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:134
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
ec_eoe_request_t eoe_ip_param_request
EoE IP parameters.
Definition: slave_config.h:153
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:186
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
uint16_t working_counter
Working counter.
Definition: datagram.h:96
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:262
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *)
Slave configuration state: START.
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:136
Sent (still in the queue).
Definition: datagram.h:69
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
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *)
Slave configuration state: SYNC.
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *)
Clear the DC assignment.
uint16_t station_address
Configured station address.
Definition: slave.h:178
int ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
Definition: soe_request.c:253
unsigned int sync_count
Number of sync managers.
Definition: slave.h:160
ec_fsm_eoe_t * fsm_eoe
EoE state machine.
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:138
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:105
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
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:139
ec_al_state_t al_state
AL state (only valid for IDN config).
Definition: soe_request.h:44
EtherCAT master structure.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:138
SAFEOP (mailbox communication and input update)
Definition: globals.h:136
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *)
WATCHDOG_DIVIDER entry function.
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:141
uint16_t boot_tx_mailbox_offset
Bootstrap tx mailbox address.
Definition: slave.h:135
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_PDI.
EtherCAT slave.
Definition: slave.h:170
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_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition: sdo_request.c:70
EtherCAT slave configuration state machine.
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
uint16_t ec_pdo_list_total_size(const ec_pdo_list_t *pl)
Calculates the total size of the mapped PDO entries.
Definition: pdo_list.c:79
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
void ec_fsm_soe_transfer(ec_fsm_soe_t *fsm, ec_slave_t *slave, ec_soe_request_t *request)
Starts to transfer an IDN to/from a slave.
Definition: fsm_soe.c: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
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:136
ec_datagram_state_t state
State.
Definition: datagram.h:97
ec_slave_config_t * config
Current configuration.
Definition: slave.h:184
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3387
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:42
Slave configutation feature flag.
Definition: flag.h:38
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG_DIVIDER.
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:141
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
Definition: slave_config.c:647
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *)
State: END.
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *)
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:70
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:605
#define EC_DC_START_OFFSET
Time offset (in ns), that is added to cyclic start time.
Sync manager.
Definition: sync.h:39
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:137
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:157
struct list_head list
List item.
Definition: soe_request.h:41
void ec_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition: soe_request.c:71
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR FMMU.
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:41
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:140
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *)
Check for mailbox sync managers to be configured.
ec_datagram_t * datagram
Datagram used in the state machine.
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3370
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:201
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:189
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_eoe.c:157
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *)
Check for FMMUs to be configured.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3277
unsigned long wait_ms
Wait time (used to wait before SAFEOP).
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:123
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *)
Check for SDO configurations to be applied.
ec_master_t * master
Master owning the slave.
Definition: slave.h:172
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_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied.
void(* state)(ec_fsm_slave_config_t *)
State function.
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:298
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:206
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *)
Start state change to INIT.
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: PDO_CONF.
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition: datagram.c:273
uint8_t control_register
Control register value.
Definition: sync.h:43
ec_fsm_coe_t * fsm_coe
CoE state machine.
uint16_t watchdog_divider
Watchdog divider as a number of 40ns intervals (see spec.
Definition: slave_config.h:121
PDO configuration state machine.
Definition: fsm_pdo.h:46
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_state_pdo_sync(ec_fsm_slave_config_t *)
Configure PDO sync managers.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *)
Request SAFEOP state.
ec_fsm_soe_t * fsm_soe
SoE state machine.
struct list_head soe_configs
List of SoE configurations.
Definition: slave_config.h:148
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
Ethernet-over-EtherCAT set IP parameter request.
Definition: eoe_request.h:41
unsigned int take_time
Store jiffies after datagram reception.
void ec_fsm_slave_config_state_eoe_ip_param(ec_fsm_slave_config_t *)
Slave configuration state: EOE_IP_PARAM.
INIT state (no mailbox communication, no IO)
Definition: globals.h:130
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:187
Finite state machine to configure an EtherCAT slave.
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
Mailbox functionality.
uint8_t enable
Enable bit.
Definition: sync.h:44
ec_slave_t * slave
Slave the FSM runs on.
Invalid direction.
Definition: ecrt.h:523
void ec_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition: sdo_request.c:48
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *)
Slave configuration state: OP.
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3404
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:134
ec_soe_request_t soe_request_copy
Copied SDO request.
Sync manager configuration.
Definition: sync_config.h:38
int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm)
Executes the current state of the state machine.
struct list_head list
List item.
Definition: sdo_request.h:41
EtherCAT slave sync signal configuration.
Definition: globals.h:185
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:229
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR SYNC.
Queued for sending.
Definition: datagram.h:68
Timed out (dequeued).
Definition: datagram.h:71
void ec_fsm_slave_config_enter_wait_safeop(ec_fsm_slave_config_t *)
Wait before SAFEOP transition.
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *)
State: ERROR.
int32_t value
Flag value (meaning depends on key).
Definition: flag.h:41
void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *fsm)
Destructor.
u64 app_time
Time of the last ecrt_master_sync() call.
Definition: master.h:236
uint16_t physical_start_address
Physical start address.
Definition: sync.h:41
unsigned long jiffies_preop
Time, the slave went to PREOP.
Definition: slave.h:222
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:191
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:204
uint8_t * data
Datagram payload.
Definition: datagram.h:91
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *)
Slave configuration state: DC ASSIGN.
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:202
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *)
Bring slave to OP.
EtherCAT slave configuration.
Definition: slave_config.h:111
ec_soe_request_t * soe_request
SDO request for SDO configuration.
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *)
Check for PDO sync managers to be configured.
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition: soe_request.c:48
EtherCAT slave configuration structure.
int ec_fsm_soe_exec(ec_fsm_soe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_soe.c:152
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:206
uint16_t default_length
Data length in bytes.
Definition: sync.h:42
void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_ETHERCAT.
PREOP state (mailbox communication, no IO)
Definition: globals.h:132
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: SDO_CONF.
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG.
Received (dequeued).
Definition: datagram.h:70
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *)
Request PREOP state.
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:187
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:159
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:140
EtherCAT master.
Definition: master.h:194
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:185
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:101
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c:38
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *)
Slave configuration state: DC SYNC CHECK.
#define EC_DC_SYNC_WAIT_MS
Maximum time (in ms) to wait for clock discipline.
Sercos-over-EtherCAT request.
Definition: soe_request.h:40
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:105
EtherCAT state change FSM.
Definition: fsm_change.h:56
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *)
Check for DC to be configured.
int ec_soe_request_copy(ec_soe_request_t *req, const ec_soe_request_t *other)
Copy another SoE request.
Definition: soe_request.c:84
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:172
Finite state machines for the Ethernet over EtherCAT protocol.
Definition: fsm_eoe.h:44
unsigned long jiffies_start
For timeout calculations.
Finite state machines for the CANopen over EtherCAT protocol.
Definition: fsm_coe.h:45
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:864
unsigned int retries
Retries on datagram timeout.