IgH EtherCAT Master  1.6.0
fsm_slave_config.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
4  *
5  * This file is part of the IgH EtherCAT Master.
6  *
7  * The IgH EtherCAT Master is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version 2, as
9  * published by the Free Software Foundation.
10  *
11  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14  * Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with the IgH EtherCAT Master; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
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 
61 #ifdef EC_SII_ASSIGN
63 #endif
65 #ifdef EC_SII_ASSIGN
67 #endif
83 
88 #ifdef EC_SII_ASSIGN
90 #endif
104 
107 
109 
110 /****************************************************************************/
111 
115  ec_fsm_slave_config_t *fsm,
116  ec_datagram_t *datagram,
117  ec_fsm_change_t *fsm_change,
118  ec_fsm_coe_t *fsm_coe,
119  ec_fsm_soe_t *fsm_soe,
120  ec_fsm_pdo_t *fsm_pdo
121  )
122 {
125 
126  fsm->datagram = datagram;
127  fsm->fsm_change = fsm_change;
128  fsm->fsm_coe = fsm_coe;
129  fsm->fsm_soe = fsm_soe;
130  fsm->fsm_pdo = fsm_pdo;
131 
132  fsm->wait_ms = 0;
133 }
134 
135 /****************************************************************************/
136 
141  )
142 {
145 }
146 
147 /****************************************************************************/
148 
152  ec_fsm_slave_config_t *fsm,
153  ec_slave_t *slave
154  )
155 {
156  fsm->slave = slave;
158 }
159 
160 /****************************************************************************/
161 
166  const ec_fsm_slave_config_t *fsm
167  )
168 {
169  return fsm->state != ec_fsm_slave_config_state_end
171 }
172 
173 /****************************************************************************/
174 
184  )
185 {
186  if (fsm->datagram->state == EC_DATAGRAM_SENT
187  || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
188  // datagram was not sent or received yet.
189  return ec_fsm_slave_config_running(fsm);
190  }
191 
192  fsm->state(fsm);
193  return ec_fsm_slave_config_running(fsm);
194 }
195 
196 /****************************************************************************/
197 
202  const ec_fsm_slave_config_t *fsm
203  )
204 {
205  return fsm->state == ec_fsm_slave_config_state_end;
206 }
207 
208 /*****************************************************************************
209  * Slave configuration state machine
210  ****************************************************************************/
211 
216  )
217 {
218  EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
220 }
221 
222 /****************************************************************************/
223 
228  )
229 {
233 }
234 
235 /****************************************************************************/
236 
241  )
242 {
243  ec_slave_t *slave = fsm->slave;
244  ec_datagram_t *datagram = fsm->datagram;
245 
246  if (ec_fsm_change_exec(fsm->fsm_change)) return;
247 
248  if (!ec_fsm_change_success(fsm->fsm_change)) {
249  if (!fsm->fsm_change->spontaneous_change)
250  slave->error_flag = 1;
252  return;
253  }
254 
255  EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
256 
257  if (!slave->base_fmmu_count) { // skip FMMU configuration
259  return;
260  }
261 
262  EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
263 
264  // clear FMMU configurations
265  ec_datagram_fpwr(datagram, slave->station_address,
266  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
267  ec_datagram_zero(datagram);
268  fsm->retries = EC_FSM_RETRIES;
270 }
271 
272 /****************************************************************************/
273 
278  )
279 {
280  ec_datagram_t *datagram = fsm->datagram;
281 
282  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
283  return;
284 
285  if (datagram->state != EC_DATAGRAM_RECEIVED) {
287  EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
288  return;
289  }
290 
291  if (datagram->working_counter != 1) {
292  fsm->slave->error_flag = 1;
294  EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
295  ec_datagram_print_wc_error(datagram);
296  return;
297  }
298 
300 }
301 
302 /****************************************************************************/
303 
308  )
309 {
310  ec_slave_t *slave = fsm->slave;
311  ec_datagram_t *datagram = fsm->datagram;
312  size_t sync_size;
313 
314  if (!slave->base_sync_count) {
315  // no sync managers
317  return;
318  }
319 
320  EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
321 
322  sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
323 
324  // clear sync manager configurations
325  ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
326  ec_datagram_zero(datagram);
327  fsm->retries = EC_FSM_RETRIES;
329 }
330 
331 /****************************************************************************/
332 
337  )
338 {
339  ec_datagram_t *datagram = fsm->datagram;
340 
341  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
342  return;
343 
344  if (datagram->state != EC_DATAGRAM_RECEIVED) {
346  EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
347  " clearing datagram.\n");
348  return;
349  }
350 
351  if (datagram->working_counter != 1) {
352  fsm->slave->error_flag = 1;
354  EC_SLAVE_ERR(fsm->slave,
355  "Failed to clear sync manager configurations: ");
356  ec_datagram_print_wc_error(datagram);
357  return;
358  }
359 
361 }
362 
363 /****************************************************************************/
364 
369  )
370 {
371  ec_slave_t *slave = fsm->slave;
372  ec_datagram_t *datagram = fsm->datagram;
373 
374  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
376  return;
377  }
378 
379  EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
380 
381  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
382  ec_datagram_zero(datagram);
383  fsm->retries = EC_FSM_RETRIES;
385 }
386 
387 /****************************************************************************/
388 
393  )
394 {
395  ec_datagram_t *datagram = fsm->datagram;
396 
397  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
398  return;
399 
400  if (datagram->state != EC_DATAGRAM_RECEIVED) {
402  EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
403  " clearing datagram.\n");
404  return;
405  }
406 
407  if (datagram->working_counter != 1) {
408  // clearing the DC assignment does not succeed on simple slaves
409  EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
410  ec_datagram_print_wc_error(datagram);
411  }
412 
414 }
415 
416 /****************************************************************************/
417 
422  )
423 {
424  ec_slave_t *slave = fsm->slave;
425  ec_datagram_t *datagram = fsm->datagram;
426  unsigned int i;
427 
428  // slave is now in INIT
429  if (slave->current_state == slave->requested_state) {
430  fsm->state = ec_fsm_slave_config_state_end; // successful
431  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
432  return;
433  }
434 
435  if (!slave->sii.mailbox_protocols) {
436  // no mailbox protocols supported
437  EC_SLAVE_DBG(slave, 1, "Slave does not support"
438  " mailbox communication.\n");
439 #ifdef EC_SII_ASSIGN
441 #else
443 #endif
444  return;
445  }
446 
447  EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
448 
449  if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
450  ec_sync_t sync;
451 
452  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
453  EC_SYNC_PAGE_SIZE * 2);
454  ec_datagram_zero(datagram);
455 
456  ec_sync_init(&sync, slave);
458  sync.control_register = 0x26;
459  sync.enable = 1;
460  ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
461  EC_DIR_INVALID, // use default direction
462  0, // no PDO xfer
463  datagram->data);
467  slave->sii.boot_rx_mailbox_size;
468 
469  ec_sync_init(&sync, slave);
471  sync.control_register = 0x22;
472  sync.enable = 1;
473  ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
474  EC_DIR_INVALID, // use default direction
475  0, // no PDO xfer
476  datagram->data + EC_SYNC_PAGE_SIZE);
480  slave->sii.boot_tx_mailbox_size;
481 
482  } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
483  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
484  EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
485  ec_datagram_zero(datagram);
486 
487  for (i = 0; i < 2; i++) {
488  ec_sync_page(&slave->sii.syncs[i], i,
489  slave->sii.syncs[i].default_length,
490  NULL, // use default sync manager configuration
491  0, // no PDO xfer
492  datagram->data + EC_SYNC_PAGE_SIZE * i);
493  }
494 
496  slave->sii.syncs[0].physical_start_address;
498  slave->sii.syncs[0].default_length;
500  slave->sii.syncs[1].physical_start_address;
502  slave->sii.syncs[1].default_length;
503  } else { // no mailbox sync manager configurations provided
504  ec_sync_t sync;
505 
506  EC_SLAVE_DBG(slave, 1, "Slave does not provide"
507  " mailbox sync manager configurations.\n");
508 
509  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
510  EC_SYNC_PAGE_SIZE * 2);
511  ec_datagram_zero(datagram);
512 
513  ec_sync_init(&sync, slave);
515  sync.control_register = 0x26;
516  sync.enable = 1;
517  ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
518  NULL, // use default sync manager configuration
519  0, // no PDO xfer
520  datagram->data);
522  slave->sii.std_rx_mailbox_offset;
524  slave->sii.std_rx_mailbox_size;
525 
526  ec_sync_init(&sync, slave);
528  sync.control_register = 0x22;
529  sync.enable = 1;
530  ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
531  NULL, // use default sync manager configuration
532  0, // no PDO xfer
533  datagram->data + EC_SYNC_PAGE_SIZE);
535  slave->sii.std_tx_mailbox_offset;
537  slave->sii.std_tx_mailbox_size;
538  }
539 
540  fsm->take_time = 1;
541 
542  fsm->retries = EC_FSM_RETRIES;
544 }
545 
546 /****************************************************************************/
547 
554  )
555 {
556  ec_datagram_t *datagram = fsm->datagram;
557  ec_slave_t *slave = fsm->slave;
558 
559  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
560  return;
561 
562  if (datagram->state != EC_DATAGRAM_RECEIVED) {
564  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
565  " configuration datagram: ");
566  ec_datagram_print_state(datagram);
567  return;
568  }
569 
570  if (fsm->take_time) {
571  fsm->take_time = 0;
572  fsm->jiffies_start = datagram->jiffies_sent;
573  }
574 
575  /* Because the sync manager configurations are cleared during the last
576  * cycle, some slaves do not immediately respond to the mailbox sync
577  * manager configuration datagram. Therefore, resend the datagram for
578  * a certain time, if the slave does not respond.
579  */
580  if (datagram->working_counter == 0) {
581  unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
582 
583  if (diff >= HZ) {
584  slave->error_flag = 1;
586  EC_SLAVE_ERR(slave, "Timeout while configuring"
587  " mailbox sync managers.\n");
588  return;
589  } else {
590  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
591  (unsigned int) diff * 1000 / HZ);
592  }
593 
594  // send configuration datagram again
595  fsm->retries = EC_FSM_RETRIES;
596  return;
597  }
598  else if (datagram->working_counter != 1) {
599  slave->error_flag = 1;
601  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
602  ec_datagram_print_wc_error(datagram);
603  return;
604  }
605 
606 #ifdef EC_SII_ASSIGN
608 #else
610 #endif
611 }
612 
613 /****************************************************************************/
614 
615 #ifdef EC_SII_ASSIGN
616 
621  )
622 {
623  ec_datagram_t *datagram = fsm->datagram;
624  ec_slave_t *slave = fsm->slave;
625 
627  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
628 
629  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
630  EC_WRITE_U8(datagram->data, 0x01); // PDI
631  fsm->retries = EC_FSM_RETRIES;
633  }
634  else {
636  }
637 }
638 
639 /****************************************************************************/
640 
645  )
646 {
647  ec_datagram_t *datagram = fsm->datagram;
648  ec_slave_t *slave = fsm->slave;
649 
650  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
651  return;
652  }
653 
654  if (datagram->state != EC_DATAGRAM_RECEIVED) {
655  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
656  ec_datagram_print_state(datagram);
657  goto cont_preop;
658  }
659 
660  if (datagram->working_counter != 1) {
661  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
662  ec_datagram_print_wc_error(datagram);
663  }
664 
665 cont_preop:
667 }
668 
669 #endif
670 
671 /****************************************************************************/
672 
677  )
678 {
680 
684  } else { // BOOT
686  fsm->slave, EC_SLAVE_STATE_BOOT);
687  }
688 
689  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
690 }
691 
692 /****************************************************************************/
693 
698  )
699 {
700  ec_slave_t *slave = fsm->slave;
701 #ifdef EC_SII_ASSIGN
702  int assign_to_pdi;
703  ec_slave_config_t *config;
704  ec_flag_t *flag;
705 #endif
706 
707  if (ec_fsm_change_exec(fsm->fsm_change)) {
708  return;
709  }
710 
711  if (!ec_fsm_change_success(fsm->fsm_change)) {
712  if (!fsm->fsm_change->spontaneous_change)
713  slave->error_flag = 1;
715  return;
716  }
717 
718  // slave is now in BOOT or PREOP
719  slave->jiffies_preop = fsm->datagram->jiffies_received;
720 
721  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
722  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
723 
724 #ifdef EC_SII_ASSIGN
725  assign_to_pdi = 0;
726  config = fsm->slave->config;
727  if (config) {
728  flag = ec_slave_config_find_flag(config, "AssignToPdi");
729  if (flag) {
730  assign_to_pdi = flag->value;
731  }
732  }
733 
734  if (assign_to_pdi) {
735  EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
736  if (slave->current_state == slave->requested_state) {
737  fsm->state = ec_fsm_slave_config_state_end; // successful
738  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
739  return;
740  }
741 
743  }
744  else {
745  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
746 
747  ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
748  EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
749  fsm->retries = EC_FSM_RETRIES;
751  }
752 #else
753  if (slave->current_state == slave->requested_state) {
754  fsm->state = ec_fsm_slave_config_state_end; // successful
755  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
756  return;
757  }
758 
760 #endif
761 }
762 
763 /****************************************************************************/
764 
765 #ifdef EC_SII_ASSIGN
766 
771  )
772 {
773  ec_datagram_t *datagram = fsm->datagram;
774  ec_slave_t *slave = fsm->slave;
775 
776  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
777  return;
778  }
779 
780  if (datagram->state != EC_DATAGRAM_RECEIVED) {
781  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
782  ec_datagram_print_state(datagram);
783  goto cont_sdo_conf;
784  }
785 
786  if (datagram->working_counter != 1) {
787  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
788  ec_datagram_print_wc_error(datagram);
789  }
790 
791 cont_sdo_conf:
792  if (slave->current_state == slave->requested_state) {
793  fsm->state = ec_fsm_slave_config_state_end; // successful
794  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
795  return;
796  }
797 
799 }
800 
801 #endif
802 
803 /****************************************************************************/
804 
809  )
810 {
811  ec_slave_t *slave = fsm->slave;
812 
813  if (!slave->config) {
815  return;
816  }
817 
818  // No CoE configuration to be applied?
819  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
821  return;
822  }
823 
824  // start SDO configuration
826  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
827  ec_sdo_request_t, list);
830  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
831  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
832 }
833 
834 /****************************************************************************/
835 
840  )
841 {
842  if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
843  return;
844  }
845 
846  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
847  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
848  fsm->slave->error_flag = 1;
850  return;
851  }
852 
853  if (!fsm->slave->config) { // config removed in the meantime
855  return;
856  }
857 
858  // Another SDO to configure?
859  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
860  fsm->request = list_entry(fsm->request->list.next,
861  ec_sdo_request_t, list);
864  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
865  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
866  return;
867  }
868 
869  // All SDOs are now configured.
871 }
872 
873 /****************************************************************************/
874 
879  )
880 {
881  ec_slave_t *slave = fsm->slave;
882  ec_soe_request_t *req;
883 
884  if (!slave->config) {
886  return;
887  }
888 
889  list_for_each_entry(req, &slave->config->soe_configs, list) {
890  if (req->al_state == EC_AL_STATE_PREOP) {
891  // start SoE configuration
893  fsm->soe_request = req;
896  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
897  &fsm->soe_request_copy);
898  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
899  return;
900  }
901  }
902 
903  // No SoE configuration to be applied in PREOP
905 }
906 
907 /****************************************************************************/
908 
913  )
914 {
915  ec_slave_t *slave = fsm->slave;
916 
917  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
918  return;
919  }
920 
921  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
922  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
923  fsm->slave->error_flag = 1;
925  return;
926  }
927 
928  if (!fsm->slave->config) { // config removed in the meantime
930  return;
931  }
932 
933  // Another IDN to configure in PREOP?
934  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
935  fsm->soe_request = list_entry(fsm->soe_request->list.next,
936  ec_soe_request_t, list);
937  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
940  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
941  &fsm->soe_request_copy);
942  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
943  return;
944  }
945  }
946 
947  // All PREOP IDNs are now configured.
949 }
950 
951 /****************************************************************************/
952 
957  )
958 {
959  // Start configuring PDOs
962  fsm->state(fsm); // execute immediately
963 }
964 
965 /****************************************************************************/
966 
971  )
972 {
973  // TODO check for config here
974 
975  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
976  return;
977  }
978 
979  if (!fsm->slave->config) { // config removed in the meantime
981  return;
982  }
983 
984  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
985  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
986  }
987 
989 }
990 
991 /****************************************************************************/
992 
997  )
998 {
999  ec_slave_t *slave = fsm->slave;
1000  ec_datagram_t *datagram = fsm->datagram;
1001  ec_slave_config_t *config = slave->config;
1002 
1003  if (config && config->watchdog_divider) {
1004  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1005  config->watchdog_divider);
1006 
1007  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1008  EC_WRITE_U16(datagram->data, config->watchdog_divider);
1009  fsm->retries = EC_FSM_RETRIES;
1011  } else {
1013  }
1014 }
1015 
1016 /****************************************************************************/
1017 
1021  ec_fsm_slave_config_t *fsm
1022  )
1023 {
1024  ec_datagram_t *datagram = fsm->datagram;
1025  ec_slave_t *slave = fsm->slave;
1026 
1027  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1028  return;
1029 
1030  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1032  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1033  " configuration datagram: ");
1034  ec_datagram_print_state(datagram);
1035  return;
1036  }
1037 
1038  if (datagram->working_counter != 1) {
1039  slave->error_flag = 1;
1040  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1041  ec_datagram_print_wc_error(datagram);
1042  return;
1043  }
1044 
1046 }
1047 
1048 /****************************************************************************/
1049 
1053  ec_fsm_slave_config_t *fsm
1054  )
1055 {
1056  ec_datagram_t *datagram = fsm->datagram;
1057  ec_slave_t *slave = fsm->slave;
1058  ec_slave_config_t *config = slave->config;
1059 
1060  if (config && config->watchdog_intervals) {
1061  EC_SLAVE_DBG(slave, 1, "Setting process data"
1062  " watchdog intervals to %u.\n", config->watchdog_intervals);
1063 
1064  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1065  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1066 
1067  fsm->retries = EC_FSM_RETRIES;
1069  } else {
1071  }
1072 }
1073 
1074 /****************************************************************************/
1075 
1080  ec_fsm_slave_config_t *fsm
1081  )
1082 {
1083  ec_datagram_t *datagram = fsm->datagram;
1084  ec_slave_t *slave = fsm->slave;
1085 
1086  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1087  return;
1088 
1089  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1091  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1092  " watchdog configuration datagram: ");
1093  ec_datagram_print_state(datagram);
1094  return;
1095  }
1096 
1097  if (datagram->working_counter != 1) {
1098  EC_SLAVE_WARN(slave, "Failed to set process data"
1099  " watchdog intervals: ");
1100  ec_datagram_print_wc_error(datagram);
1101  }
1102 
1104 }
1105 
1106 /****************************************************************************/
1107 
1111  ec_fsm_slave_config_t *fsm
1112  )
1113 {
1114  ec_slave_t *slave = fsm->slave;
1115  ec_datagram_t *datagram = fsm->datagram;
1116  unsigned int i, j, offset, num_pdo_syncs;
1117  uint8_t sync_index;
1118  const ec_sync_t *sync;
1119  uint16_t size;
1120 
1121  if (slave->sii.mailbox_protocols) {
1122  offset = 2; // slave has mailboxes
1123  } else {
1124  offset = 0;
1125  }
1126 
1127  if (slave->sii.sync_count <= offset) {
1128  // no PDO sync managers to configure
1130  return;
1131  }
1132 
1133  num_pdo_syncs = slave->sii.sync_count - offset;
1134 
1135  // configure sync managers for process data
1136  ec_datagram_fpwr(datagram, slave->station_address,
1137  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1138  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1139  ec_datagram_zero(datagram);
1140 
1141  for (i = 0; i < num_pdo_syncs; i++) {
1142  const ec_sync_config_t *sync_config;
1143  uint8_t pdo_xfer = 0;
1144  sync_index = i + offset;
1145  sync = &slave->sii.syncs[sync_index];
1146 
1147  if (slave->config) {
1148  const ec_slave_config_t *sc = slave->config;
1149  sync_config = &sc->sync_configs[sync_index];
1150  size = ec_pdo_list_total_size(&sync_config->pdos);
1151 
1152  // determine, if PDOs shall be transferred via this SM
1153  // inthat case, enable sync manager in every case
1154  for (j = 0; j < sc->used_fmmus; j++) {
1155  if (sc->fmmu_configs[j].sync_index == sync_index) {
1156  pdo_xfer = 1;
1157  break;
1158  }
1159  }
1160 
1161  } else {
1162  sync_config = NULL;
1163  size = sync->default_length;
1164  }
1165 
1166  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1167  datagram->data + EC_SYNC_PAGE_SIZE * i);
1168  }
1169 
1170  fsm->retries = EC_FSM_RETRIES;
1172 }
1173 
1174 /****************************************************************************/
1175 
1179  ec_fsm_slave_config_t *fsm
1180  )
1181 {
1182  ec_datagram_t *datagram = fsm->datagram;
1183  ec_slave_t *slave = fsm->slave;
1184 
1185  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1186  return;
1187 
1188  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1190  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1191  " manager configuration datagram: ");
1192  ec_datagram_print_state(datagram);
1193  return;
1194  }
1195 
1196  if (datagram->working_counter != 1) {
1197  slave->error_flag = 1;
1199  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1200  ec_datagram_print_wc_error(datagram);
1201  return;
1202  }
1203 
1205 }
1206 
1207 /****************************************************************************/
1208 
1212  ec_fsm_slave_config_t *fsm
1213  )
1214 {
1215  ec_slave_t *slave = fsm->slave;
1216  ec_datagram_t *datagram = fsm->datagram;
1217  unsigned int i;
1218  const ec_fmmu_config_t *fmmu;
1219  const ec_sync_t *sync;
1220 
1221  if (!slave->config) {
1223  return;
1224  }
1225 
1226  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1227  slave->error_flag = 1;
1229  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1230  " than requested (%u).\n", slave->base_fmmu_count,
1231  slave->config->used_fmmus);
1232  return;
1233  }
1234 
1235  if (!slave->base_fmmu_count) { // skip FMMU configuration
1237  return;
1238  }
1239 
1240  // configure FMMUs
1241  ec_datagram_fpwr(datagram, slave->station_address,
1242  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1243  ec_datagram_zero(datagram);
1244  for (i = 0; i < slave->config->used_fmmus; i++) {
1245  fmmu = &slave->config->fmmu_configs[i];
1246  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1247  slave->error_flag = 1;
1249  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1250  " for FMMU!\n");
1251  return;
1252  }
1253  ec_fmmu_config_page(fmmu, sync,
1254  datagram->data + EC_FMMU_PAGE_SIZE * i);
1255  }
1256 
1257  fsm->retries = EC_FSM_RETRIES;
1259 }
1260 
1261 /****************************************************************************/
1262 
1266  ec_fsm_slave_config_t *fsm
1267  )
1268 {
1269  ec_datagram_t *datagram = fsm->datagram;
1270  ec_slave_t *slave = fsm->slave;
1271 
1272  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1273  return;
1274 
1275  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1277  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1278  ec_datagram_print_state(datagram);
1279  return;
1280  }
1281 
1282  if (datagram->working_counter != 1) {
1283  slave->error_flag = 1;
1285  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1286  ec_datagram_print_wc_error(datagram);
1287  return;
1288  }
1289 
1291 }
1292 
1293 /****************************************************************************/
1294 
1298  ec_fsm_slave_config_t *fsm
1299  )
1300 {
1301  ec_datagram_t *datagram = fsm->datagram;
1302  ec_slave_t *slave = fsm->slave;
1303  ec_slave_config_t *config = slave->config;
1304 
1305  if (!config) { // config removed in the meantime
1307  return;
1308  }
1309 
1310  if (config->dc_assign_activate) {
1311  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1312  EC_SLAVE_WARN(slave, "Slave seems not to support"
1313  " distributed clocks!\n");
1314  }
1315 
1316  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1317  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1318 
1319  // set DC cycle times
1320  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1321  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1322  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1323  fsm->retries = EC_FSM_RETRIES;
1325  } else {
1326  // DC are unused
1328  }
1329 }
1330 
1331 /****************************************************************************/
1332 
1336  ec_fsm_slave_config_t *fsm
1337  )
1338 {
1339  ec_datagram_t *datagram = fsm->datagram;
1340  ec_slave_t *slave = fsm->slave;
1341  ec_slave_config_t *config = slave->config;
1342 
1343  if (!config) { // config removed in the meantime
1345  return;
1346  }
1347 
1348  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1349  return;
1350 
1351  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1353  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1354  ec_datagram_print_state(datagram);
1355  return;
1356  }
1357 
1358  if (datagram->working_counter != 1) {
1359  slave->error_flag = 1;
1361  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1362  ec_datagram_print_wc_error(datagram);
1363  return;
1364  }
1365 
1366  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1367 
1368  fsm->jiffies_start = jiffies;
1369  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1370  fsm->retries = EC_FSM_RETRIES;
1372 }
1373 
1374 /****************************************************************************/
1375 
1379  ec_fsm_slave_config_t *fsm
1380  )
1381 {
1382  ec_datagram_t *datagram = fsm->datagram;
1383  ec_slave_t *slave = fsm->slave;
1384  ec_master_t *master = slave->master;
1385  ec_slave_config_t *config = slave->config;
1386  uint32_t abs_sync_diff;
1387  unsigned long diff_ms;
1388  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1389  ec_sync_signal_t *sync1 = &config->dc_sync[1];
1390  u64 start_time;
1391 
1392  if (!config) { // config removed in the meantime
1394  return;
1395  }
1396 
1397  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1398  return;
1399 
1400  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1402  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1403  ec_datagram_print_state(datagram);
1404  return;
1405  }
1406 
1407  if (datagram->working_counter != 1) {
1408  slave->error_flag = 1;
1410  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1411  ec_datagram_print_wc_error(datagram);
1412  return;
1413  }
1414 
1415  abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1416  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1417 
1418  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1419 
1420  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1421  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1422  diff_ms);
1423  } else {
1424  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1425  diff_ms, abs_sync_diff);
1426 
1427  // check synchrony again
1428  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1429  fsm->retries = EC_FSM_RETRIES;
1430  return;
1431  }
1432  } else {
1433  EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1434  abs_sync_diff, diff_ms);
1435  }
1436 
1437  // set DC start time (roughly in the future, not in-phase)
1438  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1439 
1440  if (sync0->cycle_time) {
1441  // find correct phase
1442  if (master->dc_ref_time) {
1443  u64 diff, start;
1444  u32 remainder, cycle;
1445 
1446  diff = start_time - master->dc_ref_time;
1447  cycle = sync0->cycle_time + sync1->cycle_time;
1448  remainder = do_div(diff, cycle);
1449 
1450  start = start_time + cycle - remainder + sync0->shift_time;
1451 
1452  EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1453  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1454  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1455  EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1456  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1457  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1458  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1459  start_time = start;
1460  } else {
1461  EC_SLAVE_WARN(slave, "No application time supplied."
1462  " Cyclic start time will not be in phase.\n");
1463  }
1464  }
1465 
1466  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1467  " start time to %llu.\n", start_time);
1468 
1469  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1470  EC_WRITE_U64(datagram->data, start_time);
1471  fsm->retries = EC_FSM_RETRIES;
1473 }
1474 
1475 /****************************************************************************/
1476 
1480  ec_fsm_slave_config_t *fsm
1481  )
1482 {
1483  ec_datagram_t *datagram = fsm->datagram;
1484  ec_slave_t *slave = fsm->slave;
1485  ec_slave_config_t *config = slave->config;
1486 
1487  if (!config) { // config removed in the meantime
1489  return;
1490  }
1491 
1492  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1493  return;
1494 
1495  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1497  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1498  ec_datagram_print_state(datagram);
1499  return;
1500  }
1501 
1502  if (datagram->working_counter != 1) {
1503  slave->error_flag = 1;
1505  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1506  ec_datagram_print_wc_error(datagram);
1507  return;
1508  }
1509 
1510  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1511  config->dc_assign_activate);
1512 
1513  // assign sync unit to EtherCAT or PDI
1514  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1515  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1516  fsm->retries = EC_FSM_RETRIES;
1518 }
1519 
1520 /****************************************************************************/
1521 
1525  ec_fsm_slave_config_t *fsm
1526  )
1527 {
1528  ec_datagram_t *datagram = fsm->datagram;
1529  ec_slave_t *slave = fsm->slave;
1530 
1531  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1532  return;
1533 
1534  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1536  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1537  ec_datagram_print_state(datagram);
1538  return;
1539  }
1540 
1541  if (datagram->working_counter != 1) {
1542  slave->error_flag = 1;
1544  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1545  ec_datagram_print_wc_error(datagram);
1546  return;
1547  }
1548 
1550 }
1551 
1552 /****************************************************************************/
1553 
1561  ec_fsm_slave_config_t *fsm
1562  )
1563 {
1564  ec_slave_config_t *config = fsm->slave->config;
1565  fsm->wait_ms = 0UL;
1566  if (config) {
1567  ec_flag_t *flag = ec_slave_config_find_flag(config,
1568  "WaitBeforeSAFEOPms");
1569  if (flag && flag->value > 0) {
1570  fsm->wait_ms = (unsigned long) flag->value;
1571  }
1572  }
1573 
1574  if (fsm->wait_ms > 0) {
1576 
1577  /* dummy read */
1579  0x0600, 1);
1580 
1581  fsm->jiffies_start = jiffies;
1582  }
1583  else {
1585  }
1586 }
1587 
1588 /****************************************************************************/
1589 
1593  ec_fsm_slave_config_t *fsm
1594  )
1595 {
1596  unsigned long diff = jiffies - fsm->jiffies_start;
1597 
1598  if (diff * 1000 / HZ < fsm->wait_ms) {
1599  return;
1600  }
1601 
1603 }
1604 
1605 /****************************************************************************/
1606 
1610  ec_fsm_slave_config_t *fsm
1611  )
1612 {
1615  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1616 }
1617 
1618 /****************************************************************************/
1619 
1623  ec_fsm_slave_config_t *fsm
1624  )
1625 {
1626  ec_slave_t *slave = fsm->slave;
1627 
1628  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1629 
1630  if (!ec_fsm_change_success(fsm->fsm_change)) {
1631  if (!fsm->fsm_change->spontaneous_change)
1632  fsm->slave->error_flag = 1;
1634  return;
1635  }
1636 
1637  // slave is now in SAFEOP
1638 
1639  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1640 
1641  if (fsm->slave->current_state == fsm->slave->requested_state) {
1642  fsm->state = ec_fsm_slave_config_state_end; // successful
1643  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1644  return;
1645  }
1646 
1648 }
1649 
1650 /****************************************************************************/
1651 
1655  ec_fsm_slave_config_t *fsm
1656  )
1657 {
1658  ec_slave_t *slave = fsm->slave;
1659  ec_soe_request_t *req;
1660 
1661  if (!slave->config) {
1663  return;
1664  }
1665 
1666  list_for_each_entry(req, &slave->config->soe_configs, list) {
1667  if (req->al_state == EC_AL_STATE_SAFEOP) {
1668  // start SoE configuration
1670  fsm->soe_request = req;
1673  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1674  &fsm->soe_request_copy);
1675  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1676  return;
1677  }
1678  }
1679 
1680  // No SoE configuration to be applied in SAFEOP
1682 }
1683 
1684 /****************************************************************************/
1685 
1689  ec_fsm_slave_config_t *fsm
1690  )
1691 {
1692  ec_slave_t *slave = fsm->slave;
1693 
1694  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1695  return;
1696  }
1697 
1698  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1699  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1700  fsm->slave->error_flag = 1;
1702  return;
1703  }
1704 
1705  if (!fsm->slave->config) { // config removed in the meantime
1707  return;
1708  }
1709 
1710  // Another IDN to configure in SAFEOP?
1711  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1712  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1713  ec_soe_request_t, list);
1714  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1717  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1718  &fsm->soe_request_copy);
1719  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1720  return;
1721  }
1722  }
1723 
1724  // All SAFEOP IDNs are now configured.
1726 }
1727 
1728 /****************************************************************************/
1729 
1733  ec_fsm_slave_config_t *fsm
1734  )
1735 {
1736  // set state to OP
1739  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1740 }
1741 
1742 /****************************************************************************/
1743 
1747  ec_fsm_slave_config_t *fsm
1748  )
1749 {
1750  ec_slave_t *slave = fsm->slave;
1751 
1752  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1753 
1754  if (!ec_fsm_change_success(fsm->fsm_change)) {
1755  if (!fsm->fsm_change->spontaneous_change)
1756  slave->error_flag = 1;
1758  return;
1759  }
1760 
1761  // slave is now in OP
1762 
1763  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1764 
1765  fsm->state = ec_fsm_slave_config_state_end; // successful
1766 }
1767 
1768 /****************************************************************************/
1769 
1773  ec_fsm_slave_config_t *fsm
1774  )
1775 {
1776  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1777  "configuration. Reconfiguring.");
1778 
1779  ec_fsm_slave_config_enter_init(fsm); // reconfigure
1780 }
1781 
1782 /*****************************************************************************
1783  * Common state functions
1784  ****************************************************************************/
1785 
1789  ec_fsm_slave_config_t *fsm
1790  )
1791 {
1792 }
1793 
1794 /****************************************************************************/
1795 
1799  ec_fsm_slave_config_t *fsm
1800  )
1801 {
1802 }
1803 
1804 /****************************************************************************/
#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:43
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:96
Pre-operational.
Definition: ecrt.h:614
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:136
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:131
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:89
ec_sii_t sii
Extracted SII data.
Definition: slave.h:215
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:156
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.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:193
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:98
void ec_fsm_pdo_start_configuration(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start writing the PDO configuration.
Definition: fsm_pdo.c:124
int32_t shift_time
Shift time [ns].
Definition: globals.h:182
OP (mailbox communication and input/output update)
Definition: globals.h:132
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:191
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:184
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:132
Safe-operational.
Definition: ecrt.h:615
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:82
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:79
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2699
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:224
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:128
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:181
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:85
uint16_t working_counter
Working counter.
Definition: datagram.h:91
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:254
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:134
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:176
int ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
Definition: soe_request.c:241
unsigned int sync_count
Number of sync managers.
Definition: slave.h:158
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:136
void ec_fsm_slave_config_init(ec_fsm_slave_config_t *fsm, ec_datagram_t *datagram, ec_fsm_change_t *fsm_change, ec_fsm_coe_t *fsm_coe, ec_fsm_soe_t *fsm_soe, ec_fsm_pdo_t *fsm_pdo)
Constructor.
void ec_sync_page(const ec_sync_t *sync, uint8_t sync_index, uint16_t data_size, const ec_sync_config_t *sync_config, uint8_t pdo_xfer, uint8_t *data)
Initializes a sync manager configuration page.
Definition: sync.c:86
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:137
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:131
SAFEOP (mailbox communication and input update)
Definition: globals.h:130
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:134
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:133
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_PDI.
EtherCAT slave.
Definition: slave.h:168
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:170
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:122
int ec_fsm_soe_success(const ec_fsm_soe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_soe.c:179
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:129
ec_datagram_state_t state
State.
Definition: datagram.h:92
ec_slave_config_t * config
Current configuration.
Definition: slave.h:182
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2733
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:139
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
Definition: slave_config.c:602
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *)
State: END.
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm)
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:68
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:594
#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:135
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:119
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
int ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:232
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:133
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:2716
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:199
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:187
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:2627
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:170
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:290
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:204
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:265
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_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:141
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
unsigned int take_time
Store jiffies after datagram reception.
INIT state (no mailbox communication, no IO)
Definition: globals.h:124
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:172
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:557
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:502
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:2750
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:132
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:180
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:220
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:223
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:219
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:189
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:202
uint8_t * data
Datagram payload.
Definition: datagram.h:86
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:200
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:144
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:197
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:126
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:185
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
EtherCAT master.
Definition: master.h:183
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:183
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:95
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c: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:100
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:134
unsigned long jiffies_start
For timeout calculations.
Finite state machines for the CANopen over EtherCAT protocol.
Definition: fsm_coe.h:44
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:594
unsigned int retries
Retries on datagram timeout.