IgH EtherCAT Master  1.5.2
fsm_slave_config.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
6  *
7  * This file is part of the IgH EtherCAT Master.
8  *
9  * The IgH EtherCAT Master is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version 2, as
11  * published by the Free Software Foundation.
12  *
13  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with the IgH EtherCAT Master; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * ---
23  *
24  * The license mentioned above concerns the source code only. Using the
25  * EtherCAT technology and brand is only permitted in compliance with the
26  * industrial property and similar rights of Beckhoff Automation GmbH.
27  *
28  *****************************************************************************/
29 
35 /*****************************************************************************/
36 
37 #include <asm/div64.h>
38 
39 #include "globals.h"
40 #include "master.h"
41 #include "mailbox.h"
42 #include "slave_config.h"
43 #include "fsm_slave_config.h"
44 
45 /*****************************************************************************/
46 
52 #define EC_DC_MAX_SYNC_DIFF_NS 10000
53 
56 #define EC_DC_SYNC_WAIT_MS 5000
57 
60 #define EC_DC_START_OFFSET 100000000ULL
61 
62 /*****************************************************************************/
63 
71 #ifdef EC_SII_ASSIGN
73 #endif
75 #ifdef EC_SII_ASSIGN
77 #endif
92 
97 #ifdef EC_SII_ASSIGN
99 #endif
112 
115 
117 
118 /*****************************************************************************/
119 
123  ec_fsm_slave_config_t *fsm,
124  ec_slave_t *slave,
125  ec_fsm_change_t *fsm_change,
126  ec_fsm_coe_t *fsm_coe,
127  ec_fsm_soe_t *fsm_soe,
128  ec_fsm_pdo_t *fsm_pdo
129  )
130 {
133 
134  fsm->slave = slave;
135  fsm->datagram = NULL;
136  fsm->fsm_change = fsm_change;
137  fsm->fsm_coe = fsm_coe;
138  fsm->fsm_soe = fsm_soe;
139  fsm->fsm_pdo = fsm_pdo;
140 }
141 
142 /*****************************************************************************/
143 
148  )
149 {
152 }
153 
154 /*****************************************************************************/
155 
160  )
161 {
163 }
164 
165 /*****************************************************************************/
166 
171  )
172 {
174 }
175 
176 /*****************************************************************************/
177 
182  const ec_fsm_slave_config_t *fsm
183  )
184 {
185  return fsm->state != ec_fsm_slave_config_state_end
187 }
188 
189 /*****************************************************************************/
190 
199  ec_fsm_slave_config_t *fsm,
200  ec_datagram_t *datagram
201  )
202 {
203  if (!ec_fsm_slave_config_running(fsm))
204  return 0;
205 
206  fsm->state(fsm, datagram);
207 
208  if (!ec_fsm_slave_config_running(fsm)) {
209  fsm->datagram = NULL;
210  return 0;
211  }
212 
213  fsm->datagram = datagram;
214  return 1;
215 }
216 
217 /*****************************************************************************/
218 
223  const ec_fsm_slave_config_t *fsm
224  )
225 {
226  return fsm->state == ec_fsm_slave_config_state_end;
227 }
228 
229 /******************************************************************************
230  * Slave configuration state machine
231  *****************************************************************************/
232 
236  ec_fsm_slave_config_t *fsm,
237  ec_datagram_t *datagram
238  )
239 {
240  EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
241  ec_fsm_slave_config_enter_init(fsm, datagram);
242 }
243 
244 /*****************************************************************************/
245 
249  ec_fsm_slave_config_t *fsm,
250  ec_datagram_t *datagram
251  )
252 {
253  EC_SLAVE_DBG(fsm->slave, 1, "Configuring (quick)...\n");
255 }
256 
257 /*****************************************************************************/
258 
262  ec_fsm_slave_config_t *fsm,
263  ec_datagram_t *datagram
264  )
265 {
267  ec_fsm_change_exec(fsm->fsm_change, datagram);
269 }
270 
271 /*****************************************************************************/
272 
276  ec_fsm_slave_config_t *fsm,
277  ec_datagram_t *datagram
278  )
279 {
280  ec_slave_t *slave = fsm->slave;
281 
282  if (ec_fsm_change_exec(fsm->fsm_change, datagram)) return;
283 
284  if (!ec_fsm_change_success(fsm->fsm_change)) {
285  if (!fsm->fsm_change->spontaneous_change)
286  slave->error_flag = 1;
288  return;
289  }
290 
291  EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
292 
293  if (!slave->base_fmmu_count) { // skip FMMU configuration
295  return;
296  }
297 
298  EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
299 
300  // clear FMMU configurations
301  ec_datagram_fpwr(datagram, slave->station_address,
302  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
303  ec_datagram_zero(datagram);
304  fsm->retries = EC_FSM_RETRIES;
306 
307  EC_SLAVE_DBG(slave, 1, "Clearing mailbox check flag...\n");
308 
310 }
311 
312 /*****************************************************************************/
313 
317  ec_fsm_slave_config_t *fsm,
318  ec_datagram_t *datagram
319  )
320 {
321  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
322  ec_datagram_repeat(datagram, fsm->datagram);
323  return;
324  }
325 
326  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
328  EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
329  return;
330  }
331 
332  if (fsm->datagram->working_counter != 1) {
333  fsm->slave->error_flag = 1;
335  EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
337  return;
338  }
339 
341 }
342 
343 /*****************************************************************************/
344 
348  ec_fsm_slave_config_t *fsm,
349  ec_datagram_t *datagram
350  )
351 {
352  ec_slave_t *slave = fsm->slave;
353  size_t sync_size;
354 
355  if (!slave->base_sync_count) {
356  // no sync managers
358  return;
359  }
360 
361  EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
362 
363  sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
364 
365  // clear sync manager configurations
366  ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
367  ec_datagram_zero(datagram);
368  fsm->retries = EC_FSM_RETRIES;
370 }
371 
372 /*****************************************************************************/
373 
377  ec_fsm_slave_config_t *fsm,
378  ec_datagram_t *datagram
379  )
380 {
381  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
382  ec_datagram_repeat(datagram, fsm->datagram);
383  return;
384  }
385 
386  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
388  EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
389  " clearing datagram.\n");
390  return;
391  }
392 
393  if (fsm->datagram->working_counter != 1) {
394  fsm->slave->error_flag = 1;
396  EC_SLAVE_ERR(fsm->slave,
397  "Failed to clear sync manager configurations: ");
399  return;
400  }
401 
403 }
404 
405 /*****************************************************************************/
406 
410  ec_fsm_slave_config_t *fsm,
411  ec_datagram_t *datagram
412  )
413 {
414  ec_slave_t *slave = fsm->slave;
415 
416  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
418  return;
419  }
420 
421  EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
422 
423  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
424  ec_datagram_zero(datagram);
425  fsm->retries = EC_FSM_RETRIES;
427 }
428 
429 /*****************************************************************************/
430 
434  ec_fsm_slave_config_t *fsm,
435  ec_datagram_t *datagram
436  )
437 {
438  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
439  ec_datagram_repeat(datagram, fsm->datagram);
440  return;
441  }
442 
443  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
445  EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
446  " clearing datagram.\n");
447  return;
448  }
449 
450  if (fsm->datagram->working_counter != 1) {
451  // clearing the DC assignment does not succeed on simple slaves
452  EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
454  }
455 
457 }
458 
459 /*****************************************************************************/
460 
464  ec_fsm_slave_config_t *fsm,
465  ec_datagram_t *datagram
466  )
467 {
468  ec_slave_t *slave = fsm->slave;
469  unsigned int i;
470 
471  // slave is now in INIT
472  if (fsm->slave->current_state == slave->requested_state) {
473  fsm->state = ec_fsm_slave_config_state_end; // successful
474  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
475  return;
476  }
477 
478  if (!slave->sii_image) {
480  EC_SLAVE_ERR(slave, "Slave cannot configure SyncManager."
481  " SII data not available.\n");
482  return;
483  }
484 
485  if (!slave->sii_image->sii.mailbox_protocols) {
486  // no mailbox protocols supported
487  EC_SLAVE_DBG(slave, 1, "Slave does not support"
488  " mailbox communication.\n");
489 #ifdef EC_SII_ASSIGN
491 #else
493 #endif
494  return;
495  }
496 
497  EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
498 
499  if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
500  ec_sync_t sync;
501 
502  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
503  EC_SYNC_PAGE_SIZE * 2);
504  ec_datagram_zero(datagram);
505 
506  ec_sync_init(&sync, slave);
508  sync.control_register = 0x26;
509  sync.enable = 1;
511  EC_DIR_INVALID, // use default direction
512  0, // no PDO xfer
513  datagram->data);
518 
519  ec_sync_init(&sync, slave);
521  sync.control_register = 0x22;
522  sync.enable = 1;
524  EC_DIR_INVALID, // use default direction
525  0, // no PDO xfer
526  datagram->data + EC_SYNC_PAGE_SIZE);
531 
532  } else if (slave->sii_image->sii.sync_count >= 2) { // mailbox configuration provided
533  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
535  ec_datagram_zero(datagram);
536 
537  if (slave->sii_image->sii.syncs) {
538  for (i = 0; i < 2; i++) {
539  ec_sync_page(&slave->sii_image->sii.syncs[i], i,
540  slave->sii_image->sii.syncs[i].default_length,
541  NULL, // use default sync manager configuration
542  0, // no PDO xfer
543  datagram->data + EC_SYNC_PAGE_SIZE * i);
544  }
545 
549  slave->sii_image->sii.syncs[0].default_length;
553  slave->sii_image->sii.syncs[1].default_length;
554  }
555  else {
556  EC_SLAVE_ERR(slave, "Slave has no SyncManager\n");
557  }
558  } else { // no mailbox sync manager configurations provided
559  ec_sync_t sync;
560 
561  EC_SLAVE_DBG(slave, 1, "Slave does not provide"
562  " mailbox sync manager configurations.\n");
563 
564  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
565  EC_SYNC_PAGE_SIZE * 2);
566  ec_datagram_zero(datagram);
567 
568  ec_sync_init(&sync, slave);
570  sync.control_register = 0x26;
571  sync.enable = 1;
572  ec_sync_page(&sync, 0, slave->sii_image->sii.std_rx_mailbox_size,
573  NULL, // use default sync manager configuration
574  0, // no PDO xfer
575  datagram->data);
580 
581  ec_sync_init(&sync, slave);
583  sync.control_register = 0x22;
584  sync.enable = 1;
585  ec_sync_page(&sync, 1, slave->sii_image->sii.std_tx_mailbox_size,
586  NULL, // use default sync manager configuration
587  0, // no PDO xfer
588  datagram->data + EC_SYNC_PAGE_SIZE);
593  }
594 
595  // allocate memory for mailbox response data for supported mailbox protocols
597 
598  fsm->take_time = 1;
599 
600  fsm->retries = EC_FSM_RETRIES;
602 }
603 
604 /*****************************************************************************/
605 
611  ec_fsm_slave_config_t *fsm,
612  ec_datagram_t *datagram
613  )
614 {
615  ec_slave_t *slave = fsm->slave;
616 
617  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
618  ec_datagram_repeat(datagram, fsm->datagram);
619  return;
620  }
621 
622  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
624  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
625  " configuration datagram: ");
627  return;
628  }
629 
630  if (fsm->take_time) {
631  fsm->take_time = 0;
632  fsm->jiffies_start = fsm->datagram->jiffies_sent;
633  }
634 
635  /* Because the sync manager configurations are cleared during the last
636  * cycle, some slaves do not immediately respond to the mailbox sync
637  * manager configuration datagram. Therefore, resend the datagram for
638  * a certain time, if the slave does not respond.
639  */
640  if (fsm->datagram->working_counter == 0) {
641  unsigned long diff = fsm->datagram->jiffies_received - fsm->jiffies_start;
642 
643  if (diff >= HZ) {
644  slave->error_flag = 1;
646  EC_SLAVE_ERR(slave, "Timeout while configuring"
647  " mailbox sync managers.\n");
648  return;
649  } else {
650  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
651  (unsigned int) diff * 1000 / HZ);
652  }
653 
654  // send configuration datagram again
655  ec_datagram_repeat(datagram, fsm->datagram);
656  fsm->retries = EC_FSM_RETRIES;
657  return;
658  }
659  else if (fsm->datagram->working_counter != 1) {
660  slave->error_flag = 1;
662  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
664  return;
665  }
666 
667 #ifdef EC_SII_ASSIGN
669 #else
671 #endif
672 }
673 
674 /*****************************************************************************/
675 
676 #ifdef EC_SII_ASSIGN
677 
681  ec_fsm_slave_config_t *fsm,
682  ec_datagram_t *datagram
683  )
684 {
685  ec_slave_t *slave = fsm->slave;
686 
688  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
689 
690  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
691  EC_WRITE_U8(datagram->data, 0x01); // PDI
692  fsm->retries = EC_FSM_RETRIES;
694  }
695  else {
697  }
698 }
699 
700 /*****************************************************************************/
701 
705  ec_fsm_slave_config_t *fsm,
706  ec_datagram_t *datagram
707  )
708 {
709  ec_slave_t *slave = fsm->slave;
710 
711  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
712  ec_datagram_repeat(datagram, fsm->datagram);
713  return;
714  }
715 
716  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
717  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
719  goto cont_preop;
720  }
721 
722  if (fsm->datagram->working_counter != 1) {
723  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
725  }
726 
727 cont_preop:
729 }
730 
731 #endif
732 
733 /*****************************************************************************/
734 
738  ec_fsm_slave_config_t *fsm,
739  ec_datagram_t *datagram
740  )
741 {
743 
747  } else { // BOOT
749  fsm->slave, EC_SLAVE_STATE_BOOT);
750  }
751 
752  ec_fsm_change_exec(fsm->fsm_change, datagram); // execute immediately
753 }
754 
755 /*****************************************************************************/
756 
760  ec_fsm_slave_config_t *fsm,
761  ec_datagram_t *datagram
762  )
763 {
764  ec_slave_t *slave = fsm->slave;
765 
766  if (ec_fsm_change_exec(fsm->fsm_change, datagram)) {
767  return;
768  }
769 
770  if (!ec_fsm_change_success(fsm->fsm_change)) {
771  if (!fsm->fsm_change->spontaneous_change)
772  slave->error_flag = 1;
774  return;
775  }
776 
777  // slave is now in BOOT or PREOP
778  slave->jiffies_preop = fsm->datagram->jiffies_received;
779 
780  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
781  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
782 
783 #ifdef EC_SII_ASSIGN
784  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
785 
786  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
787  EC_WRITE_U8(datagram->data, 0x00); // EtherCAT
788  fsm->retries = EC_FSM_RETRIES;
790 #else
791  if (slave->current_state == slave->requested_state) {
792  fsm->state = ec_fsm_slave_config_state_end; // successful
793  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
794  return;
795  }
796 
797  ec_fsm_slave_config_enter_sdo_conf(fsm, datagram);
798 #endif
799 }
800 
801 /*****************************************************************************/
802 
803 #ifdef EC_SII_ASSIGN
804 
808  ec_fsm_slave_config_t *fsm,
809  ec_datagram_t *datagram
810  )
811 {
812  ec_slave_t *slave = fsm->slave;
813 
814  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
815  ec_datagram_repeat(datagram, fsm->datagram);
816  return;
817  }
818 
819  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
820  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
822  goto cont_sdo_conf;
823  }
824 
825  if (fsm->datagram->working_counter != 1) {
826  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
828  }
829 
830 cont_sdo_conf:
831  if (slave->current_state == slave->requested_state) {
832  fsm->state = ec_fsm_slave_config_state_end; // successful
833  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
834  return;
835  }
836 
837  ec_fsm_slave_config_enter_sdo_conf(fsm, datagram);
838 }
839 
840 #endif
841 
842 /*****************************************************************************/
843 
847  ec_fsm_slave_config_t *fsm,
848  ec_datagram_t *datagram
849  )
850 {
851  ec_slave_t *slave = fsm->slave;
852 
853  if (!slave->config) {
854  ec_fsm_slave_config_enter_pdo_sync(fsm, datagram);
855  return;
856  }
857 
858  // No CoE configuration to be applied?
859  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
861  return;
862  }
863 
864  // start SDO configuration
866  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
867  ec_sdo_request_t, list);
870  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
871  ec_fsm_coe_exec(fsm->fsm_coe, datagram); // execute immediately
872 }
873 
874 /*****************************************************************************/
875 
879  ec_fsm_slave_config_t *fsm,
880  ec_datagram_t *datagram
881  )
882 {
883  if (ec_fsm_coe_exec(fsm->fsm_coe, datagram)) {
884  return;
885  }
886 
887  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
888  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
889  fsm->slave->error_flag = 1;
891  return;
892  }
893 
894  if (!fsm->slave->config) { // config removed in the meantime
895  ec_fsm_slave_config_reconfigure(fsm, datagram);
896  return;
897  }
898 
899  // Another SDO to configure?
900  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
901  fsm->request = list_entry(fsm->request->list.next,
902  ec_sdo_request_t, list);
905  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
906  ec_fsm_coe_exec(fsm->fsm_coe, datagram); // execute immediately
907  return;
908  }
909 
910  // All SDOs are now configured.
912 }
913 
914 /*****************************************************************************/
915 
919  ec_fsm_slave_config_t *fsm,
920  ec_datagram_t *datagram
921  )
922 {
923  ec_slave_t *slave = fsm->slave;
924  ec_soe_request_t *req;
925 
926  if (!slave->config) {
927  ec_fsm_slave_config_enter_pdo_sync(fsm, datagram);
928  return;
929  }
930 
931  list_for_each_entry(req, &slave->config->soe_configs, list) {
932  if (req->al_state == EC_AL_STATE_PREOP) {
933  // start SoE configuration
935  fsm->soe_request = req;
938  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
939  &fsm->soe_request_copy);
940  ec_fsm_soe_exec(fsm->fsm_soe, datagram);
941  return;
942  }
943  }
944 
945  // No SoE configuration to be applied in PREOP
946  ec_fsm_slave_config_enter_pdo_conf(fsm, datagram);
947 }
948 
949 /*****************************************************************************/
950 
954  ec_fsm_slave_config_t *fsm,
955  ec_datagram_t *datagram
956  )
957 {
958  ec_slave_t *slave = fsm->slave;
959 
960  if (ec_fsm_soe_exec(fsm->fsm_soe, datagram)) {
961  return;
962  }
963 
964  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
965  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
966  fsm->slave->error_flag = 1;
968  return;
969  }
970 
971  if (!fsm->slave->config) { // config removed in the meantime
972  ec_fsm_slave_config_reconfigure(fsm, datagram);
973  return;
974  }
975 
976  // Another IDN to configure in PREOP?
977  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
978  fsm->soe_request = list_entry(fsm->soe_request->list.next,
979  ec_soe_request_t, list);
980  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
983  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
984  &fsm->soe_request_copy);
985  ec_fsm_soe_exec(fsm->fsm_soe, datagram);
986  return;
987  }
988  }
989 
990  // All PREOP IDNs are now configured.
991  ec_fsm_slave_config_enter_pdo_conf(fsm, datagram);
992 }
993 
994 /*****************************************************************************/
995 
999  ec_fsm_slave_config_t *fsm,
1000  ec_datagram_t *datagram
1001  )
1002 {
1003  // Start configuring PDOs
1006  fsm->state(fsm, datagram); // execute immediately
1007 }
1008 
1009 /*****************************************************************************/
1010 
1014  ec_fsm_slave_config_t *fsm,
1015  ec_datagram_t *datagram
1016  )
1017 {
1018  // TODO check for config here
1019 
1020  if (ec_fsm_pdo_exec(fsm->fsm_pdo, datagram)) {
1021  return;
1022  }
1023 
1024  if (!fsm->slave->config) { // config removed in the meantime
1025  ec_fsm_slave_config_reconfigure(fsm, datagram);
1026  return;
1027  }
1028 
1029  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
1030  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
1031  }
1032 
1034 }
1035 
1036 /*****************************************************************************/
1037 
1041  ec_fsm_slave_config_t *fsm,
1042  ec_datagram_t *datagram
1043  )
1044 {
1045  ec_slave_t *slave = fsm->slave;
1046  ec_slave_config_t *config = slave->config;
1047 
1048  if (config && config->watchdog_divider) {
1049  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1050  config->watchdog_divider);
1051 
1052  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1053  EC_WRITE_U16(datagram->data, config->watchdog_divider);
1054  fsm->retries = EC_FSM_RETRIES;
1056  } else {
1057  ec_fsm_slave_config_enter_watchdog(fsm, datagram);
1058  }
1059 }
1060 
1061 /*****************************************************************************/
1062 
1066  ec_fsm_slave_config_t *fsm,
1067  ec_datagram_t *datagram
1068  )
1069 {
1070  ec_slave_t *slave = fsm->slave;
1071 
1072  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1073  ec_datagram_repeat(datagram, fsm->datagram);
1074  return;
1075  }
1076 
1077  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1079  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1080  " configuration datagram: ");
1082  return;
1083  }
1084 
1085  if (fsm->datagram->working_counter != 1) {
1086  slave->error_flag = 1;
1087  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1089  return;
1090  }
1091 
1092  ec_fsm_slave_config_enter_watchdog(fsm, datagram);
1093 }
1094 
1095 /*****************************************************************************/
1096 
1100  ec_fsm_slave_config_t *fsm,
1101  ec_datagram_t *datagram
1102  )
1103 {
1104  ec_slave_t *slave = fsm->slave;
1105  ec_slave_config_t *config = slave->config;
1106 
1107  if (config && config->watchdog_intervals) {
1108  EC_SLAVE_DBG(slave, 1, "Setting process data"
1109  " watchdog intervals to %u.\n", config->watchdog_intervals);
1110 
1111  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1112  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1113 
1114  fsm->retries = EC_FSM_RETRIES;
1116  } else {
1117  ec_fsm_slave_config_enter_pdo_sync(fsm, datagram);
1118  }
1119 }
1120 
1121 /*****************************************************************************/
1122 
1127  ec_fsm_slave_config_t *fsm,
1128  ec_datagram_t *datagram
1129  )
1130 {
1131  ec_slave_t *slave = fsm->slave;
1132 
1133  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1134  ec_datagram_repeat(datagram, fsm->datagram);
1135  return;
1136  }
1137 
1138  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1140  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1141  " watchdog configuration datagram: ");
1143  return;
1144  }
1145 
1146  if (fsm->datagram->working_counter != 1) {
1147  EC_SLAVE_WARN(slave, "Failed to set process data"
1148  " watchdog intervals: ");
1150  }
1151 
1152  ec_fsm_slave_config_enter_pdo_sync(fsm, datagram);
1153 }
1154 
1155 /*****************************************************************************/
1156 
1160  ec_fsm_slave_config_t *fsm,
1161  ec_datagram_t *datagram
1162  )
1163 {
1164  ec_slave_t *slave = fsm->slave;
1165  unsigned int i, j, offset, num_pdo_syncs;
1166  uint8_t sync_index;
1167  const ec_sync_t *sync;
1168  uint16_t size;
1169 
1170  if (!slave->sii_image) {
1172  EC_SLAVE_ERR(slave, "Slave cannot configure PDO SyncManager."
1173  " SII data not available.\n");
1174  return;
1175  }
1176 
1177  if (slave->sii_image->sii.mailbox_protocols) {
1178  offset = 2; // slave has mailboxes
1179  } else {
1180  offset = 0;
1181  }
1182 
1183  if (slave->sii_image->sii.sync_count <= offset) {
1184  // no PDO sync managers to configure
1185  ec_fsm_slave_config_enter_fmmu(fsm, datagram);
1186  return;
1187  }
1188 
1189  num_pdo_syncs = slave->sii_image->sii.sync_count - offset;
1190 
1191  // configure sync managers for process data
1192  ec_datagram_fpwr(datagram, slave->station_address,
1193  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1194  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1195  ec_datagram_zero(datagram);
1196 
1197  for (i = 0; i < num_pdo_syncs; i++) {
1198  const ec_sync_config_t *sync_config;
1199  uint8_t pdo_xfer = 0;
1200  sync_index = i + offset;
1201  sync = &slave->sii_image->sii.syncs[sync_index];
1202 
1203  if (slave->config) {
1204  const ec_slave_config_t *sc = slave->config;
1205  sync_config = &sc->sync_configs[sync_index];
1206  size = ec_pdo_list_total_size(&sync_config->pdos);
1207 
1208  // determine, if PDOs shall be transferred via this SM
1209  // in that case, enable sync manager in every case
1210  for (j = 0; j < sc->used_fmmus; j++) {
1211  if (sc->fmmu_configs[j].sync_index == sync_index) {
1212  pdo_xfer = 1;
1213  break;
1214  }
1215  }
1216 
1217  } else {
1218  sync_config = NULL;
1219  size = sync->default_length;
1220  }
1221 
1222  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1223  datagram->data + EC_SYNC_PAGE_SIZE * i);
1224  }
1225 
1226  fsm->retries = EC_FSM_RETRIES;
1228 }
1229 
1230 /*****************************************************************************/
1231 
1235  ec_fsm_slave_config_t *fsm,
1236  ec_datagram_t *datagram
1237  )
1238 {
1239  ec_slave_t *slave = fsm->slave;
1240 
1241  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1242  ec_datagram_repeat(datagram, fsm->datagram);
1243  return;
1244  }
1245 
1246  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1248  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1249  " manager configuration datagram: ");
1251  return;
1252  }
1253 
1254  if (fsm->datagram->working_counter != 1) {
1255  slave->error_flag = 1;
1257  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1259  return;
1260  }
1261 
1262  ec_fsm_slave_config_enter_fmmu(fsm, datagram);
1263 }
1264 
1265 /*****************************************************************************/
1266 
1270  ec_fsm_slave_config_t *fsm,
1271  ec_datagram_t *datagram
1272  )
1273 {
1274  ec_slave_t *slave = fsm->slave;
1275  unsigned int i;
1276  const ec_fmmu_config_t *fmmu;
1277  const ec_sync_t *sync;
1278 
1279  if (!slave->config) {
1280  ec_fsm_slave_config_enter_safeop(fsm, datagram);
1281  return;
1282  }
1283 
1284  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1285  slave->error_flag = 1;
1287  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1288  " than requested (%u).\n", slave->base_fmmu_count,
1289  slave->config->used_fmmus);
1290  return;
1291  }
1292 
1293  if (!slave->base_fmmu_count) { // skip FMMU configuration
1294  ec_fsm_slave_config_enter_dc_cycle(fsm, datagram);
1295  return;
1296  }
1297 
1298  // configure FMMUs
1299  ec_datagram_fpwr(datagram, slave->station_address,
1300  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1301  ec_datagram_zero(datagram);
1302  for (i = 0; i < slave->config->used_fmmus; i++) {
1303  fmmu = &slave->config->fmmu_configs[i];
1304  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1305  slave->error_flag = 1;
1307  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1308  " for FMMU!\n");
1309  return;
1310  }
1311  ec_fmmu_config_page(fmmu, sync,
1312  datagram->data + EC_FMMU_PAGE_SIZE * i);
1313  }
1314 
1315  fsm->retries = EC_FSM_RETRIES;
1317 }
1318 
1319 /*****************************************************************************/
1320 
1324  ec_fsm_slave_config_t *fsm,
1325  ec_datagram_t *datagram
1326  )
1327 {
1328  ec_slave_t *slave = fsm->slave;
1329 
1330  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1331  ec_datagram_repeat(datagram, fsm->datagram);
1332  return;
1333  }
1334 
1335  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1337  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1339  return;
1340  }
1341 
1342  if (fsm->datagram->working_counter != 1) {
1343  slave->error_flag = 1;
1345  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1347  return;
1348  }
1349 
1350  ec_fsm_slave_config_enter_dc_cycle(fsm, datagram);
1351 }
1352 
1353 /*****************************************************************************/
1354 
1358  ec_fsm_slave_config_t *fsm,
1359  ec_datagram_t *datagram
1360  )
1361 {
1362  ec_slave_t *slave = fsm->slave;
1363  ec_slave_config_t *config = slave->config;
1364 
1365  if (!config) { // config removed in the meantime
1366  ec_fsm_slave_config_reconfigure(fsm, datagram);
1367  return;
1368  }
1369 
1370  if (config->dc_assign_activate) {
1371  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1372  EC_SLAVE_WARN(slave, "Slave seems not to support"
1373  " distributed clocks!\n");
1374  }
1375 
1376  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1377  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1378 
1379  // set DC cycle times
1380  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1381  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1382  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time +
1383  config->dc_sync[1].shift_time);
1384  fsm->retries = EC_FSM_RETRIES;
1386  } else {
1387  // DC are unused
1388  ec_fsm_slave_config_enter_safeop(fsm, datagram);
1389  }
1390 }
1391 
1392 /*****************************************************************************/
1393 
1397  ec_fsm_slave_config_t *fsm,
1398  ec_datagram_t *datagram
1399  )
1400 {
1401  ec_slave_t *slave = fsm->slave;
1402  ec_slave_config_t *config = slave->config;
1403 
1404  if (!config) { // config removed in the meantime
1405  ec_fsm_slave_config_reconfigure(fsm, datagram);
1406  return;
1407  }
1408 
1409  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1410  ec_datagram_repeat(datagram, fsm->datagram);
1411  return;
1412  }
1413 
1414  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1416  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1418  return;
1419  }
1420 
1421  if (fsm->datagram->working_counter != 1) {
1422  slave->error_flag = 1;
1424  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1426  return;
1427  }
1428 
1429  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1430 
1431  fsm->last_diff_ms = 0;
1432  fsm->jiffies_start = jiffies;
1433  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1434  ec_datagram_zero(datagram);
1435  fsm->retries = EC_FSM_RETRIES;
1437 }
1438 
1439 /*****************************************************************************/
1440 
1444  ec_fsm_slave_config_t *fsm,
1445  ec_datagram_t *datagram
1446  )
1447 {
1448  ec_slave_t *slave = fsm->slave;
1449  ec_master_t *master = slave->master;
1450  ec_slave_config_t *config = slave->config;
1451  bool negative;
1452  uint32_t abs_sync_diff;
1453  unsigned long diff_ms;
1454  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1455  ec_sync_signal_t *sync1 = &config->dc_sync[1];
1456  u64 start_time;
1457 
1458  if (!config) { // config removed in the meantime
1459  ec_fsm_slave_config_reconfigure(fsm, datagram);
1460  return;
1461  }
1462 
1463  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1464  ec_datagram_repeat(datagram, fsm->datagram);
1465  return;
1466  }
1467 
1468  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1470  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1472  return;
1473  }
1474 
1475  if (fsm->datagram->working_counter != 1) {
1476  slave->error_flag = 1;
1478  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1480  return;
1481  }
1482 
1483  abs_sync_diff = EC_READ_U32(fsm->datagram->data) & 0x7fffffff;
1484  negative = (EC_READ_U32(fsm->datagram->data) & 0x80000000) != 0;
1485  diff_ms = (fsm->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1486 
1487  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1488 
1489  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1490  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1491  diff_ms);
1492  } else {
1493  if ((diff_ms < fsm->last_diff_ms)
1494  || (diff_ms >= (fsm->last_diff_ms + 100))) {
1495  fsm->last_diff_ms = diff_ms;
1496  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10d ns\n",
1497  diff_ms, negative ? -abs_sync_diff: abs_sync_diff);
1498  }
1499 
1500  // check synchrony again
1501  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1502  ec_datagram_zero(datagram);
1503  fsm->retries = EC_FSM_RETRIES;
1504  return;
1505  }
1506  } else {
1507  EC_SLAVE_DBG(slave, 1, "%d ns difference after %lu ms.\n",
1508  negative ? -abs_sync_diff: abs_sync_diff, diff_ms);
1509  }
1510 
1511  // set DC start time (roughly in the future, not in-phase)
1512  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1513 
1514  if (sync0->cycle_time) {
1515  // find correct phase
1516  if (master->dc_ref_time) {
1517  u64 diff, start;
1518  u32 remainder, cycle;
1519 
1520  diff = start_time - master->dc_ref_time;
1521  cycle = sync0->cycle_time + sync1->cycle_time;
1522  remainder = do_div(diff, cycle);
1523 
1524  start = start_time + cycle - remainder + sync0->shift_time;
1525 
1526  EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1527  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1528  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1529  EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1530  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1531  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1532  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1533  start_time = start;
1534  } else {
1535  EC_SLAVE_WARN(slave, "No application time supplied."
1536  " Cyclic start time will not be in phase.\n");
1537  }
1538  }
1539 
1540  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1541  " start time to %llu.\n", start_time);
1542 
1543  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1544  EC_WRITE_U64(datagram->data, start_time);
1545  fsm->retries = EC_FSM_RETRIES;
1547 }
1548 
1549 /*****************************************************************************/
1550 
1554  ec_fsm_slave_config_t *fsm,
1555  ec_datagram_t *datagram
1556  )
1557 {
1558  ec_slave_t *slave = fsm->slave;
1559  ec_slave_config_t *config = slave->config;
1560 
1561  if (!config) { // config removed in the meantime
1562  ec_fsm_slave_config_reconfigure(fsm, datagram);
1563  return;
1564  }
1565 
1566  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1567  ec_datagram_repeat(datagram, fsm->datagram);
1568  return;
1569  }
1570 
1571  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1573  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1575  return;
1576  }
1577 
1578  if (fsm->datagram->working_counter != 1) {
1579  slave->error_flag = 1;
1581  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1583  return;
1584  }
1585 
1586  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1587  config->dc_assign_activate);
1588 
1589  // assign sync unit to EtherCAT or PDI
1590  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1591  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1592  fsm->retries = EC_FSM_RETRIES;
1594 }
1595 
1596 /*****************************************************************************/
1597 
1601  ec_fsm_slave_config_t *fsm,
1602  ec_datagram_t *datagram
1603  )
1604 {
1605  ec_slave_t *slave = fsm->slave;
1606 
1607  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
1608  ec_datagram_repeat(datagram, fsm->datagram);
1609  return;
1610  }
1611 
1612  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
1614  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1616  return;
1617  }
1618 
1619  if (fsm->datagram->working_counter != 1) {
1620  slave->error_flag = 1;
1622  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1624  return;
1625  }
1626 
1627  ec_fsm_slave_config_enter_safeop(fsm, datagram);
1628 }
1629 
1630 /*****************************************************************************/
1631 
1635  ec_fsm_slave_config_t *fsm,
1636  ec_datagram_t *datagram
1637  )
1638 {
1641  ec_fsm_change_exec(fsm->fsm_change, datagram); // execute immediately
1642 }
1643 
1644 /*****************************************************************************/
1645 
1649  ec_fsm_slave_config_t *fsm,
1650  ec_datagram_t *datagram
1651  )
1652 {
1653  ec_slave_t *slave = fsm->slave;
1654 
1655  if (ec_fsm_change_exec(fsm->fsm_change, datagram)) return;
1656 
1657  if (!ec_fsm_change_success(fsm->fsm_change)) {
1658  if (!fsm->fsm_change->spontaneous_change)
1659  fsm->slave->error_flag = 1;
1661  return;
1662  }
1663 
1664  // slave is now in SAFEOP
1665 
1666  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1667 
1668  if (fsm->slave->current_state == fsm->slave->requested_state) {
1669  fsm->state = ec_fsm_slave_config_state_end; // successful
1670  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1671  return;
1672  }
1673 
1675 }
1676 
1677 /*****************************************************************************/
1678 
1682  ec_fsm_slave_config_t *fsm,
1683  ec_datagram_t *datagram
1684  )
1685 {
1686  ec_slave_t *slave = fsm->slave;
1687  ec_soe_request_t *req;
1688 
1689  if (!slave->config) {
1690  ec_fsm_slave_config_enter_op(fsm, datagram);
1691  return;
1692  }
1693 
1694  list_for_each_entry(req, &slave->config->soe_configs, list) {
1695  if (req->al_state == EC_AL_STATE_SAFEOP) {
1696  // start SoE configuration
1698  fsm->soe_request = req;
1701  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1702  &fsm->soe_request_copy);
1703  ec_fsm_soe_exec(fsm->fsm_soe, datagram);
1704  return;
1705  }
1706  }
1707 
1708  // No SoE configuration to be applied in SAFEOP
1709  ec_fsm_slave_config_enter_op(fsm, datagram);
1710 }
1711 
1712 /*****************************************************************************/
1713 
1717  ec_fsm_slave_config_t *fsm,
1718  ec_datagram_t *datagram
1719  )
1720 {
1721  ec_slave_t *slave = fsm->slave;
1722 
1723  if (ec_fsm_soe_exec(fsm->fsm_soe, datagram)) {
1724  return;
1725  }
1726 
1727  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1728  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1729  fsm->slave->error_flag = 1;
1731  return;
1732  }
1733 
1734  if (!fsm->slave->config) { // config removed in the meantime
1735  ec_fsm_slave_config_reconfigure(fsm, datagram);
1736  return;
1737  }
1738 
1739  // Another IDN to configure in SAFEOP?
1740  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1741  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1742  ec_soe_request_t, list);
1743  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1746  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1747  &fsm->soe_request_copy);
1748  ec_fsm_soe_exec(fsm->fsm_soe, datagram);
1749  return;
1750  }
1751  }
1752 
1753  // All SAFEOP IDNs are now configured.
1754  ec_fsm_slave_config_enter_op(fsm, datagram);
1755 }
1756 
1757 /*****************************************************************************/
1758 
1762  ec_fsm_slave_config_t *fsm,
1763  ec_datagram_t *datagram
1764  )
1765 {
1766  // set state to OP
1769  ec_fsm_change_exec(fsm->fsm_change, datagram); // execute immediately
1770 }
1771 
1772 /*****************************************************************************/
1773 
1777  ec_fsm_slave_config_t *fsm,
1778  ec_datagram_t *datagram
1779  )
1780 {
1781  ec_slave_t *slave = fsm->slave;
1782 
1783  if (ec_fsm_change_exec(fsm->fsm_change, datagram)) return;
1784 
1785  if (!ec_fsm_change_success(fsm->fsm_change)) {
1786  if (!fsm->fsm_change->spontaneous_change)
1787  slave->error_flag = 1;
1789  return;
1790  }
1791 
1792  // slave is now in OP
1793 
1794  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1795 
1796  fsm->state = ec_fsm_slave_config_state_end; // successful
1797 }
1798 
1799 /*****************************************************************************/
1800 
1804  ec_fsm_slave_config_t *fsm,
1805  ec_datagram_t *datagram
1806  )
1807 {
1808  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1809  "configuration. Reconfiguring.");
1810 
1811  ec_fsm_slave_config_enter_init(fsm, datagram); // reconfigure
1812 }
1813 
1814 /******************************************************************************
1815  * Common state functions
1816  *****************************************************************************/
1817 
1821  ec_fsm_slave_config_t *fsm,
1822  ec_datagram_t *datagram
1823  )
1824 {
1825 }
1826 
1827 /*****************************************************************************/
1828 
1832  ec_fsm_slave_config_t *fsm,
1833  ec_datagram_t *datagram
1834  )
1835 {
1836 }
1837 
1838 /*****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:59
Finite state machines for the Sercos over EtherCAT protocol.
Definition: fsm_soe.h:51
void ec_mbox_prot_data_prealloc(ec_slave_t *slave, uint16_t protocols, size_t size)
Allocates internal memory for mailbox response data for all slave supported mailbox protocols ...
Definition: datagram.c:738
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
Pre-operational.
Definition: ecrt.h:574
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:145
void ec_fsm_slave_config_start(ec_fsm_slave_config_t *fsm)
Start slave configuration state machine.
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:164
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:127
int ec_fsm_pdo_exec(ec_fsm_pdo_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_pdo.c:164
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: OP.
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: SOE_CONF.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:248
FMMU configuration.
Definition: fmmu_config.h:46
ec_sdo_request_t * request
SDO request for SDO configuration.
struct list_head list
List item.
Definition: soe_request.h:49
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:108
void ec_fsm_pdo_start_configuration(ec_fsm_pdo_t *fsm, ec_slave_t *slave)
Start writing the PDO configuration.
Definition: fsm_pdo.c:132
int32_t shift_time
Shift time [ns].
Definition: globals.h:220
OP (mailbox communication and input/output update)
Definition: globals.h:170
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:246
ec_fsm_change_t * fsm_change
State change state machine.
CANopen SDO request.
Definition: sdo_request.h:48
ec_slave_state_t current_state
Current application state.
Definition: slave.h:237
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:141
Safe-operational.
Definition: ecrt.h:575
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:91
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: START.
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: WATCHDOG.
EtherCAT datagram.
Definition: datagram.h:88
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2642
void ec_fsm_slave_config_quick_start(ec_fsm_slave_config_t *fsm)
Start slave configuration state machine for "quick" SAFEOP->OP.
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:250
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:166
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:219
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:88
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: WATCHDOG_DIVIDER.
uint16_t working_counter
Working counter.
Definition: datagram.h:100
void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *, ec_datagram_t *)
Assign SII to PDI.
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:259
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:167
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:86
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: ASSIGN_PDI.
uint16_t station_address
Configured station address.
Definition: slave.h:222
unsigned int sync_count
Number of sync managers.
Definition: slave.h:191
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:169
void ec_sync_page(const ec_sync_t *sync, uint8_t sync_index, uint16_t data_size, const ec_sync_config_t *sync_config, uint8_t pdo_xfer, uint8_t *data)
Initializes a sync manager configuration page.
Definition: sync.c:94
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:170
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Configure PDO sync managers.
EtherCAT master structure.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:140
SAFEOP (mailbox communication and input update)
Definition: globals.h:168
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Clear the sync manager configurations.
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:143
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:166
EtherCAT slave.
Definition: slave.h:214
void ec_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for SoE configurations to be applied.
void ec_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition: sdo_request.c:76
EtherCAT slave configuration state machine.
uint16_t ec_pdo_list_total_size(const ec_pdo_list_t *pl)
Calculates the total size of the mapped PDO entries.
Definition: pdo_list.c:87
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:179
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for FMMUs to be configured.
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
ec_sii_image_t * sii_image
Current complete SII image.
Definition: slave.h:267
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:132
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:138
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: INIT.
ec_datagram_state_t state
State.
Definition: datagram.h:101
ec_slave_config_t * config
Current configuration.
Definition: slave.h:235
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2676
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for DC to be configured.
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:172
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: BOOT/PREOP.
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: SOE_CONF.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: PDO_CONF.
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:77
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: DC CYCLE.
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for SoE configurations to be applied in SAFEOP.
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:627
#define EC_DC_START_OFFSET
Time offset (in ns), that is added to cyclic start time.
Sync manager.
Definition: sync.h:47
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:168
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for SDO configurations to be applied.
void ec_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition: soe_request.c:77
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:49
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:142
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:2659
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: CLEAR SYNC.
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:254
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:242
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for mailbox sync managers to be configured.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2570
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:130
ec_master_t * master
Master owning the slave.
Definition: slave.h:216
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Check for PDO sync managers to be configured.
int ec_sdo_request_copy(ec_sdo_request_t *req, const ec_sdo_request_t *other)
Copy another SDO request.
Definition: sdo_request.c:91
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *, ec_datagram_t *)
Start state change to INIT.
void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: ASSIGN_ETHERCAT.
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:320
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:259
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: SYNC.
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:295
uint8_t control_register
Control register value.
Definition: sync.h:51
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: FMMU.
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: SAFEOP.
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:128
PDO configuration state machine.
Definition: fsm_pdo.h:54
ec_al_state_t al_state
AL state (only valid for IDN config).
Definition: soe_request.h:52
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *, ec_datagram_t *)
Reconfigure the slave starting at INIT.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: CLEAR DC ASSIGN.
ec_fsm_soe_t * fsm_soe
SoE state machine.
struct list_head soe_configs
List of SoE configurations.
Definition: slave_config.h:150
unsigned int take_time
Store jiffies after datagram reception.
void ec_read_mbox_lock_clear(ec_slave_t *slave)
Clears the mailbox lock.
Definition: slave.c:216
INIT state (no mailbox communication, no IO)
Definition: globals.h:162
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:180
Finite state machine to configure an EtherCAT slave.
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:587
Mailbox functionality.
uint8_t enable
Enable bit.
Definition: sync.h:52
ec_slave_t * slave
Slave the FSM runs on.
Invalid direction.
Definition: ecrt.h:437
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: SDO_CONF.
void ec_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition: sdo_request.c:56
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2693
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:165
ec_soe_request_t soe_request_copy
Copied SDO request.
Sync manager configuration.
Definition: sync_config.h:46
struct list_head list
List item.
Definition: sdo_request.h:49
EtherCAT slave sync signal configuration.
Definition: globals.h:218
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:235
int ec_fsm_slave_config_exec(ec_fsm_slave_config_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *, ec_datagram_t *)
Request SAFEOP state.
int ec_fsm_change_exec(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_change.c:122
Timed out (dequeued).
Definition: datagram.h:79
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:249
uint16_t physical_start_address
Physical start address.
Definition: sync.h:49
unsigned long jiffies_preop
Time, the slave went to PREOP.
Definition: slave.h:272
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: DC SYNC CHECK.
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:244
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:257
void ec_fsm_slave_config_init(ec_fsm_slave_config_t *fsm, ec_slave_t *slave, 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.
uint8_t * data
Datagram payload.
Definition: datagram.h:95
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *, ec_datagram_t *)
WATCHDOG_DIVIDER entry function.
void ec_fsm_slave_config_state_quick_start(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: QUICK START.
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:255
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *, ec_datagram_t *)
Request PREOP state.
EtherCAT slave configuration.
Definition: slave_config.h:118
ec_soe_request_t * soe_request
SDO request for SDO configuration.
void ec_soe_request_write(ec_soe_request_t *req)
Request a write operation.
Definition: soe_request.c:245
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *, ec_datagram_t *)
Bring slave to OP.
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition: soe_request.c:56
EtherCAT slave configuration structure.
ec_sii_t sii
Extracted SII data.
Definition: slave.h:207
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:154
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:212
uint16_t default_length
Data length in bytes.
Definition: sync.h:50
PREOP state (mailbox communication, no IO)
Definition: globals.h:164
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: DC ASSIGN.
Received (dequeued).
Definition: datagram.h:78
unsigned long last_diff_ms
For sync reporting.
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *, ec_datagram_t *)
PDO_CONF entry function.
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:239
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:190
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:171
EtherCAT master.
Definition: master.h:202
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:236
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:133
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *, ec_datagram_t *)
Clear the DC assignment.
int ec_datagram_repeat(ec_datagram_t *datagram, const ec_datagram_t *source)
Copies a previously constructed datagram for repeated send.
Definition: datagram.c:190
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c:46
void ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:243
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: CLEAR FMMU.
#define EC_DC_SYNC_WAIT_MS
Maximum time (in ms) to wait for clock discipline.
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:110
void(* state)(ec_fsm_slave_config_t *, ec_datagram_t *)
State function.
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *, ec_datagram_t *)
Slave configuration state: DC START.
EtherCAT state change FSM.
Definition: fsm_change.h:64
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *, ec_datagram_t *)
State: ERROR.
int ec_soe_request_copy(ec_soe_request_t *req, const ec_soe_request_t *other)
Copy another SoE request.
Definition: soe_request.c:90
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *, ec_datagram_t *)
State: END.
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:148
unsigned long jiffies_start
For timeout calculations.
Sercos-over-EtherCAT request.
Definition: soe_request.h:48
Finite state machines for the CANopen over EtherCAT protocol.
Definition: fsm_coe.h:52
ec_sync_t * ec_slave_get_sync(ec_slave_t *slave, uint8_t sync_index)
Get the sync manager given an index.
Definition: slave.c:767
unsigned int retries
Retries on datagram timeout.
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *, ec_datagram_t *)
WATCHDOG entry function.