IgH EtherCAT Master  1.6.0-rc1
fsm_slave_config.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
6  *
7  * This file is part of the IgH EtherCAT Master.
8  *
9  * The IgH EtherCAT Master is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version 2, as
11  * published by the Free Software Foundation.
12  *
13  * The IgH EtherCAT Master is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with the IgH EtherCAT Master; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * ---
23  *
24  * The license mentioned above concerns the source code only. Using the
25  * EtherCAT technology and brand is only permitted in compliance with the
26  * industrial property and similar rights of Beckhoff Automation GmbH.
27  *
28  *****************************************************************************/
29 
35 /*****************************************************************************/
36 
37 #include <asm/div64.h>
38 
39 #include "globals.h"
40 #include "master.h"
41 #include "mailbox.h"
42 #include "slave_config.h"
43 #include "fsm_slave_config.h"
44 
45 /*****************************************************************************/
46 
52 #define EC_DC_MAX_SYNC_DIFF_NS 10000
53 
56 #define EC_DC_SYNC_WAIT_MS 5000
57 
60 #define EC_DC_START_OFFSET 100000000ULL
61 
62 /*****************************************************************************/
63 
70 #ifdef EC_SII_ASSIGN
72 #endif
74 #ifdef EC_SII_ASSIGN
76 #endif
91 
96 #ifdef EC_SII_ASSIGN
98 #endif
111 
114 
116 
117 /*****************************************************************************/
118 
122  ec_fsm_slave_config_t *fsm,
123  ec_datagram_t *datagram,
124  ec_fsm_change_t *fsm_change,
125  ec_fsm_coe_t *fsm_coe,
126  ec_fsm_soe_t *fsm_soe,
127  ec_fsm_pdo_t *fsm_pdo
128  )
129 {
132 
133  fsm->datagram = datagram;
134  fsm->fsm_change = fsm_change;
135  fsm->fsm_coe = fsm_coe;
136  fsm->fsm_soe = fsm_soe;
137  fsm->fsm_pdo = fsm_pdo;
138 }
139 
140 /*****************************************************************************/
141 
146  )
147 {
150 }
151 
152 /*****************************************************************************/
153 
157  ec_fsm_slave_config_t *fsm,
158  ec_slave_t *slave
159  )
160 {
161  fsm->slave = slave;
163 }
164 
165 /*****************************************************************************/
166 
171  const ec_fsm_slave_config_t *fsm
172  )
173 {
174  return fsm->state != ec_fsm_slave_config_state_end
176 }
177 
178 /*****************************************************************************/
179 
189  )
190 {
191  if (fsm->datagram->state == EC_DATAGRAM_SENT
192  || fsm->datagram->state == EC_DATAGRAM_QUEUED) {
193  // datagram was not sent or received yet.
194  return ec_fsm_slave_config_running(fsm);
195  }
196 
197  fsm->state(fsm);
198  return ec_fsm_slave_config_running(fsm);
199 }
200 
201 /*****************************************************************************/
202 
207  const ec_fsm_slave_config_t *fsm
208  )
209 {
210  return fsm->state == ec_fsm_slave_config_state_end;
211 }
212 
213 /******************************************************************************
214  * Slave configuration state machine
215  *****************************************************************************/
216 
221  )
222 {
223  EC_SLAVE_DBG(fsm->slave, 1, "Configuring...\n");
225 }
226 
227 /*****************************************************************************/
228 
233  )
234 {
238 }
239 
240 /*****************************************************************************/
241 
246  )
247 {
248  ec_slave_t *slave = fsm->slave;
249  ec_datagram_t *datagram = fsm->datagram;
250 
251  if (ec_fsm_change_exec(fsm->fsm_change)) return;
252 
253  if (!ec_fsm_change_success(fsm->fsm_change)) {
254  if (!fsm->fsm_change->spontaneous_change)
255  slave->error_flag = 1;
257  return;
258  }
259 
260  EC_SLAVE_DBG(slave, 1, "Now in INIT.\n");
261 
262  if (!slave->base_fmmu_count) { // skip FMMU configuration
264  return;
265  }
266 
267  EC_SLAVE_DBG(slave, 1, "Clearing FMMU configurations...\n");
268 
269  // clear FMMU configurations
270  ec_datagram_fpwr(datagram, slave->station_address,
271  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
272  ec_datagram_zero(datagram);
273  fsm->retries = EC_FSM_RETRIES;
275 
276  EC_SLAVE_DBG(slave, 1, "Clearing mailbox check flag...\n");
277 
279 }
280 
281 /*****************************************************************************/
282 
287  )
288 {
289  ec_datagram_t *datagram = fsm->datagram;
290 
291  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
292  return;
293 
294  if (datagram->state != EC_DATAGRAM_RECEIVED) {
296  EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
297  return;
298  }
299 
300  if (datagram->working_counter != 1) {
301  fsm->slave->error_flag = 1;
303  EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
304  ec_datagram_print_wc_error(datagram);
305  return;
306  }
307 
309 }
310 
311 /*****************************************************************************/
312 
317  )
318 {
319  ec_slave_t *slave = fsm->slave;
320  ec_datagram_t *datagram = fsm->datagram;
321  size_t sync_size;
322 
323  if (!slave->base_sync_count) {
324  // no sync managers
326  return;
327  }
328 
329  EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
330 
331  sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
332 
333  // clear sync manager configurations
334  ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
335  ec_datagram_zero(datagram);
336  fsm->retries = EC_FSM_RETRIES;
338 }
339 
340 /*****************************************************************************/
341 
346  )
347 {
348  ec_datagram_t *datagram = fsm->datagram;
349 
350  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
351  return;
352 
353  if (datagram->state != EC_DATAGRAM_RECEIVED) {
355  EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
356  " clearing datagram.\n");
357  return;
358  }
359 
360  if (datagram->working_counter != 1) {
361  fsm->slave->error_flag = 1;
363  EC_SLAVE_ERR(fsm->slave,
364  "Failed to clear sync manager configurations: ");
365  ec_datagram_print_wc_error(datagram);
366  return;
367  }
368 
370 }
371 
372 /*****************************************************************************/
373 
378  )
379 {
380  ec_slave_t *slave = fsm->slave;
381  ec_datagram_t *datagram = fsm->datagram;
382 
383  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
385  return;
386  }
387 
388  EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
389 
390  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
391  ec_datagram_zero(datagram);
392  fsm->retries = EC_FSM_RETRIES;
394 }
395 
396 /*****************************************************************************/
397 
402  )
403 {
404  ec_datagram_t *datagram = fsm->datagram;
405 
406  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
407  return;
408 
409  if (datagram->state != EC_DATAGRAM_RECEIVED) {
411  EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
412  " clearing datagram.\n");
413  return;
414  }
415 
416  if (datagram->working_counter != 1) {
417  // clearing the DC assignment does not succeed on simple slaves
418  EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
419  ec_datagram_print_wc_error(datagram);
420  }
421 
423 }
424 
425 /*****************************************************************************/
426 
431  )
432 {
433  ec_slave_t *slave = fsm->slave;
434  ec_datagram_t *datagram = fsm->datagram;
435  unsigned int i;
436 
437  // slave is now in INIT
438  if (slave->current_state == slave->requested_state) {
439  fsm->state = ec_fsm_slave_config_state_end; // successful
440  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
441  return;
442  }
443 
444  if (!slave->sii.mailbox_protocols) {
445  // no mailbox protocols supported
446  EC_SLAVE_DBG(slave, 1, "Slave does not support"
447  " mailbox communication.\n");
448 #ifdef EC_SII_ASSIGN
450 #else
452 #endif
453  return;
454  }
455 
456  EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
457 
458  if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
459  ec_sync_t sync;
460 
461  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
462  EC_SYNC_PAGE_SIZE * 2);
463  ec_datagram_zero(datagram);
464 
465  ec_sync_init(&sync, slave);
467  sync.control_register = 0x26;
468  sync.enable = 1;
469  ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
470  EC_DIR_INVALID, // use default direction
471  0, // no PDO xfer
472  datagram->data);
476  slave->sii.boot_rx_mailbox_size;
477 
478  ec_sync_init(&sync, slave);
480  sync.control_register = 0x22;
481  sync.enable = 1;
482  ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
483  EC_DIR_INVALID, // use default direction
484  0, // no PDO xfer
485  datagram->data + EC_SYNC_PAGE_SIZE);
489  slave->sii.boot_tx_mailbox_size;
490 
491  } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
492  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
493  EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
494  ec_datagram_zero(datagram);
495 
496  for (i = 0; i < 2; i++) {
497  ec_sync_page(&slave->sii.syncs[i], i,
498  slave->sii.syncs[i].default_length,
499  NULL, // use default sync manager configuration
500  0, // no PDO xfer
501  datagram->data + EC_SYNC_PAGE_SIZE * i);
502  }
503 
505  slave->sii.syncs[0].physical_start_address;
507  slave->sii.syncs[0].default_length;
509  slave->sii.syncs[1].physical_start_address;
511  slave->sii.syncs[1].default_length;
512  } else { // no mailbox sync manager configurations provided
513  ec_sync_t sync;
514 
515  EC_SLAVE_DBG(slave, 1, "Slave does not provide"
516  " mailbox sync manager configurations.\n");
517 
518  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
519  EC_SYNC_PAGE_SIZE * 2);
520  ec_datagram_zero(datagram);
521 
522  ec_sync_init(&sync, slave);
524  sync.control_register = 0x26;
525  sync.enable = 1;
526  ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
527  NULL, // use default sync manager configuration
528  0, // no PDO xfer
529  datagram->data);
531  slave->sii.std_rx_mailbox_offset;
533  slave->sii.std_rx_mailbox_size;
534 
535  ec_sync_init(&sync, slave);
537  sync.control_register = 0x22;
538  sync.enable = 1;
539  ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
540  NULL, // use default sync manager configuration
541  0, // no PDO xfer
542  datagram->data + EC_SYNC_PAGE_SIZE);
544  slave->sii.std_tx_mailbox_offset;
546  slave->sii.std_tx_mailbox_size;
547  }
548 
549  // allocate memory for mailbox response data for supported mailbox protocols
551 
552  fsm->take_time = 1;
553 
554  fsm->retries = EC_FSM_RETRIES;
556 }
557 
558 /*****************************************************************************/
559 
566  )
567 {
568  ec_datagram_t *datagram = fsm->datagram;
569  ec_slave_t *slave = fsm->slave;
570 
571  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
572  return;
573 
574  if (datagram->state != EC_DATAGRAM_RECEIVED) {
576  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
577  " configuration datagram: ");
578  ec_datagram_print_state(datagram);
579  return;
580  }
581 
582  if (fsm->take_time) {
583  fsm->take_time = 0;
584  fsm->jiffies_start = datagram->jiffies_sent;
585  }
586 
587  /* Because the sync manager configurations are cleared during the last
588  * cycle, some slaves do not immediately respond to the mailbox sync
589  * manager configuration datagram. Therefore, resend the datagram for
590  * a certain time, if the slave does not respond.
591  */
592  if (datagram->working_counter == 0) {
593  unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
594 
595  if (diff >= HZ) {
596  slave->error_flag = 1;
598  EC_SLAVE_ERR(slave, "Timeout while configuring"
599  " mailbox sync managers.\n");
600  return;
601  } else {
602  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
603  (unsigned int) diff * 1000 / HZ);
604  }
605 
606  // send configuration datagram again
607  fsm->retries = EC_FSM_RETRIES;
608  return;
609  }
610  else if (datagram->working_counter != 1) {
611  slave->error_flag = 1;
613  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
614  ec_datagram_print_wc_error(datagram);
615  return;
616  }
617 
618 #ifdef EC_SII_ASSIGN
620 #else
622 #endif
623 }
624 
625 /*****************************************************************************/
626 
627 #ifdef EC_SII_ASSIGN
628 
633  )
634 {
635  ec_datagram_t *datagram = fsm->datagram;
636  ec_slave_t *slave = fsm->slave;
637 
639  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
640 
641  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
642  EC_WRITE_U8(datagram->data, 0x01); // PDI
643  fsm->retries = EC_FSM_RETRIES;
645  }
646  else {
648  }
649 }
650 
651 /*****************************************************************************/
652 
657  )
658 {
659  ec_datagram_t *datagram = fsm->datagram;
660  ec_slave_t *slave = fsm->slave;
661 
662  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
663  return;
664  }
665 
666  if (datagram->state != EC_DATAGRAM_RECEIVED) {
667  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
668  ec_datagram_print_state(datagram);
669  goto cont_preop;
670  }
671 
672  if (datagram->working_counter != 1) {
673  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
674  ec_datagram_print_wc_error(datagram);
675  }
676 
677 cont_preop:
679 }
680 
681 #endif
682 
683 /*****************************************************************************/
684 
689  )
690 {
692 
696  } else { // BOOT
698  fsm->slave, EC_SLAVE_STATE_BOOT);
699  }
700 
701  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
702 }
703 
704 /*****************************************************************************/
705 
710  )
711 {
712  ec_slave_t *slave = fsm->slave;
713 #ifdef EC_SII_ASSIGN
714  int assign_to_pdi;
715  ec_slave_config_t *config;
716  ec_flag_t *flag;
717 #endif
718 
719  if (ec_fsm_change_exec(fsm->fsm_change)) {
720  return;
721  }
722 
723  if (!ec_fsm_change_success(fsm->fsm_change)) {
724  if (!fsm->fsm_change->spontaneous_change)
725  slave->error_flag = 1;
727  return;
728  }
729 
730  // slave is now in BOOT or PREOP
731  slave->jiffies_preop = fsm->datagram->jiffies_received;
732 
733  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
734  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
735 
736 #ifdef EC_SII_ASSIGN
737  assign_to_pdi = 0;
738  config = fsm->slave->config;
739  if (config) {
740  flag = ec_slave_config_find_flag(config, "AssignToPdi");
741  if (flag) {
742  assign_to_pdi = flag->value;
743  }
744  }
745 
746  if (assign_to_pdi) {
747  EC_SLAVE_DBG(slave, 1, "Skipping SII assignment back to EtherCAT.\n");
748  if (slave->current_state == slave->requested_state) {
749  fsm->state = ec_fsm_slave_config_state_end; // successful
750  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
751  return;
752  }
753 
755  }
756  else {
757  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
758 
759  ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
760  EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
761  fsm->retries = EC_FSM_RETRIES;
763  }
764 #else
765  if (slave->current_state == slave->requested_state) {
766  fsm->state = ec_fsm_slave_config_state_end; // successful
767  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
768  return;
769  }
770 
772 #endif
773 }
774 
775 /*****************************************************************************/
776 
777 #ifdef EC_SII_ASSIGN
778 
783  )
784 {
785  ec_datagram_t *datagram = fsm->datagram;
786  ec_slave_t *slave = fsm->slave;
787 
788  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
789  return;
790  }
791 
792  if (datagram->state != EC_DATAGRAM_RECEIVED) {
793  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
794  ec_datagram_print_state(datagram);
795  goto cont_sdo_conf;
796  }
797 
798  if (datagram->working_counter != 1) {
799  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
800  ec_datagram_print_wc_error(datagram);
801  }
802 
803 cont_sdo_conf:
804  if (slave->current_state == slave->requested_state) {
805  fsm->state = ec_fsm_slave_config_state_end; // successful
806  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
807  return;
808  }
809 
811 }
812 
813 #endif
814 
815 /*****************************************************************************/
816 
821  )
822 {
823  ec_slave_t *slave = fsm->slave;
824 
825  if (!slave->config) {
827  return;
828  }
829 
830  // No CoE configuration to be applied?
831  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
833  return;
834  }
835 
836  // start SDO configuration
838  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
839  ec_sdo_request_t, list);
842  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
843  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
844 }
845 
846 /*****************************************************************************/
847 
852  )
853 {
854  if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
855  return;
856  }
857 
858  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
859  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
860  fsm->slave->error_flag = 1;
862  return;
863  }
864 
865  if (!fsm->slave->config) { // config removed in the meantime
867  return;
868  }
869 
870  // Another SDO to configure?
871  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
872  fsm->request = list_entry(fsm->request->list.next,
873  ec_sdo_request_t, list);
876  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
877  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
878  return;
879  }
880 
881  // All SDOs are now configured.
883 }
884 
885 /*****************************************************************************/
886 
891  )
892 {
893  ec_slave_t *slave = fsm->slave;
894  ec_soe_request_t *req;
895 
896  if (!slave->config) {
898  return;
899  }
900 
901  list_for_each_entry(req, &slave->config->soe_configs, list) {
902  if (req->al_state == EC_AL_STATE_PREOP) {
903  // start SoE configuration
905  fsm->soe_request = req;
908  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
909  &fsm->soe_request_copy);
910  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
911  return;
912  }
913  }
914 
915  // No SoE configuration to be applied in PREOP
917 }
918 
919 /*****************************************************************************/
920 
925  )
926 {
927  ec_slave_t *slave = fsm->slave;
928 
929  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
930  return;
931  }
932 
933  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
934  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
935  fsm->slave->error_flag = 1;
937  return;
938  }
939 
940  if (!fsm->slave->config) { // config removed in the meantime
942  return;
943  }
944 
945  // Another IDN to configure in PREOP?
946  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
947  fsm->soe_request = list_entry(fsm->soe_request->list.next,
948  ec_soe_request_t, list);
949  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
952  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
953  &fsm->soe_request_copy);
954  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
955  return;
956  }
957  }
958 
959  // All PREOP IDNs are now configured.
961 }
962 
963 /*****************************************************************************/
964 
969  )
970 {
971  // Start configuring PDOs
974  fsm->state(fsm); // execute immediately
975 }
976 
977 /*****************************************************************************/
978 
983  )
984 {
985  // TODO check for config here
986 
987  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
988  return;
989  }
990 
991  if (!fsm->slave->config) { // config removed in the meantime
993  return;
994  }
995 
996  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
997  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
998  }
999 
1001 }
1002 
1003 /*****************************************************************************/
1004 
1008  ec_fsm_slave_config_t *fsm
1009  )
1010 {
1011  ec_slave_t *slave = fsm->slave;
1012  ec_datagram_t *datagram = fsm->datagram;
1013  ec_slave_config_t *config = slave->config;
1014 
1015  if (config && config->watchdog_divider) {
1016  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
1017  config->watchdog_divider);
1018 
1019  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
1020  EC_WRITE_U16(datagram->data, config->watchdog_divider);
1021  fsm->retries = EC_FSM_RETRIES;
1023  } else {
1025  }
1026 }
1027 
1028 /*****************************************************************************/
1029 
1033  ec_fsm_slave_config_t *fsm
1034  )
1035 {
1036  ec_datagram_t *datagram = fsm->datagram;
1037  ec_slave_t *slave = fsm->slave;
1038 
1039  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1040  return;
1041 
1042  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1044  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1045  " configuration datagram: ");
1046  ec_datagram_print_state(datagram);
1047  return;
1048  }
1049 
1050  if (datagram->working_counter != 1) {
1051  slave->error_flag = 1;
1052  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1053  ec_datagram_print_wc_error(datagram);
1054  return;
1055  }
1056 
1058 }
1059 
1060 /*****************************************************************************/
1061 
1065  ec_fsm_slave_config_t *fsm
1066  )
1067 {
1068  ec_datagram_t *datagram = fsm->datagram;
1069  ec_slave_t *slave = fsm->slave;
1070  ec_slave_config_t *config = slave->config;
1071 
1072  if (config && config->watchdog_intervals) {
1073  EC_SLAVE_DBG(slave, 1, "Setting process data"
1074  " watchdog intervals to %u.\n", config->watchdog_intervals);
1075 
1076  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1077  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1078 
1079  fsm->retries = EC_FSM_RETRIES;
1081  } else {
1083  }
1084 }
1085 
1086 /*****************************************************************************/
1087 
1092  ec_fsm_slave_config_t *fsm
1093  )
1094 {
1095  ec_datagram_t *datagram = fsm->datagram;
1096  ec_slave_t *slave = fsm->slave;
1097 
1098  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1099  return;
1100 
1101  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1103  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1104  " watchdog configuration datagram: ");
1105  ec_datagram_print_state(datagram);
1106  return;
1107  }
1108 
1109  if (datagram->working_counter != 1) {
1110  EC_SLAVE_WARN(slave, "Failed to set process data"
1111  " watchdog intervals: ");
1112  ec_datagram_print_wc_error(datagram);
1113  }
1114 
1116 }
1117 
1118 /*****************************************************************************/
1119 
1123  ec_fsm_slave_config_t *fsm
1124  )
1125 {
1126  ec_slave_t *slave = fsm->slave;
1127  ec_datagram_t *datagram = fsm->datagram;
1128  unsigned int i, j, offset, num_pdo_syncs;
1129  uint8_t sync_index;
1130  const ec_sync_t *sync;
1131  uint16_t size;
1132 
1133  if (slave->sii.mailbox_protocols) {
1134  offset = 2; // slave has mailboxes
1135  } else {
1136  offset = 0;
1137  }
1138 
1139  if (slave->sii.sync_count <= offset) {
1140  // no PDO sync managers to configure
1142  return;
1143  }
1144 
1145  num_pdo_syncs = slave->sii.sync_count - offset;
1146 
1147  // configure sync managers for process data
1148  ec_datagram_fpwr(datagram, slave->station_address,
1149  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1150  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1151  ec_datagram_zero(datagram);
1152 
1153  for (i = 0; i < num_pdo_syncs; i++) {
1154  const ec_sync_config_t *sync_config;
1155  uint8_t pdo_xfer = 0;
1156  sync_index = i + offset;
1157  sync = &slave->sii.syncs[sync_index];
1158 
1159  if (slave->config) {
1160  const ec_slave_config_t *sc = slave->config;
1161  sync_config = &sc->sync_configs[sync_index];
1162  size = ec_pdo_list_total_size(&sync_config->pdos);
1163 
1164  // determine, if PDOs shall be transferred via this SM
1165  // in that case, enable sync manager in every case
1166  for (j = 0; j < sc->used_fmmus; j++) {
1167  if (sc->fmmu_configs[j].sync_index == sync_index) {
1168  pdo_xfer = 1;
1169  break;
1170  }
1171  }
1172 
1173  } else {
1174  sync_config = NULL;
1175  size = sync->default_length;
1176  }
1177 
1178  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1179  datagram->data + EC_SYNC_PAGE_SIZE * i);
1180  }
1181 
1182  fsm->retries = EC_FSM_RETRIES;
1184 }
1185 
1186 /*****************************************************************************/
1187 
1191  ec_fsm_slave_config_t *fsm
1192  )
1193 {
1194  ec_datagram_t *datagram = fsm->datagram;
1195  ec_slave_t *slave = fsm->slave;
1196 
1197  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1198  return;
1199 
1200  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1202  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1203  " manager configuration datagram: ");
1204  ec_datagram_print_state(datagram);
1205  return;
1206  }
1207 
1208  if (datagram->working_counter != 1) {
1209  slave->error_flag = 1;
1211  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1212  ec_datagram_print_wc_error(datagram);
1213  return;
1214  }
1215 
1217 }
1218 
1219 /*****************************************************************************/
1220 
1224  ec_fsm_slave_config_t *fsm
1225  )
1226 {
1227  ec_slave_t *slave = fsm->slave;
1228  ec_datagram_t *datagram = fsm->datagram;
1229  unsigned int i;
1230  const ec_fmmu_config_t *fmmu;
1231  const ec_sync_t *sync;
1232 
1233  if (!slave->config) {
1235  return;
1236  }
1237 
1238  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1239  slave->error_flag = 1;
1241  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1242  " than requested (%u).\n", slave->base_fmmu_count,
1243  slave->config->used_fmmus);
1244  return;
1245  }
1246 
1247  if (!slave->base_fmmu_count) { // skip FMMU configuration
1249  return;
1250  }
1251 
1252  // configure FMMUs
1253  ec_datagram_fpwr(datagram, slave->station_address,
1254  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1255  ec_datagram_zero(datagram);
1256  for (i = 0; i < slave->config->used_fmmus; i++) {
1257  fmmu = &slave->config->fmmu_configs[i];
1258  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1259  slave->error_flag = 1;
1261  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1262  " for FMMU!\n");
1263  return;
1264  }
1265  ec_fmmu_config_page(fmmu, sync,
1266  datagram->data + EC_FMMU_PAGE_SIZE * i);
1267  }
1268 
1269  fsm->retries = EC_FSM_RETRIES;
1271 }
1272 
1273 /*****************************************************************************/
1274 
1278  ec_fsm_slave_config_t *fsm
1279  )
1280 {
1281  ec_datagram_t *datagram = fsm->datagram;
1282  ec_slave_t *slave = fsm->slave;
1283 
1284  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1285  return;
1286 
1287  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1289  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1290  ec_datagram_print_state(datagram);
1291  return;
1292  }
1293 
1294  if (datagram->working_counter != 1) {
1295  slave->error_flag = 1;
1297  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1298  ec_datagram_print_wc_error(datagram);
1299  return;
1300  }
1301 
1303 }
1304 
1305 /*****************************************************************************/
1306 
1310  ec_fsm_slave_config_t *fsm
1311  )
1312 {
1313  ec_datagram_t *datagram = fsm->datagram;
1314  ec_slave_t *slave = fsm->slave;
1315  ec_slave_config_t *config = slave->config;
1316 
1317  if (!config) { // config removed in the meantime
1319  return;
1320  }
1321 
1322  if (config->dc_assign_activate) {
1323  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1324  EC_SLAVE_WARN(slave, "Slave seems not to support"
1325  " distributed clocks!\n");
1326  }
1327 
1328  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1329  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1330 
1331  // set DC cycle times
1332  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1333  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1334  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1335  fsm->retries = EC_FSM_RETRIES;
1337  } else {
1338  // DC are unused
1340  }
1341 }
1342 
1343 /*****************************************************************************/
1344 
1348  ec_fsm_slave_config_t *fsm
1349  )
1350 {
1351  ec_datagram_t *datagram = fsm->datagram;
1352  ec_slave_t *slave = fsm->slave;
1353  ec_slave_config_t *config = slave->config;
1354 
1355  if (!config) { // config removed in the meantime
1357  return;
1358  }
1359 
1360  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1361  return;
1362 
1363  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1365  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1366  ec_datagram_print_state(datagram);
1367  return;
1368  }
1369 
1370  if (datagram->working_counter != 1) {
1371  slave->error_flag = 1;
1373  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1374  ec_datagram_print_wc_error(datagram);
1375  return;
1376  }
1377 
1378  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1379 
1380  fsm->jiffies_start = jiffies;
1381  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1382  ec_datagram_zero(datagram);
1383  fsm->retries = EC_FSM_RETRIES;
1385 }
1386 
1387 /*****************************************************************************/
1388 
1392  ec_fsm_slave_config_t *fsm
1393  )
1394 {
1395  ec_datagram_t *datagram = fsm->datagram;
1396  ec_slave_t *slave = fsm->slave;
1397  ec_master_t *master = slave->master;
1398  ec_slave_config_t *config = slave->config;
1399  bool negative;
1400  uint32_t abs_sync_diff;
1401  unsigned long diff_ms;
1402  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1403  ec_sync_signal_t *sync1 = &config->dc_sync[1];
1404  u64 start_time;
1405 
1406  if (!config) { // config removed in the meantime
1408  return;
1409  }
1410 
1411  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1412  return;
1413 
1414  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1416  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1417  ec_datagram_print_state(datagram);
1418  return;
1419  }
1420 
1421  if (datagram->working_counter != 1) {
1422  slave->error_flag = 1;
1424  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1425  ec_datagram_print_wc_error(datagram);
1426  return;
1427  }
1428 
1429  abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1430  negative = (EC_READ_U32(datagram->data) & 0x80000000) != 0;
1431  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1432 
1433  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1434 
1435  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1436  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1437  diff_ms);
1438  } else {
1439  static unsigned long last_diff_ms = 0;
1440  if ((diff_ms < last_diff_ms) || (diff_ms >= (last_diff_ms + 100))) {
1441  last_diff_ms = diff_ms;
1442  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10d ns\n",
1443  diff_ms, negative ? -abs_sync_diff: abs_sync_diff);
1444  }
1445 
1446  // check synchrony again
1447  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1448  ec_datagram_zero(datagram);
1449  fsm->retries = EC_FSM_RETRIES;
1450  return;
1451  }
1452  } else {
1453  EC_SLAVE_DBG(slave, 1, "%d ns difference after %lu ms.\n",
1454  negative ? -abs_sync_diff: abs_sync_diff, diff_ms);
1455  }
1456 
1457  // set DC start time (roughly in the future, not in-phase)
1458  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1459 
1460  if (sync0->cycle_time) {
1461  // find correct phase
1462  if (master->dc_ref_time) {
1463  u64 diff, start;
1464  u32 remainder, cycle;
1465 
1466  diff = start_time - master->dc_ref_time;
1467  cycle = sync0->cycle_time + sync1->cycle_time;
1468  remainder = do_div(diff, cycle);
1469 
1470  start = start_time + cycle - remainder + sync0->shift_time;
1471 
1472  EC_SLAVE_DBG(slave, 1, " ref_time=%llu\n", master->dc_ref_time);
1473  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1474  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1475  EC_SLAVE_DBG(slave, 1, " cycle=%u\n", cycle);
1476  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1477  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1478  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1479  start_time = start;
1480  } else {
1481  EC_SLAVE_WARN(slave, "No application time supplied."
1482  " Cyclic start time will not be in phase.\n");
1483  }
1484  }
1485 
1486  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1487  " start time to %llu.\n", start_time);
1488 
1489  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1490  EC_WRITE_U64(datagram->data, start_time);
1491  fsm->retries = EC_FSM_RETRIES;
1493 }
1494 
1495 /*****************************************************************************/
1496 
1500  ec_fsm_slave_config_t *fsm
1501  )
1502 {
1503  ec_datagram_t *datagram = fsm->datagram;
1504  ec_slave_t *slave = fsm->slave;
1505  ec_slave_config_t *config = slave->config;
1506 
1507  if (!config) { // config removed in the meantime
1509  return;
1510  }
1511 
1512  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1513  return;
1514 
1515  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1517  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1518  ec_datagram_print_state(datagram);
1519  return;
1520  }
1521 
1522  if (datagram->working_counter != 1) {
1523  slave->error_flag = 1;
1525  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1526  ec_datagram_print_wc_error(datagram);
1527  return;
1528  }
1529 
1530  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1531  config->dc_assign_activate);
1532 
1533  // assign sync unit to EtherCAT or PDI
1534  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1535  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1536  fsm->retries = EC_FSM_RETRIES;
1538 }
1539 
1540 /*****************************************************************************/
1541 
1545  ec_fsm_slave_config_t *fsm
1546  )
1547 {
1548  ec_datagram_t *datagram = fsm->datagram;
1549  ec_slave_t *slave = fsm->slave;
1550 
1551  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1552  return;
1553 
1554  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1556  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1557  ec_datagram_print_state(datagram);
1558  return;
1559  }
1560 
1561  if (datagram->working_counter != 1) {
1562  slave->error_flag = 1;
1564  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1565  ec_datagram_print_wc_error(datagram);
1566  return;
1567  }
1568 
1570 }
1571 
1572 /*****************************************************************************/
1573 
1577  ec_fsm_slave_config_t *fsm
1578  )
1579 {
1582  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1583 }
1584 
1585 /*****************************************************************************/
1586 
1590  ec_fsm_slave_config_t *fsm
1591  )
1592 {
1593  ec_slave_t *slave = fsm->slave;
1594 
1595  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1596 
1597  if (!ec_fsm_change_success(fsm->fsm_change)) {
1598  if (!fsm->fsm_change->spontaneous_change)
1599  fsm->slave->error_flag = 1;
1601  return;
1602  }
1603 
1604  // slave is now in SAFEOP
1605 
1606  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1607 
1608  if (fsm->slave->current_state == fsm->slave->requested_state) {
1609  fsm->state = ec_fsm_slave_config_state_end; // successful
1610  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1611  return;
1612  }
1613 
1615 }
1616 
1617 /*****************************************************************************/
1618 
1622  ec_fsm_slave_config_t *fsm
1623  )
1624 {
1625  ec_slave_t *slave = fsm->slave;
1626  ec_soe_request_t *req;
1627 
1628  if (!slave->config) {
1630  return;
1631  }
1632 
1633  list_for_each_entry(req, &slave->config->soe_configs, list) {
1634  if (req->al_state == EC_AL_STATE_SAFEOP) {
1635  // start SoE configuration
1637  fsm->soe_request = req;
1640  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1641  &fsm->soe_request_copy);
1642  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1643  return;
1644  }
1645  }
1646 
1647  // No SoE configuration to be applied in SAFEOP
1649 }
1650 
1651 /*****************************************************************************/
1652 
1656  ec_fsm_slave_config_t *fsm
1657  )
1658 {
1659  ec_slave_t *slave = fsm->slave;
1660 
1661  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1662  return;
1663  }
1664 
1665  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1666  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1667  fsm->slave->error_flag = 1;
1669  return;
1670  }
1671 
1672  if (!fsm->slave->config) { // config removed in the meantime
1674  return;
1675  }
1676 
1677  // Another IDN to configure in SAFEOP?
1678  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1679  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1680  ec_soe_request_t, list);
1681  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1684  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1685  &fsm->soe_request_copy);
1686  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1687  return;
1688  }
1689  }
1690 
1691  // All SAFEOP IDNs are now configured.
1693 }
1694 
1695 /*****************************************************************************/
1696 
1700  ec_fsm_slave_config_t *fsm
1701  )
1702 {
1703  // set state to OP
1706  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1707 }
1708 
1709 /*****************************************************************************/
1710 
1714  ec_fsm_slave_config_t *fsm
1715  )
1716 {
1717  ec_slave_t *slave = fsm->slave;
1718 
1719  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1720 
1721  if (!ec_fsm_change_success(fsm->fsm_change)) {
1722  if (!fsm->fsm_change->spontaneous_change)
1723  slave->error_flag = 1;
1725  return;
1726  }
1727 
1728  // slave is now in OP
1729 
1730  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1731 
1732  fsm->state = ec_fsm_slave_config_state_end; // successful
1733 }
1734 
1735 /*****************************************************************************/
1736 
1740  ec_fsm_slave_config_t *fsm
1741  )
1742 {
1743  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1744  "configuration. Reconfiguring.");
1745 
1746  ec_fsm_slave_config_enter_init(fsm); // reconfigure
1747 }
1748 
1749 /******************************************************************************
1750  * Common state functions
1751  *****************************************************************************/
1752 
1756  ec_fsm_slave_config_t *fsm
1757  )
1758 {
1759 }
1760 
1761 /*****************************************************************************/
1762 
1766  ec_fsm_slave_config_t *fsm
1767  )
1768 {
1769 }
1770 
1771 /*****************************************************************************/
#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:51
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *)
Check for DC to be configured.
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:720
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *)
WATCHDOG entry function.
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
Pre-operational.
Definition: ecrt.h:548
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:146
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:162
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:95
ec_sii_t sii
Extracted SII data.
Definition: slave.h:246
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_start(ec_fsm_slave_config_t *fsm, ec_slave_t *slave)
Start slave configuration state machine.
void ec_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied.
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: PDO_CONF.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:224
FMMU configuration.
Definition: fmmu_config.h:46
ec_sdo_request_t * request
SDO request for SDO configuration.
void ec_fsm_slave_config_state_dc_sync_check(ec_fsm_slave_config_t *)
Slave configuration state: DC SYNC CHECK.
struct list_head list
List item.
Definition: soe_request.h:49
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR DC ASSIGN.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:107
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:188
OP (mailbox communication and input/output update)
Definition: globals.h:138
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *)
Clear the DC assignment.
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:222
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:215
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *)
Slave configuration state: OP.
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:142
Safe-operational.
Definition: ecrt.h:549
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *)
Check for mailbox sync managers to be configured.
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:91
EtherCAT datagram.
Definition: datagram.h:88
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *)
Slave configuration state: DC CYCLE.
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2338
u64 dc_ref_time
Common reference timestamp for DC start times.
Definition: master.h:235
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:134
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *)
Slave configuration state: SYNC.
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:187
void ec_fsm_change_start(ec_fsm_change_t *fsm, ec_slave_t *slave, ec_slave_state_t state)
Starts the change state machine.
Definition: fsm_change.c:90
uint16_t working_counter
Working counter.
Definition: datagram.h:100
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:268
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR SYNC.
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:165
Sent (still in the queue).
Definition: datagram.h:77
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_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
uint16_t station_address
Configured station address.
Definition: slave.h:207
unsigned int sync_count
Number of sync managers.
Definition: slave.h:189
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:167
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:94
Global definitions and macros.
uint16_t std_tx_mailbox_offset
Standard transmit mailbox address.
Definition: slave.h:168
EtherCAT master structure.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:141
SAFEOP (mailbox communication and input update)
Definition: globals.h:136
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:144
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG.
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:164
void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_ETHERCAT.
EtherCAT slave.
Definition: slave.h:199
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *)
Check for FMMUs to be configured.
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
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
void ec_fsm_soe_transfer(ec_fsm_soe_t *fsm, ec_slave_t *slave, ec_soe_request_t *request)
Starts to transfer an IDN to/from a slave.
Definition: fsm_soe.c:130
int ec_fsm_soe_success(const ec_fsm_soe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_soe.c:187
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:139
ec_datagram_state_t state
State.
Definition: datagram.h:101
ec_slave_config_t * config
Current configuration.
Definition: slave.h:213
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2372
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
Slave configutation feature flag.
Definition: flag.h:38
void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *)
Configure PDO sync managers.
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:170
ec_flag_t * ec_slave_config_find_flag(ec_slave_config_t *sc, const char *key)
Finds a flag.
Definition: slave_config.c:650
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *)
State: ERROR.
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:77
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:606
#define EC_DC_START_OFFSET
Time offset (in ns), that is added to cyclic start time.
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *)
Start state change to INIT.
Sync manager.
Definition: sync.h:47
uint16_t std_rx_mailbox_offset
Standard receive mailbox address.
Definition: slave.h:166
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:124
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR FMMU.
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:143
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:2355
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:230
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:218
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SAFEOP.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2266
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *)
Check for PDO sync managers to be configured.
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:131
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
ec_master_t * master
Master owning the slave.
Definition: slave.h:201
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(* 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:299
void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *)
Assign SII to PDI.
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:235
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:274
uint8_t control_register
Control register value.
Definition: sync.h:51
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *)
Bring slave to OP.
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:129
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_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
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:190
INIT state (no mailbox communication, no IO)
Definition: globals.h:130
int ec_fsm_pdo_success(const ec_fsm_pdo_t *fsm)
Get execution result.
Definition: fsm_pdo.c:180
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: SDO_CONF.
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:566
void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *)
Slave configuration state: ASSIGN_PDI.
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:436
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:2389
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:163
ec_soe_request_t soe_request_copy
Copied SDO request.
Sync manager configuration.
Definition: sync_config.h:46
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:49
EtherCAT slave sync signal configuration.
Definition: globals.h:186
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
Queued for sending.
Definition: datagram.h:76
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *)
Slave configuration state: START.
Timed out (dequeued).
Definition: datagram.h:79
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *)
Request PREOP state.
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:234
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:250
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *)
State: END.
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:220
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:233
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *)
WATCHDOG_DIVIDER entry function.
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *)
Slave configuration state: BOOT/PREOP.
uint8_t * data
Datagram payload.
Definition: datagram.h:95
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:231
EtherCAT slave configuration.
Definition: slave_config.h:119
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied in SAFEOP.
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
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.
int ec_fsm_soe_exec(ec_fsm_soe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_soe.c:152
void ec_fsm_coe_transfer(ec_fsm_coe_t *fsm, ec_slave_t *slave, ec_sdo_request_t *request)
Starts to transfer an SDO to/from a slave.
Definition: fsm_coe.c:212
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *)
Slave configuration state: DC ASSIGN.
uint16_t default_length
Data length in bytes.
Definition: sync.h:50
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *)
Slave configuration state: DC START.
PREOP state (mailbox communication, no IO)
Definition: globals.h:132
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *)
Reconfigure the slave starting at INIT.
Received (dequeued).
Definition: datagram.h:78
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *)
Request SAFEOP state.
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:216
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:188
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:169
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *)
Check for SDO configurations to be applied.
EtherCAT master.
Definition: master.h:189
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:214
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:101
void ec_sync_init(ec_sync_t *sync, ec_slave_t *slave)
Constructor.
Definition: sync.c:46
void ecrt_sdo_request_write(ec_sdo_request_t *req)
Schedule an SDO write operation.
Definition: sdo_request.c:235
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *)
Slave configuration state: INIT.
#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
EtherCAT state change FSM.
Definition: fsm_change.h:64
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
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:139
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:712
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG_DIVIDER.
unsigned int retries
Retries on datagram timeout.