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 
70 #ifdef EC_SII_ASSIGN
71 void ec_fsm_slave_config_state_assign_pdi(ec_fsm_slave_config_t *);
72 #endif
74 #ifdef EC_SII_ASSIGN
75 void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *);
76 #endif
91 
96 #ifdef EC_SII_ASSIGN
97 void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *);
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 
277 /*****************************************************************************/
278 
283  )
284 {
285  ec_datagram_t *datagram = fsm->datagram;
286 
287  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
288  return;
289 
290  if (datagram->state != EC_DATAGRAM_RECEIVED) {
292  EC_SLAVE_ERR(fsm->slave, "Failed receive FMMU clearing datagram.\n");
293  return;
294  }
295 
296  if (datagram->working_counter != 1) {
297  fsm->slave->error_flag = 1;
299  EC_SLAVE_ERR(fsm->slave, "Failed to clear FMMUs: ");
300  ec_datagram_print_wc_error(datagram);
301  return;
302  }
303 
305 }
306 
307 /*****************************************************************************/
308 
313  )
314 {
315  ec_slave_t *slave = fsm->slave;
316  ec_datagram_t *datagram = fsm->datagram;
317  size_t sync_size;
318 
319  if (!slave->base_sync_count) {
320  // no sync managers
322  return;
323  }
324 
325  EC_SLAVE_DBG(slave, 1, "Clearing sync manager configurations...\n");
326 
327  sync_size = EC_SYNC_PAGE_SIZE * slave->base_sync_count;
328 
329  // clear sync manager configurations
330  ec_datagram_fpwr(datagram, slave->station_address, 0x0800, sync_size);
331  ec_datagram_zero(datagram);
332  fsm->retries = EC_FSM_RETRIES;
334 }
335 
336 /*****************************************************************************/
337 
342  )
343 {
344  ec_datagram_t *datagram = fsm->datagram;
345 
346  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
347  return;
348 
349  if (datagram->state != EC_DATAGRAM_RECEIVED) {
351  EC_SLAVE_ERR(fsm->slave, "Failed receive sync manager"
352  " clearing datagram.\n");
353  return;
354  }
355 
356  if (datagram->working_counter != 1) {
357  fsm->slave->error_flag = 1;
359  EC_SLAVE_ERR(fsm->slave,
360  "Failed to clear sync manager configurations: ");
361  ec_datagram_print_wc_error(datagram);
362  return;
363  }
364 
366 }
367 
368 /*****************************************************************************/
369 
374  )
375 {
376  ec_slave_t *slave = fsm->slave;
377  ec_datagram_t *datagram = fsm->datagram;
378 
379  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
381  return;
382  }
383 
384  EC_SLAVE_DBG(slave, 1, "Clearing DC assignment...\n");
385 
386  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
387  ec_datagram_zero(datagram);
388  fsm->retries = EC_FSM_RETRIES;
390 }
391 
392 /*****************************************************************************/
393 
398  )
399 {
400  ec_datagram_t *datagram = fsm->datagram;
401 
402  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
403  return;
404 
405  if (datagram->state != EC_DATAGRAM_RECEIVED) {
407  EC_SLAVE_ERR(fsm->slave, "Failed receive DC assignment"
408  " clearing datagram.\n");
409  return;
410  }
411 
412  if (datagram->working_counter != 1) {
413  // clearing the DC assignment does not succeed on simple slaves
414  EC_SLAVE_DBG(fsm->slave, 1, "Failed to clear DC assignment: ");
415  ec_datagram_print_wc_error(datagram);
416  }
417 
419 }
420 
421 /*****************************************************************************/
422 
427  )
428 {
429  ec_slave_t *slave = fsm->slave;
430  ec_datagram_t *datagram = fsm->datagram;
431  unsigned int i;
432 
433  // slave is now in INIT
434  if (slave->current_state == slave->requested_state) {
435  fsm->state = ec_fsm_slave_config_state_end; // successful
436  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
437  return;
438  }
439 
440  if (!slave->sii.mailbox_protocols) {
441  // no mailbox protocols supported
442  EC_SLAVE_DBG(slave, 1, "Slave does not support"
443  " mailbox communication.\n");
444 #ifdef EC_SII_ASSIGN
445  ec_fsm_slave_config_enter_assign_pdi(fsm);
446 #else
448 #endif
449  return;
450  }
451 
452  EC_SLAVE_DBG(slave, 1, "Configuring mailbox sync managers...\n");
453 
454  if (slave->requested_state == EC_SLAVE_STATE_BOOT) {
455  ec_sync_t sync;
456 
457  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
458  EC_SYNC_PAGE_SIZE * 2);
459  ec_datagram_zero(datagram);
460 
461  ec_sync_init(&sync, slave);
463  sync.control_register = 0x26;
464  sync.enable = 1;
465  ec_sync_page(&sync, 0, slave->sii.boot_rx_mailbox_size,
466  EC_DIR_INVALID, // use default direction
467  0, // no PDO xfer
468  datagram->data);
472  slave->sii.boot_rx_mailbox_size;
473 
474  ec_sync_init(&sync, slave);
476  sync.control_register = 0x22;
477  sync.enable = 1;
478  ec_sync_page(&sync, 1, slave->sii.boot_tx_mailbox_size,
479  EC_DIR_INVALID, // use default direction
480  0, // no PDO xfer
481  datagram->data + EC_SYNC_PAGE_SIZE);
485  slave->sii.boot_tx_mailbox_size;
486 
487  } else if (slave->sii.sync_count >= 2) { // mailbox configuration provided
488  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
489  EC_SYNC_PAGE_SIZE * slave->sii.sync_count);
490  ec_datagram_zero(datagram);
491 
492  for (i = 0; i < 2; i++) {
493  ec_sync_page(&slave->sii.syncs[i], i,
494  slave->sii.syncs[i].default_length,
495  NULL, // use default sync manager configuration
496  0, // no PDO xfer
497  datagram->data + EC_SYNC_PAGE_SIZE * i);
498  }
499 
501  slave->sii.syncs[0].physical_start_address;
503  slave->sii.syncs[0].default_length;
505  slave->sii.syncs[1].physical_start_address;
507  slave->sii.syncs[1].default_length;
508  } else { // no mailbox sync manager configurations provided
509  ec_sync_t sync;
510 
511  EC_SLAVE_DBG(slave, 1, "Slave does not provide"
512  " mailbox sync manager configurations.\n");
513 
514  ec_datagram_fpwr(datagram, slave->station_address, 0x0800,
515  EC_SYNC_PAGE_SIZE * 2);
516  ec_datagram_zero(datagram);
517 
518  ec_sync_init(&sync, slave);
520  sync.control_register = 0x26;
521  sync.enable = 1;
522  ec_sync_page(&sync, 0, slave->sii.std_rx_mailbox_size,
523  NULL, // use default sync manager configuration
524  0, // no PDO xfer
525  datagram->data);
527  slave->sii.std_rx_mailbox_offset;
529  slave->sii.std_rx_mailbox_size;
530 
531  ec_sync_init(&sync, slave);
533  sync.control_register = 0x22;
534  sync.enable = 1;
535  ec_sync_page(&sync, 1, slave->sii.std_tx_mailbox_size,
536  NULL, // use default sync manager configuration
537  0, // no PDO xfer
538  datagram->data + EC_SYNC_PAGE_SIZE);
540  slave->sii.std_tx_mailbox_offset;
542  slave->sii.std_tx_mailbox_size;
543  }
544 
545  fsm->take_time = 1;
546 
547  fsm->retries = EC_FSM_RETRIES;
549 }
550 
551 /*****************************************************************************/
552 
559  )
560 {
561  ec_datagram_t *datagram = fsm->datagram;
562  ec_slave_t *slave = fsm->slave;
563 
564  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
565  return;
566 
567  if (datagram->state != EC_DATAGRAM_RECEIVED) {
569  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
570  " configuration datagram: ");
571  ec_datagram_print_state(datagram);
572  return;
573  }
574 
575  if (fsm->take_time) {
576  fsm->take_time = 0;
577  fsm->jiffies_start = datagram->jiffies_sent;
578  }
579 
580  /* Because the sync manager configurations are cleared during the last
581  * cycle, some slaves do not immediately respond to the mailbox sync
582  * manager configuration datagram. Therefore, resend the datagram for
583  * a certain time, if the slave does not respond.
584  */
585  if (datagram->working_counter == 0) {
586  unsigned long diff = datagram->jiffies_received - fsm->jiffies_start;
587 
588  if (diff >= HZ) {
589  slave->error_flag = 1;
591  EC_SLAVE_ERR(slave, "Timeout while configuring"
592  " mailbox sync managers.\n");
593  return;
594  } else {
595  EC_SLAVE_DBG(slave, 1, "Resending after %u ms...\n",
596  (unsigned int) diff * 1000 / HZ);
597  }
598 
599  // send configuration datagram again
600  fsm->retries = EC_FSM_RETRIES;
601  return;
602  }
603  else if (datagram->working_counter != 1) {
604  slave->error_flag = 1;
606  EC_SLAVE_ERR(slave, "Failed to set sync managers: ");
607  ec_datagram_print_wc_error(datagram);
608  return;
609  }
610 
611 #ifdef EC_SII_ASSIGN
612  ec_fsm_slave_config_enter_assign_pdi(fsm);
613 #else
615 #endif
616 }
617 
618 /*****************************************************************************/
619 
620 #ifdef EC_SII_ASSIGN
621 
624 void ec_fsm_slave_config_enter_assign_pdi(
626  )
627 {
628  ec_datagram_t *datagram = fsm->datagram;
629  ec_slave_t *slave = fsm->slave;
630 
632  EC_SLAVE_DBG(slave, 1, "Assigning SII access to PDI.\n");
633 
634  ec_datagram_fpwr(datagram, slave->station_address, 0x0500, 0x01);
635  EC_WRITE_U8(datagram->data, 0x01); // PDI
636  fsm->retries = EC_FSM_RETRIES;
637  fsm->state = ec_fsm_slave_config_state_assign_pdi;
638  }
639  else {
641  }
642 }
643 
644 /*****************************************************************************/
645 
648 void ec_fsm_slave_config_state_assign_pdi(
650  )
651 {
652  ec_datagram_t *datagram = fsm->datagram;
653  ec_slave_t *slave = fsm->slave;
654 
655  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
656  return;
657  }
658 
659  if (datagram->state != EC_DATAGRAM_RECEIVED) {
660  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
661  ec_datagram_print_state(datagram);
662  goto cont_preop;
663  }
664 
665  if (datagram->working_counter != 1) {
666  EC_SLAVE_WARN(slave, "Failed to assign SII to PDI: ");
667  ec_datagram_print_wc_error(datagram);
668  }
669 
670 cont_preop:
672 }
673 
674 #endif
675 
676 /*****************************************************************************/
677 
682  )
683 {
685 
689  } else { // BOOT
691  fsm->slave, EC_SLAVE_STATE_BOOT);
692  }
693 
694  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
695 }
696 
697 /*****************************************************************************/
698 
703  )
704 {
705  ec_slave_t *slave = fsm->slave;
706 
707  if (ec_fsm_change_exec(fsm->fsm_change)) {
708  return;
709  }
710 
711  if (!ec_fsm_change_success(fsm->fsm_change)) {
712  if (!fsm->fsm_change->spontaneous_change)
713  slave->error_flag = 1;
715  return;
716  }
717 
718  // slave is now in BOOT or PREOP
719  slave->jiffies_preop = fsm->datagram->jiffies_received;
720 
721  EC_SLAVE_DBG(slave, 1, "Now in %s.\n",
722  slave->requested_state != EC_SLAVE_STATE_BOOT ? "PREOP" : "BOOT");
723 
724 #ifdef EC_SII_ASSIGN
725  EC_SLAVE_DBG(slave, 1, "Assigning SII access back to EtherCAT.\n");
726 
727  ec_datagram_fpwr(fsm->datagram, slave->station_address, 0x0500, 0x01);
728  EC_WRITE_U8(fsm->datagram->data, 0x00); // EtherCAT
729  fsm->retries = EC_FSM_RETRIES;
730  fsm->state = ec_fsm_slave_config_state_assign_ethercat;
731 #else
732  if (slave->current_state == slave->requested_state) {
733  fsm->state = ec_fsm_slave_config_state_end; // successful
734  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
735  return;
736  }
737 
739 #endif
740 }
741 
742 /*****************************************************************************/
743 
744 #ifdef EC_SII_ASSIGN
745 
748 void ec_fsm_slave_config_state_assign_ethercat(
750  )
751 {
752  ec_datagram_t *datagram = fsm->datagram;
753  ec_slave_t *slave = fsm->slave;
754 
755  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
756  return;
757  }
758 
759  if (datagram->state != EC_DATAGRAM_RECEIVED) {
760  EC_SLAVE_WARN(slave, "Failed receive SII assignment datagram: ");
761  ec_datagram_print_state(datagram);
762  goto cont_sdo_conf;
763  }
764 
765  if (datagram->working_counter != 1) {
766  EC_SLAVE_WARN(slave, "Failed to assign SII back to EtherCAT: ");
767  ec_datagram_print_wc_error(datagram);
768  }
769 
770 cont_sdo_conf:
771  if (slave->current_state == slave->requested_state) {
772  fsm->state = ec_fsm_slave_config_state_end; // successful
773  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
774  return;
775  }
776 
778 }
779 
780 #endif
781 
782 /*****************************************************************************/
783 
788  )
789 {
790  ec_slave_t *slave = fsm->slave;
791 
792  if (!slave->config) {
794  return;
795  }
796 
797  // No CoE configuration to be applied?
798  if (list_empty(&slave->config->sdo_configs)) { // skip SDO configuration
800  return;
801  }
802 
803  // start SDO configuration
805  fsm->request = list_entry(fsm->slave->config->sdo_configs.next,
806  ec_sdo_request_t, list);
809  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
810  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
811 }
812 
813 /*****************************************************************************/
814 
819  )
820 {
821  if (ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram)) {
822  return;
823  }
824 
825  if (!ec_fsm_coe_success(fsm->fsm_coe)) {
826  EC_SLAVE_ERR(fsm->slave, "SDO configuration failed.\n");
827  fsm->slave->error_flag = 1;
829  return;
830  }
831 
832  if (!fsm->slave->config) { // config removed in the meantime
834  return;
835  }
836 
837  // Another SDO to configure?
838  if (fsm->request->list.next != &fsm->slave->config->sdo_configs) {
839  fsm->request = list_entry(fsm->request->list.next,
840  ec_sdo_request_t, list);
843  ec_fsm_coe_transfer(fsm->fsm_coe, fsm->slave, &fsm->request_copy);
844  ec_fsm_coe_exec(fsm->fsm_coe, fsm->datagram); // execute immediately
845  return;
846  }
847 
848  // All SDOs are now configured.
850 }
851 
852 /*****************************************************************************/
853 
858  )
859 {
860  ec_slave_t *slave = fsm->slave;
861  ec_soe_request_t *req;
862 
863  if (!slave->config) {
865  return;
866  }
867 
868  list_for_each_entry(req, &slave->config->soe_configs, list) {
869  if (req->al_state == EC_AL_STATE_PREOP) {
870  // start SoE configuration
872  fsm->soe_request = req;
875  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
876  &fsm->soe_request_copy);
877  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
878  return;
879  }
880  }
881 
882  // No SoE configuration to be applied in PREOP
884 }
885 
886 /*****************************************************************************/
887 
892  )
893 {
894  ec_slave_t *slave = fsm->slave;
895 
896  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
897  return;
898  }
899 
900  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
901  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
902  fsm->slave->error_flag = 1;
904  return;
905  }
906 
907  if (!fsm->slave->config) { // config removed in the meantime
909  return;
910  }
911 
912  // Another IDN to configure in PREOP?
913  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
914  fsm->soe_request = list_entry(fsm->soe_request->list.next,
915  ec_soe_request_t, list);
916  if (fsm->soe_request->al_state == EC_AL_STATE_PREOP) {
919  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
920  &fsm->soe_request_copy);
921  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
922  return;
923  }
924  }
925 
926  // All PREOP IDNs are now configured.
928 }
929 
930 /*****************************************************************************/
931 
936  )
937 {
938  // Start configuring PDOs
941  fsm->state(fsm); // execute immediately
942 }
943 
944 /*****************************************************************************/
945 
950  )
951 {
952  // TODO check for config here
953 
954  if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
955  return;
956  }
957 
958  if (!fsm->slave->config) { // config removed in the meantime
960  return;
961  }
962 
963  if (!ec_fsm_pdo_success(fsm->fsm_pdo)) {
964  EC_SLAVE_WARN(fsm->slave, "PDO configuration failed.\n");
965  }
966 
968 }
969 
970 /*****************************************************************************/
971 
976  )
977 {
978  ec_slave_t *slave = fsm->slave;
979  ec_datagram_t *datagram = fsm->datagram;
980  ec_slave_config_t *config = slave->config;
981 
982  if (config && config->watchdog_divider) {
983  EC_SLAVE_DBG(slave, 1, "Setting watchdog divider to %u.\n",
984  config->watchdog_divider);
985 
986  ec_datagram_fpwr(datagram, slave->station_address, 0x0400, 2);
987  EC_WRITE_U16(datagram->data, config->watchdog_divider);
988  fsm->retries = EC_FSM_RETRIES;
990  } else {
992  }
993 }
994 
995 /*****************************************************************************/
996 
1000  ec_fsm_slave_config_t *fsm
1001  )
1002 {
1003  ec_datagram_t *datagram = fsm->datagram;
1004  ec_slave_t *slave = fsm->slave;
1005 
1006  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1007  return;
1008 
1009  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1011  EC_SLAVE_ERR(slave, "Failed to receive watchdog divider"
1012  " configuration datagram: ");
1013  ec_datagram_print_state(datagram);
1014  return;
1015  }
1016 
1017  if (datagram->working_counter != 1) {
1018  slave->error_flag = 1;
1019  EC_SLAVE_WARN(slave, "Failed to set watchdog divider: ");
1020  ec_datagram_print_wc_error(datagram);
1021  return;
1022  }
1023 
1025 }
1026 
1027 /*****************************************************************************/
1028 
1032  ec_fsm_slave_config_t *fsm
1033  )
1034 {
1035  ec_datagram_t *datagram = fsm->datagram;
1036  ec_slave_t *slave = fsm->slave;
1037  ec_slave_config_t *config = slave->config;
1038 
1039  if (config && config->watchdog_intervals) {
1040  EC_SLAVE_DBG(slave, 1, "Setting process data"
1041  " watchdog intervals to %u.\n", config->watchdog_intervals);
1042 
1043  ec_datagram_fpwr(datagram, slave->station_address, 0x0420, 2);
1044  EC_WRITE_U16(datagram->data, config->watchdog_intervals);
1045 
1046  fsm->retries = EC_FSM_RETRIES;
1048  } else {
1050  }
1051 }
1052 
1053 /*****************************************************************************/
1054 
1059  ec_fsm_slave_config_t *fsm
1060  )
1061 {
1062  ec_datagram_t *datagram = fsm->datagram;
1063  ec_slave_t *slave = fsm->slave;
1064 
1065  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1066  return;
1067 
1068  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1070  EC_SLAVE_ERR(slave, "Failed to receive sync manager"
1071  " watchdog configuration datagram: ");
1072  ec_datagram_print_state(datagram);
1073  return;
1074  }
1075 
1076  if (datagram->working_counter != 1) {
1077  EC_SLAVE_WARN(slave, "Failed to set process data"
1078  " watchdog intervals: ");
1079  ec_datagram_print_wc_error(datagram);
1080  }
1081 
1083 }
1084 
1085 /*****************************************************************************/
1086 
1090  ec_fsm_slave_config_t *fsm
1091  )
1092 {
1093  ec_slave_t *slave = fsm->slave;
1094  ec_datagram_t *datagram = fsm->datagram;
1095  unsigned int i, j, offset, num_pdo_syncs;
1096  uint8_t sync_index;
1097  const ec_sync_t *sync;
1098  uint16_t size;
1099 
1100  if (slave->sii.mailbox_protocols) {
1101  offset = 2; // slave has mailboxes
1102  } else {
1103  offset = 0;
1104  }
1105 
1106  if (slave->sii.sync_count <= offset) {
1107  // no PDO sync managers to configure
1109  return;
1110  }
1111 
1112  num_pdo_syncs = slave->sii.sync_count - offset;
1113 
1114  // configure sync managers for process data
1115  ec_datagram_fpwr(datagram, slave->station_address,
1116  0x0800 + EC_SYNC_PAGE_SIZE * offset,
1117  EC_SYNC_PAGE_SIZE * num_pdo_syncs);
1118  ec_datagram_zero(datagram);
1119 
1120  for (i = 0; i < num_pdo_syncs; i++) {
1121  const ec_sync_config_t *sync_config;
1122  uint8_t pdo_xfer = 0;
1123  sync_index = i + offset;
1124  sync = &slave->sii.syncs[sync_index];
1125 
1126  if (slave->config) {
1127  const ec_slave_config_t *sc = slave->config;
1128  sync_config = &sc->sync_configs[sync_index];
1129  size = ec_pdo_list_total_size(&sync_config->pdos);
1130 
1131  // determine, if PDOs shall be transferred via this SM
1132  // inthat case, enable sync manager in every case
1133  for (j = 0; j < sc->used_fmmus; j++) {
1134  if (sc->fmmu_configs[j].sync_index == sync_index) {
1135  pdo_xfer = 1;
1136  break;
1137  }
1138  }
1139 
1140  } else {
1141  sync_config = NULL;
1142  size = sync->default_length;
1143  }
1144 
1145  ec_sync_page(sync, sync_index, size, sync_config, pdo_xfer,
1146  datagram->data + EC_SYNC_PAGE_SIZE * i);
1147  }
1148 
1149  fsm->retries = EC_FSM_RETRIES;
1151 }
1152 
1153 /*****************************************************************************/
1154 
1158  ec_fsm_slave_config_t *fsm
1159  )
1160 {
1161  ec_datagram_t *datagram = fsm->datagram;
1162  ec_slave_t *slave = fsm->slave;
1163 
1164  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1165  return;
1166 
1167  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1169  EC_SLAVE_ERR(slave, "Failed to receive process data sync"
1170  " manager configuration datagram: ");
1171  ec_datagram_print_state(datagram);
1172  return;
1173  }
1174 
1175  if (datagram->working_counter != 1) {
1176  slave->error_flag = 1;
1178  EC_SLAVE_ERR(slave, "Failed to set process data sync managers: ");
1179  ec_datagram_print_wc_error(datagram);
1180  return;
1181  }
1182 
1184 }
1185 
1186 /*****************************************************************************/
1187 
1191  ec_fsm_slave_config_t *fsm
1192  )
1193 {
1194  ec_slave_t *slave = fsm->slave;
1195  ec_datagram_t *datagram = fsm->datagram;
1196  unsigned int i;
1197  const ec_fmmu_config_t *fmmu;
1198  const ec_sync_t *sync;
1199 
1200  if (!slave->config) {
1202  return;
1203  }
1204 
1205  if (slave->base_fmmu_count < slave->config->used_fmmus) {
1206  slave->error_flag = 1;
1208  EC_SLAVE_ERR(slave, "Slave has less FMMUs (%u)"
1209  " than requested (%u).\n", slave->base_fmmu_count,
1210  slave->config->used_fmmus);
1211  return;
1212  }
1213 
1214  if (!slave->base_fmmu_count) { // skip FMMU configuration
1216  return;
1217  }
1218 
1219  // configure FMMUs
1220  ec_datagram_fpwr(datagram, slave->station_address,
1221  0x0600, EC_FMMU_PAGE_SIZE * slave->base_fmmu_count);
1222  ec_datagram_zero(datagram);
1223  for (i = 0; i < slave->config->used_fmmus; i++) {
1224  fmmu = &slave->config->fmmu_configs[i];
1225  if (!(sync = ec_slave_get_sync(slave, fmmu->sync_index))) {
1226  slave->error_flag = 1;
1228  EC_SLAVE_ERR(slave, "Failed to determine PDO sync manager"
1229  " for FMMU!\n");
1230  return;
1231  }
1232  ec_fmmu_config_page(fmmu, sync,
1233  datagram->data + EC_FMMU_PAGE_SIZE * i);
1234  }
1235 
1236  fsm->retries = EC_FSM_RETRIES;
1238 }
1239 
1240 /*****************************************************************************/
1241 
1245  ec_fsm_slave_config_t *fsm
1246  )
1247 {
1248  ec_datagram_t *datagram = fsm->datagram;
1249  ec_slave_t *slave = fsm->slave;
1250 
1251  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1252  return;
1253 
1254  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1256  EC_SLAVE_ERR(slave, "Failed to receive FMMUs datagram: ");
1257  ec_datagram_print_state(datagram);
1258  return;
1259  }
1260 
1261  if (datagram->working_counter != 1) {
1262  slave->error_flag = 1;
1264  EC_SLAVE_ERR(slave, "Failed to set FMMUs: ");
1265  ec_datagram_print_wc_error(datagram);
1266  return;
1267  }
1268 
1270 }
1271 
1272 /*****************************************************************************/
1273 
1277  ec_fsm_slave_config_t *fsm
1278  )
1279 {
1280  ec_datagram_t *datagram = fsm->datagram;
1281  ec_slave_t *slave = fsm->slave;
1282  ec_slave_config_t *config = slave->config;
1283 
1284  if (!config) { // config removed in the meantime
1286  return;
1287  }
1288 
1289  if (config->dc_assign_activate) {
1290  if (!slave->base_dc_supported || !slave->has_dc_system_time) {
1291  EC_SLAVE_WARN(slave, "Slave seems not to support"
1292  " distributed clocks!\n");
1293  }
1294 
1295  EC_SLAVE_DBG(slave, 1, "Setting DC cycle times to %u / %u.\n",
1296  config->dc_sync[0].cycle_time, config->dc_sync[1].cycle_time);
1297 
1298  // set DC cycle times
1299  ec_datagram_fpwr(datagram, slave->station_address, 0x09A0, 8);
1300  EC_WRITE_U32(datagram->data, config->dc_sync[0].cycle_time);
1301  EC_WRITE_U32(datagram->data + 4, config->dc_sync[1].cycle_time);
1302  fsm->retries = EC_FSM_RETRIES;
1304  } else {
1305  // DC are unused
1307  }
1308 }
1309 
1310 /*****************************************************************************/
1311 
1315  ec_fsm_slave_config_t *fsm
1316  )
1317 {
1318  ec_datagram_t *datagram = fsm->datagram;
1319  ec_slave_t *slave = fsm->slave;
1320  ec_slave_config_t *config = slave->config;
1321 
1322  if (!config) { // config removed in the meantime
1324  return;
1325  }
1326 
1327  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1328  return;
1329 
1330  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1332  EC_SLAVE_ERR(slave, "Failed to receive DC cycle times datagram: ");
1333  ec_datagram_print_state(datagram);
1334  return;
1335  }
1336 
1337  if (datagram->working_counter != 1) {
1338  slave->error_flag = 1;
1340  EC_SLAVE_ERR(slave, "Failed to set DC cycle times: ");
1341  ec_datagram_print_wc_error(datagram);
1342  return;
1343  }
1344 
1345  EC_SLAVE_DBG(slave, 1, "Checking for synchrony.\n");
1346 
1347  fsm->jiffies_start = jiffies;
1348  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1349  fsm->retries = EC_FSM_RETRIES;
1351 }
1352 
1353 /*****************************************************************************/
1354 
1358  ec_fsm_slave_config_t *fsm
1359  )
1360 {
1361  ec_datagram_t *datagram = fsm->datagram;
1362  ec_slave_t *slave = fsm->slave;
1363  ec_master_t *master = slave->master;
1364  ec_slave_config_t *config = slave->config;
1365  uint32_t abs_sync_diff;
1366  unsigned long diff_ms;
1367  ec_sync_signal_t *sync0 = &config->dc_sync[0];
1368  u64 start_time;
1369 
1370  if (!config) { // config removed in the meantime
1372  return;
1373  }
1374 
1375  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1376  return;
1377 
1378  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1380  EC_SLAVE_ERR(slave, "Failed to receive DC sync check datagram: ");
1381  ec_datagram_print_state(datagram);
1382  return;
1383  }
1384 
1385  if (datagram->working_counter != 1) {
1386  slave->error_flag = 1;
1388  EC_SLAVE_ERR(slave, "Failed to check DC synchrony: ");
1389  ec_datagram_print_wc_error(datagram);
1390  return;
1391  }
1392 
1393  abs_sync_diff = EC_READ_U32(datagram->data) & 0x7fffffff;
1394  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
1395 
1396  if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
1397 
1398  if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
1399  EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
1400  diff_ms);
1401  } else {
1402  EC_SLAVE_DBG(slave, 1, "Sync after %4lu ms: %10u ns\n",
1403  diff_ms, abs_sync_diff);
1404 
1405  // check synchrony again
1406  ec_datagram_fprd(datagram, slave->station_address, 0x092c, 4);
1407  fsm->retries = EC_FSM_RETRIES;
1408  return;
1409  }
1410  } else {
1411  EC_SLAVE_DBG(slave, 1, "%u ns difference after %lu ms.\n",
1412  abs_sync_diff, diff_ms);
1413  }
1414 
1415  // set DC start time
1416  start_time = master->app_time + EC_DC_START_OFFSET; // now + X ns
1417  // FIXME use slave's local system time here?
1418 
1419  if (sync0->cycle_time) {
1420  // find correct phase
1421  if (master->has_app_time) {
1422  u64 diff, start;
1423  u32 remainder;
1424 
1425  diff = start_time - master->app_start_time;
1426  remainder = do_div(diff, sync0->cycle_time);
1427 
1428  start = start_time +
1429  sync0->cycle_time - remainder + sync0->shift_time;
1430 
1431  EC_SLAVE_DBG(slave, 1, "app_start_time=%llu\n",
1432  master->app_start_time);
1433  EC_SLAVE_DBG(slave, 1, " app_time=%llu\n", master->app_time);
1434  EC_SLAVE_DBG(slave, 1, " start_time=%llu\n", start_time);
1435  EC_SLAVE_DBG(slave, 1, " cycle_time=%u\n", sync0->cycle_time);
1436  EC_SLAVE_DBG(slave, 1, " shift_time=%i\n", sync0->shift_time);
1437  EC_SLAVE_DBG(slave, 1, " remainder=%u\n", remainder);
1438  EC_SLAVE_DBG(slave, 1, " start=%llu\n", start);
1439  start_time = start;
1440  } else {
1441  EC_SLAVE_WARN(slave, "No application time supplied."
1442  " Cyclic start time will not be in phase.\n");
1443  }
1444  }
1445 
1446  EC_SLAVE_DBG(slave, 1, "Setting DC cyclic operation"
1447  " start time to %llu.\n", start_time);
1448 
1449  ec_datagram_fpwr(datagram, slave->station_address, 0x0990, 8);
1450  EC_WRITE_U64(datagram->data, start_time);
1451  fsm->retries = EC_FSM_RETRIES;
1453 }
1454 
1455 /*****************************************************************************/
1456 
1460  ec_fsm_slave_config_t *fsm
1461  )
1462 {
1463  ec_datagram_t *datagram = fsm->datagram;
1464  ec_slave_t *slave = fsm->slave;
1465  ec_slave_config_t *config = slave->config;
1466 
1467  if (!config) { // config removed in the meantime
1469  return;
1470  }
1471 
1472  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1473  return;
1474 
1475  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1477  EC_SLAVE_ERR(slave, "Failed to receive DC start time datagram: ");
1478  ec_datagram_print_state(datagram);
1479  return;
1480  }
1481 
1482  if (datagram->working_counter != 1) {
1483  slave->error_flag = 1;
1485  EC_SLAVE_ERR(slave, "Failed to set DC start time: ");
1486  ec_datagram_print_wc_error(datagram);
1487  return;
1488  }
1489 
1490  EC_SLAVE_DBG(slave, 1, "Setting DC AssignActivate to 0x%04x.\n",
1491  config->dc_assign_activate);
1492 
1493  // assign sync unit to EtherCAT or PDI
1494  ec_datagram_fpwr(datagram, slave->station_address, 0x0980, 2);
1495  EC_WRITE_U16(datagram->data, config->dc_assign_activate);
1496  fsm->retries = EC_FSM_RETRIES;
1498 }
1499 
1500 /*****************************************************************************/
1501 
1505  ec_fsm_slave_config_t *fsm
1506  )
1507 {
1508  ec_datagram_t *datagram = fsm->datagram;
1509  ec_slave_t *slave = fsm->slave;
1510 
1511  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
1512  return;
1513 
1514  if (datagram->state != EC_DATAGRAM_RECEIVED) {
1516  EC_SLAVE_ERR(slave, "Failed to receive DC activation datagram: ");
1517  ec_datagram_print_state(datagram);
1518  return;
1519  }
1520 
1521  if (datagram->working_counter != 1) {
1522  slave->error_flag = 1;
1524  EC_SLAVE_ERR(slave, "Failed to activate DC: ");
1525  ec_datagram_print_wc_error(datagram);
1526  return;
1527  }
1528 
1530 }
1531 
1532 /*****************************************************************************/
1533 
1537  ec_fsm_slave_config_t *fsm
1538  )
1539 {
1542  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1543 }
1544 
1545 /*****************************************************************************/
1546 
1550  ec_fsm_slave_config_t *fsm
1551  )
1552 {
1553  ec_slave_t *slave = fsm->slave;
1554 
1555  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1556 
1557  if (!ec_fsm_change_success(fsm->fsm_change)) {
1558  if (!fsm->fsm_change->spontaneous_change)
1559  fsm->slave->error_flag = 1;
1561  return;
1562  }
1563 
1564  // slave is now in SAFEOP
1565 
1566  EC_SLAVE_DBG(slave, 1, "Now in SAFEOP.\n");
1567 
1568  if (fsm->slave->current_state == fsm->slave->requested_state) {
1569  fsm->state = ec_fsm_slave_config_state_end; // successful
1570  EC_SLAVE_DBG(slave, 1, "Finished configuration.\n");
1571  return;
1572  }
1573 
1575 }
1576 
1577 /*****************************************************************************/
1578 
1582  ec_fsm_slave_config_t *fsm
1583  )
1584 {
1585  ec_slave_t *slave = fsm->slave;
1586  ec_soe_request_t *req;
1587 
1588  if (!slave->config) {
1590  return;
1591  }
1592 
1593  list_for_each_entry(req, &slave->config->soe_configs, list) {
1594  if (req->al_state == EC_AL_STATE_SAFEOP) {
1595  // start SoE configuration
1597  fsm->soe_request = req;
1600  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1601  &fsm->soe_request_copy);
1602  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1603  return;
1604  }
1605  }
1606 
1607  // No SoE configuration to be applied in SAFEOP
1609 }
1610 
1611 /*****************************************************************************/
1612 
1616  ec_fsm_slave_config_t *fsm
1617  )
1618 {
1619  ec_slave_t *slave = fsm->slave;
1620 
1621  if (ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram)) {
1622  return;
1623  }
1624 
1625  if (!ec_fsm_soe_success(fsm->fsm_soe)) {
1626  EC_SLAVE_ERR(slave, "SoE configuration failed.\n");
1627  fsm->slave->error_flag = 1;
1629  return;
1630  }
1631 
1632  if (!fsm->slave->config) { // config removed in the meantime
1634  return;
1635  }
1636 
1637  // Another IDN to configure in SAFEOP?
1638  while (fsm->soe_request->list.next != &fsm->slave->config->soe_configs) {
1639  fsm->soe_request = list_entry(fsm->soe_request->list.next,
1640  ec_soe_request_t, list);
1641  if (fsm->soe_request->al_state == EC_AL_STATE_SAFEOP) {
1644  ec_fsm_soe_transfer(fsm->fsm_soe, fsm->slave,
1645  &fsm->soe_request_copy);
1646  ec_fsm_soe_exec(fsm->fsm_soe, fsm->datagram);
1647  return;
1648  }
1649  }
1650 
1651  // All SAFEOP IDNs are now configured.
1653 }
1654 
1655 /*****************************************************************************/
1656 
1660  ec_fsm_slave_config_t *fsm
1661  )
1662 {
1663  // set state to OP
1666  ec_fsm_change_exec(fsm->fsm_change); // execute immediately
1667 }
1668 
1669 /*****************************************************************************/
1670 
1674  ec_fsm_slave_config_t *fsm
1675  )
1676 {
1677  ec_slave_t *slave = fsm->slave;
1678 
1679  if (ec_fsm_change_exec(fsm->fsm_change)) return;
1680 
1681  if (!ec_fsm_change_success(fsm->fsm_change)) {
1682  if (!fsm->fsm_change->spontaneous_change)
1683  slave->error_flag = 1;
1685  return;
1686  }
1687 
1688  // slave is now in OP
1689 
1690  EC_SLAVE_DBG(slave, 1, "Now in OP. Finished configuration.\n");
1691 
1692  fsm->state = ec_fsm_slave_config_state_end; // successful
1693 }
1694 
1695 /*****************************************************************************/
1696 
1700  ec_fsm_slave_config_t *fsm
1701  )
1702 {
1703  EC_SLAVE_DBG(fsm->slave, 1, "Slave configuration detached during "
1704  "configuration. Reconfiguring.");
1705 
1706  ec_fsm_slave_config_enter_init(fsm); // reconfigure
1707 }
1708 
1709 /******************************************************************************
1710  * Common state functions
1711  *****************************************************************************/
1712 
1716  ec_fsm_slave_config_t *fsm
1717  )
1718 {
1719 }
1720 
1721 /*****************************************************************************/
1722 
1726  ec_fsm_slave_config_t *fsm
1727  )
1728 {
1729 }
1730 
1731 /*****************************************************************************/
#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
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
Pre-operational.
Definition: ecrt.h:530
void ec_fsm_slave_config_state_boot_preop(ec_fsm_slave_config_t *)
Slave configuration state: BOOT/PREOP.
struct list_head sdo_configs
List of SDO configurations.
Definition: slave_config.h:143
uint16_t boot_rx_mailbox_offset
Bootstrap receive mailbox address.
Definition: slave.h:139
#define EC_SYNC_PAGE_SIZE
Size of a sync manager configuration page.
Definition: globals.h:101
ec_sii_t sii
Extracted SII data.
Definition: slave.h:223
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.
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *)
WATCHDOG entry function.
uint16_t configured_tx_mailbox_size
Configured send mailbox size.
Definition: slave.h:201
void ec_fsm_slave_config_state_init(ec_fsm_slave_config_t *)
Slave configuration state: INIT.
void ec_fsm_slave_config_state_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SAFEOP.
FMMU configuration.
Definition: fmmu_config.h:46
ec_sdo_request_t * request
SDO request for SDO configuration.
void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *)
Reconfigure the slave starting at INIT.
u64 app_start_time
Application start time.
Definition: master.h:239
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:106
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:185
OP (mailbox communication and input/output update)
Definition: globals.h:138
uint16_t configured_tx_mailbox_offset
Configured send mailbox offset.
Definition: slave.h:199
void ec_fsm_slave_config_state_dc_cycle(ec_fsm_slave_config_t *)
Slave configuration state: DC CYCLE.
ec_fsm_change_t * fsm_change
State change state machine.
CANopen SDO request.
Definition: sdo_request.h:48
ec_slave_state_t current_state
Current application state.
Definition: slave.h:192
void ec_fsm_slave_config_state_dc_clear_assign(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR DC ASSIGN.
void ec_fsm_slave_config_state_dc_start(ec_fsm_slave_config_t *)
Slave configuration state: DC START.
uint8_t used_fmmus
Number of FMMUs used.
Definition: slave_config.h:139
Safe-operational.
Definition: ecrt.h:531
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
void ec_fsm_slave_config_enter_soe_conf_safeop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied in SAFEOP.
EtherCAT datagram.
Definition: datagram.h:87
void ec_fsm_slave_config_state_fmmu(ec_fsm_slave_config_t *)
Slave configuration state: FMMU.
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2187
Bootstrap state (mailbox communication, firmware update)
Definition: globals.h:134
void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
uint32_t cycle_time
Cycle time [ns].
Definition: globals.h:184
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:99
int ec_fsm_coe_success(const ec_fsm_coe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_coe.c:262
void ec_fsm_slave_config_state_start(ec_fsm_slave_config_t *)
Slave configuration state: START.
uint16_t boot_tx_mailbox_size
Bootstrap transmit mailbox size.
Definition: slave.h:142
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:76
void ec_fsm_slave_config_state_mbox_sync(ec_fsm_slave_config_t *)
Slave configuration state: SYNC.
void ec_fsm_slave_config_enter_dc_clear_assign(ec_fsm_slave_config_t *)
Clear the DC assignment.
uint16_t station_address
Configured station address.
Definition: slave.h:184
void(* state)(ec_fsm_slave_config_t *)
State function.
unsigned int sync_count
Number of sync managers.
Definition: slave.h:166
ec_sdo_request_t request_copy
Copied SDO request.
uint16_t std_rx_mailbox_size
Standard receive mailbox size.
Definition: slave.h:144
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:145
EtherCAT master structure.
ec_fmmu_config_t fmmu_configs[EC_MAX_FMMUS]
FMMU configurations.
Definition: slave_config.h:138
SAFEOP (mailbox communication and input update)
Definition: globals.h:136
void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *)
WATCHDOG_DIVIDER entry function.
ec_sync_signal_t dc_sync[EC_SYNC_SIGNAL_COUNT]
DC sync signals.
Definition: slave_config.h:141
uint16_t boot_tx_mailbox_offset
Bootstrap transmit mailbox address.
Definition: slave.h:141
EtherCAT slave.
Definition: slave.h:176
void ec_sdo_request_clear(ec_sdo_request_t *req)
SDO request destructor.
Definition: sdo_request.c:76
EtherCAT slave configuration state machine.
void ec_fsm_slave_config_state_soe_conf_safeop(ec_fsm_slave_config_t *)
Slave configuration state: SOE_CONF.
uint16_t ec_pdo_list_total_size(const ec_pdo_list_t *pl)
Calculates the total size of the mapped PDO entries.
Definition: pdo_list.c:87
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
ec_fsm_pdo_t * fsm_pdo
PDO configuration state machine.
void ec_fsm_soe_transfer(ec_fsm_soe_t *fsm, ec_slave_t *slave, ec_soe_request_t *request)
Starts to transfer an IDN to/from a slave.
Definition: fsm_soe.c:134
int ec_fsm_soe_success(const ec_fsm_soe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_soe.c:191
ec_sync_config_t sync_configs[EC_MAX_SYNC_MANAGERS]
Sync manager configurations.
Definition: slave_config.h:136
ec_datagram_state_t state
State.
Definition: datagram.h:100
ec_slave_config_t * config
Current configuration.
Definition: slave.h:190
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2221
uint8_t sync_index
Index of sync manager to use.
Definition: fmmu_config.h:50
void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG_DIVIDER.
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:147
void ec_fsm_slave_config_state_end(ec_fsm_slave_config_t *)
State: END.
void ec_fsm_slave_config_enter_clear_sync(ec_fsm_slave_config_t *)
Clear the sync manager configurations.
int ec_fsm_slave_config_running(const ec_fsm_slave_config_t *fsm)
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
#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:143
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_soe_request_clear(ec_soe_request_t *req)
SoE request destructor.
Definition: soe_request.c:77
void ec_fsm_slave_config_state_clear_fmmus(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR FMMU.
ec_pdo_list_t pdos
Current PDO assignment.
Definition: sync_config.h:49
uint16_t dc_assign_activate
Vendor-specific AssignActivate word.
Definition: slave_config.h:140
void ec_fsm_slave_config_enter_mbox_sync(ec_fsm_slave_config_t *)
Check for mailbox sync managers to be configured.
ec_datagram_t * datagram
Datagram used in the state machine.
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2204
uint8_t base_fmmu_count
Number of supported FMMUs.
Definition: slave.h:207
uint16_t configured_rx_mailbox_offset
Configured receive mailbox offset.
Definition: slave.h:195
void ec_fsm_slave_config_enter_fmmu(ec_fsm_slave_config_t *)
Check for FMMUs to be configured.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2151
uint16_t watchdog_intervals
Process data watchdog intervals (see spec.
Definition: slave_config.h:130
void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *)
Check for SDO configurations to be applied.
ec_master_t * master
Master owning the slave.
Definition: slave.h:178
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_soe_conf_preop(ec_fsm_slave_config_t *)
Check for SoE configurations to be applied.
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:298
uint8_t has_dc_system_time
The slave supports the DC system time register.
Definition: slave.h:212
void ec_fsm_slave_config_enter_init(ec_fsm_slave_config_t *)
Start state change to INIT.
void ec_fsm_slave_config_state_pdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: PDO_CONF.
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition: datagram.c:273
uint8_t control_register
Control register value.
Definition: sync.h:51
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_state_pdo_sync(ec_fsm_slave_config_t *)
Configure PDO sync managers.
#define EC_DC_MAX_SYNC_DIFF_NS
Maximum clock difference (in ns) before going to SAFEOP.
void ec_fsm_slave_config_enter_safeop(ec_fsm_slave_config_t *)
Request SAFEOP state.
ec_fsm_soe_t * fsm_soe
SoE state machine.
struct list_head soe_configs
List of SoE configurations.
Definition: slave_config.h:147
void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *)
PDO_CONF entry function.
unsigned int take_time
Store jiffies after datagram reception.
INIT state (no mailbox communication, no IO)
Definition: globals.h:130
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:565
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:418
void ec_sdo_request_init(ec_sdo_request_t *req)
SDO request constructor.
Definition: sdo_request.c:56
void ec_fsm_slave_config_state_op(ec_fsm_slave_config_t *)
Slave configuration state: OP.
#define EC_WRITE_U64(DATA, VAL)
Write a 64-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2238
uint16_t boot_rx_mailbox_size
Bootstrap receive mailbox size.
Definition: slave.h:140
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:183
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:228
void ec_fsm_slave_config_state_clear_sync(ec_fsm_slave_config_t *)
Slave configuration state: CLEAR SYNC.
Queued for sending.
Definition: datagram.h:76
Timed out (dequeued).
Definition: datagram.h:79
u8 has_app_time
Application time is valid.
Definition: master.h:240
void ec_fsm_slave_config_state_error(ec_fsm_slave_config_t *)
State: ERROR.
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:238
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:227
uint16_t configured_rx_mailbox_size
Configured receive mailbox size.
Definition: slave.h:197
uint8_t base_dc_supported
Distributed clocks are supported.
Definition: slave.h:210
uint8_t * data
Datagram payload.
Definition: datagram.h:94
void ec_fsm_slave_config_state_dc_assign(ec_fsm_slave_config_t *)
Slave configuration state: DC ASSIGN.
uint8_t base_sync_count
Number of supported sync managers.
Definition: slave.h:208
void ec_fsm_slave_config_enter_op(ec_fsm_slave_config_t *)
Bring slave to OP.
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
int ec_fsm_slave_config_success(const ec_fsm_slave_config_t *fsm)
void ec_fsm_slave_config_enter_pdo_sync(ec_fsm_slave_config_t *)
Check for PDO sync managers to be configured.
void ec_soe_request_init(ec_soe_request_t *req)
SoE request constructor.
Definition: soe_request.c: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:156
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:205
uint16_t default_length
Data length in bytes.
Definition: sync.h:50
PREOP state (mailbox communication, no IO)
Definition: globals.h:132
void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *)
Slave configuration state: SDO_CONF.
void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *)
Slave configuration state: WATCHDOG.
Received (dequeued).
Definition: datagram.h:78
void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *)
Request PREOP state.
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:193
ec_sync_t * syncs
SYNC MANAGER categories.
Definition: slave.h:165
uint16_t std_tx_mailbox_size
Standard transmit mailbox size.
Definition: slave.h:146
EtherCAT master.
Definition: master.h:194
ec_slave_state_t requested_state
Requested application state.
Definition: slave.h:191
#define EC_FMMU_PAGE_SIZE
Size of an FMMU configuration page.
Definition: globals.h:107
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_dc_sync_check(ec_fsm_slave_config_t *)
Slave configuration state: DC SYNC CHECK.
#define EC_DC_SYNC_WAIT_MS
Maximum time (in ms) to wait for clock discipline.
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
EtherCAT state change FSM.
Definition: fsm_change.h:64
void ec_fsm_slave_config_enter_dc_cycle(ec_fsm_slave_config_t *)
Check for DC to be configured.
int ec_soe_request_copy(ec_soe_request_t *req, const ec_soe_request_t *other)
Copy another SoE request.
Definition: soe_request.c: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:590
unsigned int retries
Retries on datagram timeout.