191 master->datagram_index = 0; |
191 master->datagram_index = 0; |
192 |
192 |
193 INIT_LIST_HEAD(&master->ext_datagram_queue); |
193 INIT_LIST_HEAD(&master->ext_datagram_queue); |
194 sema_init(&master->ext_queue_sem, 1); |
194 sema_init(&master->ext_queue_sem, 1); |
195 |
195 |
196 INIT_LIST_HEAD(&master->external_datagram_queue); |
196 master->ext_ring_idx_rt = 0; |
|
197 master->ext_ring_idx_fsm = 0; |
|
198 |
|
199 // init external datagram ring |
|
200 for (i = 0; i < EC_EXT_RING_SIZE; i++) { |
|
201 ec_datagram_t *datagram = &master->ext_datagram_ring[i]; |
|
202 ec_datagram_init(datagram); |
|
203 snprintf(datagram->name, EC_DATAGRAM_NAME_SIZE, "ext-%u", i); |
|
204 } |
197 |
205 |
198 // send interval in IDLE phase |
206 // send interval in IDLE phase |
199 ec_master_set_send_interval(master, 1000000 / HZ); |
207 ec_master_set_send_interval(master, 1000000 / HZ); |
|
208 |
|
209 master->fsm_slave = NULL; |
|
210 INIT_LIST_HEAD(&master->fsm_exec_list); |
|
211 master->fsm_exec_count = 0U; |
200 |
212 |
201 master->debug_level = debug_level; |
213 master->debug_level = debug_level; |
202 master->stats.timeouts = 0; |
214 master->stats.timeouts = 0; |
203 master->stats.corrupted = 0; |
215 master->stats.corrupted = 0; |
204 master->stats.unmatched = 0; |
216 master->stats.unmatched = 0; |
242 goto out_clear_devices; |
254 goto out_clear_devices; |
243 } |
255 } |
244 |
256 |
245 // create state machine object |
257 // create state machine object |
246 ec_fsm_master_init(&master->fsm, master, &master->fsm_datagram); |
258 ec_fsm_master_init(&master->fsm, master, &master->fsm_datagram); |
|
259 |
|
260 // alloc external datagram ring |
|
261 for (i = 0; i < EC_EXT_RING_SIZE; i++) { |
|
262 ec_datagram_t *datagram = &master->ext_datagram_ring[i]; |
|
263 ret = ec_datagram_prealloc(datagram, EC_MAX_DATA_SIZE); |
|
264 if (ret) { |
|
265 EC_MASTER_ERR(master, "Failed to allocate external" |
|
266 " datagram %u.\n", i); |
|
267 goto out_clear_ext_datagrams; |
|
268 } |
|
269 } |
247 |
270 |
248 // init reference sync datagram |
271 // init reference sync datagram |
249 ec_datagram_init(&master->ref_sync_datagram); |
272 ec_datagram_init(&master->ref_sync_datagram); |
250 snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE, |
273 snprintf(master->ref_sync_datagram.name, EC_DATAGRAM_NAME_SIZE, |
251 "refsync"); |
274 "refsync"); |
252 ret = ec_datagram_prealloc(&master->ref_sync_datagram, 4); |
275 ret = ec_datagram_prealloc(&master->ref_sync_datagram, 4); |
253 if (ret < 0) { |
276 if (ret < 0) { |
254 ec_datagram_clear(&master->ref_sync_datagram); |
277 ec_datagram_clear(&master->ref_sync_datagram); |
255 EC_MASTER_ERR(master, "Failed to allocate reference" |
278 EC_MASTER_ERR(master, "Failed to allocate reference" |
256 " synchronisation datagram.\n"); |
279 " synchronisation datagram.\n"); |
257 goto out_clear_fsm; |
280 goto out_clear_ext_datagrams; |
258 } |
281 } |
259 |
282 |
260 // init sync datagram |
283 // init sync datagram |
261 ec_datagram_init(&master->sync_datagram); |
284 ec_datagram_init(&master->sync_datagram); |
262 snprintf(master->sync_datagram.name, EC_DATAGRAM_NAME_SIZE, "sync"); |
285 snprintf(master->sync_datagram.name, EC_DATAGRAM_NAME_SIZE, "sync"); |
741 */ |
776 */ |
742 void ec_master_inject_external_datagrams( |
777 void ec_master_inject_external_datagrams( |
743 ec_master_t *master /**< EtherCAT master */ |
778 ec_master_t *master /**< EtherCAT master */ |
744 ) |
779 ) |
745 { |
780 { |
746 ec_datagram_t *datagram, *n; |
781 ec_datagram_t *datagram; |
747 size_t queue_size = 0; |
782 size_t queue_size = 0, new_queue_size = 0; |
|
783 #if DEBUG_INJECT |
|
784 unsigned int datagram_count = 0; |
|
785 #endif |
|
786 |
|
787 if (master->ext_ring_idx_rt == master->ext_ring_idx_fsm) { |
|
788 // nothing to inject |
|
789 return; |
|
790 } |
748 |
791 |
749 list_for_each_entry(datagram, &master->datagram_queue, queue) { |
792 list_for_each_entry(datagram, &master->datagram_queue, queue) { |
750 queue_size += datagram->data_size; |
793 if (datagram->state == EC_DATAGRAM_QUEUED) { |
751 } |
794 queue_size += datagram->data_size; |
752 |
795 } |
753 list_for_each_entry_safe(datagram, n, &master->external_datagram_queue, |
796 } |
754 queue) { |
797 |
755 queue_size += datagram->data_size; |
|
756 if (queue_size <= master->max_queue_size) { |
|
757 list_del_init(&datagram->queue); |
|
758 #if DEBUG_INJECT |
798 #if DEBUG_INJECT |
759 EC_MASTER_DBG(master, 0, "Injecting external datagram %08x" |
799 EC_MASTER_DBG(master, 1, "Injecting datagrams, queue_size=%zu\n", |
760 " size=%u, queue_size=%u\n", (unsigned int) datagram, |
800 queue_size); |
761 datagram->data_size, queue_size); |
801 #endif |
|
802 |
|
803 while (master->ext_ring_idx_rt != master->ext_ring_idx_fsm) { |
|
804 datagram = &master->ext_datagram_ring[master->ext_ring_idx_rt]; |
|
805 |
|
806 if (datagram->state != EC_DATAGRAM_INIT) { |
|
807 // skip datagram |
|
808 master->ext_ring_idx_rt = |
|
809 (master->ext_ring_idx_rt + 1) % EC_EXT_RING_SIZE; |
|
810 continue; |
|
811 } |
|
812 |
|
813 new_queue_size = queue_size + datagram->data_size; |
|
814 if (new_queue_size <= master->max_queue_size) { |
|
815 #if DEBUG_INJECT |
|
816 EC_MASTER_DBG(master, 1, "Injecting datagram %s" |
|
817 " size=%zu, queue_size=%zu\n", datagram->name, |
|
818 datagram->data_size, new_queue_size); |
|
819 datagram_count++; |
762 #endif |
820 #endif |
763 #ifdef EC_HAVE_CYCLES |
821 #ifdef EC_HAVE_CYCLES |
764 datagram->cycles_sent = 0; |
822 datagram->cycles_sent = 0; |
765 #endif |
823 #endif |
766 datagram->jiffies_sent = 0; |
824 datagram->jiffies_sent = 0; |
767 ec_master_queue_datagram(master, datagram); |
825 ec_master_queue_datagram(master, datagram); |
768 } else { |
826 queue_size = new_queue_size; |
769 if (datagram->data_size > master->max_queue_size) { |
827 } |
770 list_del_init(&datagram->queue); |
828 else if (datagram->data_size > master->max_queue_size) { |
|
829 datagram->state = EC_DATAGRAM_ERROR; |
|
830 EC_MASTER_ERR(master, "External datagram %s is too large," |
|
831 " size=%zu, max_queue_size=%zu\n", |
|
832 datagram->name, datagram->data_size, |
|
833 master->max_queue_size); |
|
834 } |
|
835 else { // datagram does not fit in the current cycle |
|
836 #ifdef EC_HAVE_CYCLES |
|
837 cycles_t cycles_now = get_cycles(); |
|
838 |
|
839 if (cycles_now - datagram->cycles_sent |
|
840 > ext_injection_timeout_cycles) |
|
841 #else |
|
842 if (jiffies - datagram->jiffies_sent |
|
843 > ext_injection_timeout_jiffies) |
|
844 #endif |
|
845 { |
|
846 unsigned int time_us; |
|
847 |
771 datagram->state = EC_DATAGRAM_ERROR; |
848 datagram->state = EC_DATAGRAM_ERROR; |
772 EC_MASTER_ERR(master, "External datagram %p is too large," |
|
773 " size=%zu, max_queue_size=%zu\n", |
|
774 datagram, datagram->data_size, |
|
775 master->max_queue_size); |
|
776 } else { |
|
777 #ifdef EC_HAVE_CYCLES |
849 #ifdef EC_HAVE_CYCLES |
778 cycles_t cycles_now = get_cycles(); |
850 time_us = (unsigned int) |
779 |
851 ((cycles_now - datagram->cycles_sent) * 1000LL) |
780 if (cycles_now - datagram->cycles_sent |
852 / cpu_khz; |
781 > ext_injection_timeout_cycles) |
|
782 #else |
853 #else |
783 if (jiffies - datagram->jiffies_sent |
854 time_us = (unsigned int) |
784 > ext_injection_timeout_jiffies) |
855 ((jiffies - datagram->jiffies_sent) * 1000000 / HZ); |
785 #endif |
856 #endif |
786 { |
857 EC_MASTER_ERR(master, "Timeout %u us: Injecting" |
787 unsigned int time_us; |
858 " external datagram %s size=%zu," |
788 |
859 " max_queue_size=%zu\n", time_us, datagram->name, |
789 list_del_init(&datagram->queue); |
860 datagram->data_size, master->max_queue_size); |
790 datagram->state = EC_DATAGRAM_ERROR; |
861 } |
791 #ifdef EC_HAVE_CYCLES |
862 else { |
792 time_us = (unsigned int) |
|
793 ((cycles_now - datagram->cycles_sent) * 1000LL) |
|
794 / cpu_khz; |
|
795 #else |
|
796 time_us = (unsigned int) |
|
797 ((jiffies - datagram->jiffies_sent) * 1000000 / HZ); |
|
798 #endif |
|
799 EC_MASTER_ERR(master, "Timeout %u us: Injecting" |
|
800 " external datagram %p size=%zu," |
|
801 " max_queue_size=%zu\n", time_us, datagram, |
|
802 datagram->data_size, master->max_queue_size); |
|
803 } |
|
804 #if DEBUG_INJECT |
863 #if DEBUG_INJECT |
805 else { |
864 EC_MASTER_DBG(master, 1, "Deferred injecting" |
806 EC_MASTER_DBG(master, 0, "Deferred injecting" |
865 " external datagram %s size=%u, queue_size=%u\n", |
807 " of external datagram %p" |
866 datagram->name, datagram->data_size, queue_size); |
808 " size=%u, queue_size=%u\n", |
867 #endif |
809 datagram, datagram->data_size, queue_size); |
868 break; |
810 } |
|
811 #endif |
|
812 } |
869 } |
813 } |
870 } |
814 } |
871 |
|
872 master->ext_ring_idx_rt = |
|
873 (master->ext_ring_idx_rt + 1) % EC_EXT_RING_SIZE; |
|
874 } |
|
875 |
|
876 #if DEBUG_INJECT |
|
877 EC_MASTER_DBG(master, 1, "Injected %u datagrams.\n", datagram_count); |
|
878 #endif |
815 } |
879 } |
816 |
880 |
817 /*****************************************************************************/ |
881 /*****************************************************************************/ |
818 |
882 |
819 /** Sets the expected interval between calls to ecrt_master_send |
883 /** Sets the expected interval between calls to ecrt_master_send |
830 master->max_queue_size -= master->max_queue_size / 10; |
894 master->max_queue_size -= master->max_queue_size / 10; |
831 } |
895 } |
832 |
896 |
833 /*****************************************************************************/ |
897 /*****************************************************************************/ |
834 |
898 |
835 /** Places an external datagram in the sdo datagram queue. |
899 /** Searches for a free datagram in the external datagram ring. |
836 */ |
900 */ |
837 void ec_master_queue_external_datagram( |
901 ec_datagram_t *ec_master_get_external_datagram( |
838 ec_master_t *master, /**< EtherCAT master */ |
902 ec_master_t *master /**< EtherCAT master */ |
839 ec_datagram_t *datagram /**< datagram */ |
903 ) |
840 ) |
904 { |
841 { |
905 if ((master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE != |
842 ec_datagram_t *queued_datagram; |
906 master->ext_ring_idx_rt) { |
843 |
907 ec_datagram_t *datagram = |
844 down(&master->io_sem); |
908 &master->ext_datagram_ring[master->ext_ring_idx_fsm]; |
845 |
909 return datagram; |
846 // check, if the datagram is already queued |
910 } |
847 list_for_each_entry(queued_datagram, &master->external_datagram_queue, |
911 else { |
848 queue) { |
912 return NULL; |
849 if (queued_datagram == datagram) { |
913 } |
850 up(&master->io_sem); |
|
851 datagram->state = EC_DATAGRAM_QUEUED; |
|
852 return; |
|
853 } |
|
854 } |
|
855 |
|
856 #if DEBUG_INJECT |
|
857 EC_MASTER_DBG(master, 0, "Requesting external datagram %p size=%u\n", |
|
858 datagram, datagram->data_size); |
|
859 #endif |
|
860 |
|
861 list_add_tail(&datagram->queue, &master->external_datagram_queue); |
|
862 datagram->state = EC_DATAGRAM_QUEUED; |
|
863 #ifdef EC_HAVE_CYCLES |
|
864 datagram->cycles_sent = get_cycles(); |
|
865 #endif |
|
866 datagram->jiffies_sent = jiffies; |
|
867 |
|
868 up(&master->io_sem); |
|
869 |
|
870 master->fsm.idle = 0; |
|
871 } |
914 } |
872 |
915 |
873 /*****************************************************************************/ |
916 /*****************************************************************************/ |
874 |
917 |
875 /** Places a datagram in the datagram queue. |
918 /** Places a datagram in the datagram queue. |
1364 |
1407 |
1365 #endif // EC_USE_HRTIMER |
1408 #endif // EC_USE_HRTIMER |
1366 |
1409 |
1367 /*****************************************************************************/ |
1410 /*****************************************************************************/ |
1368 |
1411 |
|
1412 /** Execute slave FSMs. |
|
1413 */ |
|
1414 void ec_master_exec_slave_fsms( |
|
1415 ec_master_t *master /**< EtherCAT master. */ |
|
1416 ) |
|
1417 { |
|
1418 ec_datagram_t *datagram; |
|
1419 ec_fsm_slave_t *fsm, *next; |
|
1420 unsigned int count = 0; |
|
1421 |
|
1422 list_for_each_entry_safe(fsm, next, &master->fsm_exec_list, list) { |
|
1423 if (!fsm->datagram) { |
|
1424 EC_MASTER_WARN(master, "Slave %u FSM has zero datagram." |
|
1425 "This is a bug!\n", fsm->slave->ring_position); |
|
1426 list_del_init(&fsm->list); |
|
1427 master->fsm_exec_count--; |
|
1428 return; |
|
1429 } |
|
1430 |
|
1431 if (fsm->datagram->state == EC_DATAGRAM_INIT || |
|
1432 fsm->datagram->state == EC_DATAGRAM_QUEUED || |
|
1433 fsm->datagram->state == EC_DATAGRAM_SENT) { |
|
1434 // previous datagram was not sent or received yet. |
|
1435 // wait until next thread execution |
|
1436 return; |
|
1437 } |
|
1438 |
|
1439 datagram = ec_master_get_external_datagram(master); |
|
1440 if (!datagram) { |
|
1441 // no free datagrams at the moment |
|
1442 EC_MASTER_WARN(master, "No free datagram during" |
|
1443 " slave FSM execution. This is a bug!\n"); |
|
1444 continue; |
|
1445 } |
|
1446 |
|
1447 #if DEBUG_INJECT |
|
1448 EC_MASTER_DBG(master, 1, "Executing slave %u FSM.\n", |
|
1449 fsm->slave->ring_position); |
|
1450 #endif |
|
1451 if (ec_fsm_slave_exec(fsm, datagram)) { |
|
1452 // FSM consumed datagram |
|
1453 #if DEBUG_INJECT |
|
1454 EC_MASTER_DBG(master, 1, "FSM consumed datagram %s\n", |
|
1455 datagram->name); |
|
1456 #endif |
|
1457 master->ext_ring_idx_fsm = |
|
1458 (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; |
|
1459 } |
|
1460 else { |
|
1461 // FSM finished |
|
1462 list_del_init(&fsm->list); |
|
1463 master->fsm_exec_count--; |
|
1464 #if DEBUG_INJECT |
|
1465 EC_MASTER_DBG(master, 1, "FSM finished. %u remaining.\n", |
|
1466 master->fsm_exec_count); |
|
1467 #endif |
|
1468 } |
|
1469 } |
|
1470 |
|
1471 while (master->fsm_exec_count < EC_EXT_RING_SIZE / 2 |
|
1472 && count < master->slave_count) { |
|
1473 |
|
1474 if (ec_fsm_slave_is_ready(&master->fsm_slave->fsm)) { |
|
1475 datagram = ec_master_get_external_datagram(master); |
|
1476 |
|
1477 if (ec_fsm_slave_exec(&master->fsm_slave->fsm, datagram)) { |
|
1478 master->ext_ring_idx_fsm = |
|
1479 (master->ext_ring_idx_fsm + 1) % EC_EXT_RING_SIZE; |
|
1480 list_add_tail(&master->fsm_slave->fsm.list, |
|
1481 &master->fsm_exec_list); |
|
1482 master->fsm_exec_count++; |
|
1483 #if DEBUG_INJECT |
|
1484 EC_MASTER_DBG(master, 1, "New slave %u FSM" |
|
1485 " consumed datagram %s, now %u FSMs in list.\n", |
|
1486 master->fsm_slave->ring_position, datagram->name, |
|
1487 master->fsm_exec_count); |
|
1488 #endif |
|
1489 } |
|
1490 } |
|
1491 |
|
1492 master->fsm_slave++; |
|
1493 if (master->fsm_slave >= master->slaves + master->slave_count) { |
|
1494 master->fsm_slave = master->slaves; |
|
1495 } |
|
1496 count++; |
|
1497 } |
|
1498 } |
|
1499 |
|
1500 /*****************************************************************************/ |
|
1501 |
1369 /** Master kernel thread function for IDLE phase. |
1502 /** Master kernel thread function for IDLE phase. |
1370 */ |
1503 */ |
1371 static int ec_master_idle_thread(void *priv_data) |
1504 static int ec_master_idle_thread(void *priv_data) |
1372 { |
1505 { |
1373 ec_master_t *master = (ec_master_t *) priv_data; |
1506 ec_master_t *master = (ec_master_t *) priv_data; |
1374 ec_slave_t *slave = NULL; |
|
1375 int fsm_exec; |
1507 int fsm_exec; |
1376 #ifdef EC_USE_HRTIMER |
1508 #ifdef EC_USE_HRTIMER |
1377 size_t sent_bytes; |
1509 size_t sent_bytes; |
1378 #endif |
1510 #endif |
1379 |
1511 |
1460 ec_datagram_output_stats(&master->fsm_datagram); |
1584 ec_datagram_output_stats(&master->fsm_datagram); |
1461 |
1585 |
1462 if (master->injection_seq_rt == master->injection_seq_fsm) { |
1586 if (master->injection_seq_rt == master->injection_seq_fsm) { |
1463 // output statistics |
1587 // output statistics |
1464 ec_master_output_stats(master); |
1588 ec_master_output_stats(master); |
1465 |
|
1466 fsm_exec = 0; |
|
1467 |
1589 |
1468 // execute master & slave state machines |
1590 // execute master & slave state machines |
1469 if (down_interruptible(&master->master_sem)) { |
1591 if (down_interruptible(&master->master_sem)) { |
1470 break; |
1592 break; |
1471 } |
1593 } |
1472 |
1594 |
1473 fsm_exec += ec_fsm_master_exec(&master->fsm); |
1595 if (ec_fsm_master_exec(&master->fsm)) { |
1474 |
1596 // Inject datagrams (let the RT thread queue them, see |
1475 for (slave = master->slaves; |
1597 // ecrt_master_send()) |
1476 slave < master->slaves + master->slave_count; |
|
1477 slave++) { |
|
1478 ec_fsm_slave_exec(&slave->fsm); |
|
1479 } |
|
1480 |
|
1481 up(&master->master_sem); |
|
1482 |
|
1483 // Inject datagrams (let the RT thread queue them, see |
|
1484 // ecrt_master_send()) |
|
1485 if (fsm_exec) { |
|
1486 master->injection_seq_fsm++; |
1598 master->injection_seq_fsm++; |
1487 } |
1599 } |
|
1600 |
|
1601 ec_master_exec_slave_fsms(master); |
|
1602 |
|
1603 up(&master->master_sem); |
1488 } |
1604 } |
1489 |
1605 |
1490 #ifdef EC_USE_HRTIMER |
1606 #ifdef EC_USE_HRTIMER |
1491 // the op thread should not work faster than the sending RT thread |
1607 // the op thread should not work faster than the sending RT thread |
1492 ec_master_nanosleep(master->send_interval * 1000); |
1608 ec_master_nanosleep(master->send_interval * 1000); |