70 |
70 |
71 void ec_master_reset(ec_master_t *master |
71 void ec_master_reset(ec_master_t *master |
72 /**< Zeiger auf den zurückzusetzenden Master */ |
72 /**< Zeiger auf den zurückzusetzenden Master */ |
73 ) |
73 ) |
74 { |
74 { |
75 ec_domain_t *domain, *next; |
|
76 |
|
77 ec_master_clear_slaves(master); |
|
78 |
|
79 // Domain-Liste leeren |
|
80 list_for_each_entry_safe(domain, next, &master->domains, list) { |
|
81 ec_domain_clear(domain); |
|
82 kfree(domain); |
|
83 } |
|
84 INIT_LIST_HEAD(&master->domains); |
|
85 |
|
86 master->command_index = 0; |
|
87 master->debug_level = 0; |
|
88 master->bus_time = 0; |
|
89 master->frames_lost = 0; |
|
90 master->frames_delayed = 0; |
|
91 master->t_last_cyclic_output = 0; |
|
92 } |
|
93 |
|
94 /*****************************************************************************/ |
|
95 |
|
96 /** |
|
97 Entfernt alle Slaves. |
|
98 */ |
|
99 |
|
100 void ec_master_clear_slaves(ec_master_t *master /**< EtherCAT-Master */) |
|
101 { |
|
102 unsigned int i; |
75 unsigned int i; |
103 |
76 ec_command_t *command, *next_command; |
|
77 ec_domain_t *domain, *next_domain; |
|
78 |
|
79 // Alle Slaves entfernen |
104 if (master->slaves) { |
80 if (master->slaves) { |
105 for (i = 0; i < master->slave_count; i++) { |
81 for (i = 0; i < master->slave_count; i++) { |
106 ec_slave_clear(master->slaves + i); |
82 ec_slave_clear(master->slaves + i); |
107 } |
83 } |
108 kfree(master->slaves); |
84 kfree(master->slaves); |
109 master->slaves = NULL; |
85 master->slaves = NULL; |
110 } |
86 } |
111 master->slave_count = 0; |
87 master->slave_count = 0; |
|
88 |
|
89 // Kommando-Warteschlange leeren |
|
90 list_for_each_entry_safe(command, next_command, &master->commands, list) { |
|
91 command->state = EC_CMD_ERROR; |
|
92 list_del_init(&command->list); |
|
93 } |
|
94 |
|
95 // Domain-Liste leeren |
|
96 list_for_each_entry_safe(domain, next_domain, &master->domains, list) { |
|
97 list_del(&domain->list); |
|
98 ec_domain_clear(domain); |
|
99 kfree(domain); |
|
100 } |
|
101 |
|
102 master->command_index = 0; |
|
103 master->debug_level = 0; |
|
104 master->stats.timeouts = 0; |
|
105 master->stats.delayed = 0; |
|
106 master->stats.corrupted = 0; |
|
107 master->stats.unmatched = 0; |
|
108 master->stats.t_last = 0; |
112 } |
109 } |
113 |
110 |
114 /*****************************************************************************/ |
111 /*****************************************************************************/ |
115 |
112 |
116 /** |
113 /** |
141 Schliesst das EtherCAT-Geraet, auf dem der Master arbeitet. |
138 Schliesst das EtherCAT-Geraet, auf dem der Master arbeitet. |
142 */ |
139 */ |
143 |
140 |
144 void ec_master_close(ec_master_t *master /**< EtherCAT-Master */) |
141 void ec_master_close(ec_master_t *master /**< EtherCAT-Master */) |
145 { |
142 { |
146 if (!master->device_registered) { |
143 if (!master->device) { |
147 EC_WARN("Warning - Trying to close an unregistered device!\n"); |
144 EC_WARN("Warning - Trying to close an unregistered device!\n"); |
148 return; |
145 return; |
149 } |
146 } |
150 |
147 |
151 if (ec_device_close(&master->device) < 0) |
148 if (ec_device_close(master->device)) |
152 EC_WARN("Warning - Could not close device!\n"); |
149 EC_WARN("Warning - Could not close device!\n"); |
|
150 } |
|
151 |
|
152 /*****************************************************************************/ |
|
153 |
|
154 /** |
|
155 Stellt ein Kommando in die Warteschlange. |
|
156 */ |
|
157 |
|
158 void ec_master_queue_command(ec_master_t *master, /**< EtherCAT-Master */ |
|
159 ec_command_t *command /**< Kommando */ |
|
160 ) |
|
161 { |
|
162 ec_command_t *queued_command; |
|
163 |
|
164 // Ist das Kommando schon in der Warteschlange? |
|
165 list_for_each_entry(queued_command, &master->commands, list) { |
|
166 if (queued_command == command) { |
|
167 command->state = EC_CMD_QUEUED; |
|
168 if (unlikely(master->debug_level)) |
|
169 EC_WARN("command already queued.\n"); |
|
170 return; |
|
171 } |
|
172 } |
|
173 |
|
174 list_add_tail(&command->list, &master->commands); |
|
175 command->state = EC_CMD_QUEUED; |
|
176 } |
|
177 |
|
178 /*****************************************************************************/ |
|
179 |
|
180 /** |
|
181 Sendet die Kommandos in der Warteschlange. |
|
182 |
|
183 \return 0 bei Erfolg, sonst < 0 |
|
184 */ |
|
185 |
|
186 void ec_master_send_commands(ec_master_t *master /**< EtherCAT-Master */) |
|
187 { |
|
188 ec_command_t *command; |
|
189 size_t command_size; |
|
190 uint8_t *frame_data, *cur_data; |
|
191 void *follows_word; |
|
192 cycles_t start = 0, end; |
|
193 |
|
194 if (unlikely(master->debug_level > 0)) { |
|
195 EC_DBG("ec_master_send\n"); |
|
196 start = get_cycles(); |
|
197 } |
|
198 |
|
199 // Zeiger auf Socket-Buffer holen |
|
200 frame_data = ec_device_tx_data(master->device); |
|
201 cur_data = frame_data + EC_FRAME_HEADER_SIZE; |
|
202 follows_word = NULL; |
|
203 |
|
204 // Aktuellen Frame mit Kommandos füllen |
|
205 list_for_each_entry(command, &master->commands, list) { |
|
206 if (command->state != EC_CMD_QUEUED) continue; |
|
207 |
|
208 // Passt das aktuelle Kommando noch in den aktuellen Rahmen? |
|
209 command_size = EC_COMMAND_HEADER_SIZE + command->data_size |
|
210 + EC_COMMAND_FOOTER_SIZE; |
|
211 if (cur_data - frame_data + command_size > EC_MAX_FRAME_SIZE) break; |
|
212 |
|
213 command->state = EC_CMD_SENT; |
|
214 command->index = master->command_index++; |
|
215 |
|
216 if (unlikely(master->debug_level > 0)) |
|
217 EC_DBG("adding command 0x%02X\n", command->index); |
|
218 |
|
219 // Command-Following-Flag im letzten Kommando setzen |
|
220 if (follows_word) |
|
221 EC_WRITE_U16(follows_word, EC_READ_U16(follows_word) | 0x8000); |
|
222 |
|
223 // EtherCAT command header |
|
224 EC_WRITE_U8 (cur_data, command->type); |
|
225 EC_WRITE_U8 (cur_data + 1, command->index); |
|
226 EC_WRITE_U32(cur_data + 2, command->address.logical); |
|
227 EC_WRITE_U16(cur_data + 6, command->data_size & 0x7FF); |
|
228 EC_WRITE_U16(cur_data + 8, 0x0000); |
|
229 follows_word = cur_data + 6; |
|
230 cur_data += EC_COMMAND_HEADER_SIZE; |
|
231 |
|
232 // EtherCAT command data |
|
233 memcpy(cur_data, command->data, command->data_size); |
|
234 cur_data += command->data_size; |
|
235 |
|
236 // EtherCAT command footer |
|
237 EC_WRITE_U16(cur_data, command->working_counter); |
|
238 cur_data += EC_COMMAND_FOOTER_SIZE; |
|
239 } |
|
240 |
|
241 if (cur_data - frame_data == EC_FRAME_HEADER_SIZE) { |
|
242 if (unlikely(master->debug_level > 0)) EC_DBG("nothing to send.\n"); |
|
243 return; |
|
244 } |
|
245 |
|
246 // EtherCAT frame header |
|
247 EC_WRITE_U16(frame_data, ((cur_data - frame_data |
|
248 - EC_FRAME_HEADER_SIZE) & 0x7FF) | 0x1000); |
|
249 |
|
250 // Rahmen auffüllen |
|
251 while (cur_data - frame_data < EC_MIN_FRAME_SIZE) |
|
252 EC_WRITE_U8(cur_data++, 0x00); |
|
253 |
|
254 if (unlikely(master->debug_level > 0)) |
|
255 EC_DBG("Frame size: %i\n", cur_data - frame_data); |
|
256 |
|
257 // Send frame |
|
258 ec_device_send(master->device, cur_data - frame_data); |
|
259 |
|
260 if (unlikely(master->debug_level > 0)) { |
|
261 end = get_cycles(); |
|
262 EC_DBG("ec_master_send finished in %ius.\n", |
|
263 (u32) (end - start) * 1000 / cpu_khz); |
|
264 } |
|
265 } |
|
266 |
|
267 /*****************************************************************************/ |
|
268 |
|
269 /** |
|
270 Wertet einen empfangenen Rahmen aus. |
|
271 |
|
272 \return 0 bei Erfolg, sonst < 0 |
|
273 */ |
|
274 |
|
275 void ec_master_receive(ec_master_t *master, /**< EtherCAT-Master */ |
|
276 const uint8_t *frame_data, /**< Empfangene Daten */ |
|
277 size_t size /**< Anzahl empfangene Datenbytes */ |
|
278 ) |
|
279 { |
|
280 size_t frame_size, data_size; |
|
281 uint8_t command_type, command_index; |
|
282 unsigned int cmd_follows, matched; |
|
283 const uint8_t *cur_data; |
|
284 ec_command_t *command; |
|
285 |
|
286 if (unlikely(size < EC_FRAME_HEADER_SIZE)) { |
|
287 master->stats.corrupted++; |
|
288 ec_master_output_stats(master); |
|
289 return; |
|
290 } |
|
291 |
|
292 cur_data = frame_data; |
|
293 |
|
294 // Länge des gesamten Frames prüfen |
|
295 frame_size = EC_READ_U16(cur_data) & 0x07FF; |
|
296 cur_data += EC_FRAME_HEADER_SIZE; |
|
297 |
|
298 if (unlikely(frame_size > size)) { |
|
299 master->stats.corrupted++; |
|
300 ec_master_output_stats(master); |
|
301 return; |
|
302 } |
|
303 |
|
304 cmd_follows = 1; |
|
305 while (cmd_follows) { |
|
306 // Kommando-Header auswerten |
|
307 command_type = EC_READ_U8 (cur_data); |
|
308 command_index = EC_READ_U8 (cur_data + 1); |
|
309 data_size = EC_READ_U16(cur_data + 6) & 0x07FF; |
|
310 cmd_follows = EC_READ_U16(cur_data + 6) & 0x8000; |
|
311 cur_data += EC_COMMAND_HEADER_SIZE; |
|
312 |
|
313 if (unlikely(cur_data - frame_data |
|
314 + data_size + EC_COMMAND_FOOTER_SIZE > size)) { |
|
315 master->stats.corrupted++; |
|
316 ec_master_output_stats(master); |
|
317 return; |
|
318 } |
|
319 |
|
320 // Suche passendes Kommando in der Liste |
|
321 matched = 0; |
|
322 list_for_each_entry(command, &master->commands, list) { |
|
323 if (command->state == EC_CMD_SENT |
|
324 && command->type == command_type |
|
325 && command->index == command_index |
|
326 && command->data_size == data_size) { |
|
327 matched = 1; |
|
328 break; |
|
329 } |
|
330 } |
|
331 |
|
332 // Kein passendes Kommando in der Liste gefunden |
|
333 if (!matched) { |
|
334 master->stats.unmatched++; |
|
335 ec_master_output_stats(master); |
|
336 cur_data += data_size + EC_COMMAND_FOOTER_SIZE; |
|
337 continue; |
|
338 } |
|
339 |
|
340 // Empfangene Daten in Kommando-Datenspeicher kopieren |
|
341 memcpy(command->data, cur_data, data_size); |
|
342 cur_data += data_size; |
|
343 |
|
344 // Working-Counter setzen |
|
345 command->working_counter = EC_READ_U16(cur_data); |
|
346 cur_data += EC_COMMAND_FOOTER_SIZE; |
|
347 |
|
348 // Kommando aus der Liste entfernen |
|
349 command->state = EC_CMD_RECEIVED; |
|
350 list_del_init(&command->list); |
|
351 } |
|
352 } |
|
353 |
|
354 /*****************************************************************************/ |
|
355 |
|
356 /** |
|
357 Sendet ein einzelnes Kommando und wartet auf den Empfang. |
|
358 |
|
359 Wenn der Slave nicht antwortet, wird das Kommando |
|
360 nochmals gesendet. |
|
361 |
|
362 \return 0 bei Erfolg, sonst < 0 |
|
363 */ |
|
364 |
|
365 int ec_master_simple_io(ec_master_t *master, /**< EtherCAT-Master */ |
|
366 ec_command_t *command /**< Kommando */ |
|
367 ) |
|
368 { |
|
369 unsigned int response_tries_left; |
|
370 |
|
371 response_tries_left = 10; |
|
372 do |
|
373 { |
|
374 ec_master_queue_command(master, command); |
|
375 EtherCAT_rt_master_xio(master); |
|
376 |
|
377 if (command->state == EC_CMD_RECEIVED) { |
|
378 break; |
|
379 } |
|
380 else if (command->state == EC_CMD_TIMEOUT) { |
|
381 EC_ERR("Simple IO TIMED OUT!\n"); |
|
382 return -1; |
|
383 } |
|
384 else if (command->state == EC_CMD_ERROR) { |
|
385 EC_ERR("Simple IO command error!\n"); |
|
386 return -1; |
|
387 } |
|
388 } |
|
389 while (unlikely(!command->working_counter && --response_tries_left)); |
|
390 |
|
391 if (unlikely(!response_tries_left)) { |
|
392 EC_ERR("No response in simple IO!\n"); |
|
393 return -1; |
|
394 } |
|
395 |
|
396 return 0; |
153 } |
397 } |
154 |
398 |
155 /*****************************************************************************/ |
399 /*****************************************************************************/ |
156 |
400 |
157 /** |
401 /** |
239 } |
481 } |
240 |
482 |
241 /*****************************************************************************/ |
483 /*****************************************************************************/ |
242 |
484 |
243 /** |
485 /** |
244 Ausgaben während des zyklischen Betriebs. |
486 Statistik-Ausgaben während des zyklischen Betriebs. |
245 |
487 |
246 Diese Funktion sorgt dafür, dass Ausgaben (Zählerstände) während |
488 Diese Funktion sorgt dafür, dass Statistiken während des zyklischen |
247 des zyklischen Betriebs nicht zu oft getätigt werden. |
489 Betriebs bei Bedarf, aber nicht zu oft ausgegeben werden. |
248 |
490 |
249 Die Ausgabe erfolgt gesammelt höchstens einmal pro Sekunde. |
491 Die Ausgabe erfolgt gesammelt höchstens einmal pro Sekunde. |
250 */ |
492 */ |
251 |
493 |
252 void ec_cyclic_output(ec_master_t *master /**< EtherCAT-Master */) |
494 void ec_master_output_stats(ec_master_t *master /**< EtherCAT-Master */) |
253 { |
495 { |
254 unsigned long int t; |
496 cycles_t t_now = get_cycles(); |
255 |
497 |
256 rdtscl(t); |
498 if (unlikely((u32) (t_now - master->stats.t_last) / cpu_khz > 1000)) { |
257 |
499 if (master->stats.timeouts) { |
258 if ((t - master->t_last_cyclic_output) / cpu_khz > 1000) { |
500 EC_WARN("%i commands TIMED OUT!\n", master->stats.timeouts); |
259 if (master->frames_lost) { |
501 master->stats.timeouts = 0; |
260 EC_WARN("%u frame(s) LOST!\n", master->frames_lost); |
502 } |
261 master->frames_lost = 0; |
503 if (master->stats.delayed) { |
262 } |
504 EC_WARN("%i frame(s) DELAYED!\n", master->stats.delayed); |
263 if (master->frames_delayed) { |
505 master->stats.delayed = 0; |
264 EC_WARN("%u frame(s) DELAYED!\n", master->frames_delayed); |
506 } |
265 master->frames_delayed = 0; |
507 if (master->stats.corrupted) { |
266 } |
508 EC_WARN("%i frame(s) CORRUPTED!\n", master->stats.corrupted); |
267 master->t_last_cyclic_output = t; |
509 master->stats.corrupted = 0; |
|
510 } |
|
511 if (master->stats.unmatched) { |
|
512 EC_WARN("%i command(s) UNMATCHED!\n", master->stats.unmatched); |
|
513 master->stats.unmatched = 0; |
|
514 } |
|
515 master->stats.t_last = t_now; |
268 } |
516 } |
269 } |
517 } |
270 |
518 |
271 /*****************************************************************************/ |
519 /*****************************************************************************/ |
272 |
520 |
492 ec_slave_check_crc(slave); |
735 ec_slave_check_crc(slave); |
493 |
736 |
494 // Resetting FMMUs |
737 // Resetting FMMUs |
495 if (slave->base_fmmu_count) { |
738 if (slave->base_fmmu_count) { |
496 memset(data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
739 memset(data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
497 ec_frame_init_npwr(&frame, master, slave->station_address, 0x0600, |
740 ec_command_init_npwr(&command, slave->station_address, 0x0600, |
498 EC_FMMU_SIZE * slave->base_fmmu_count, data); |
741 EC_FMMU_SIZE * slave->base_fmmu_count, data); |
499 if (unlikely(ec_frame_send_receive(&frame))) { |
742 if (unlikely(ec_master_simple_io(master, &command))) { |
500 EC_ERR("Resetting FMMUs failed on slave %i!\n", |
743 EC_ERR("Resetting FMMUs failed on slave %i!\n", |
501 slave->ring_position); |
744 slave->ring_position); |
502 return -1; |
745 return -1; |
503 } |
746 } |
504 } |
747 } |
505 |
748 |
506 // Resetting Sync Manager channels |
749 // Resetting Sync Manager channels |
507 if (slave->base_sync_count) { |
750 if (slave->base_sync_count) { |
508 memset(data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); |
751 memset(data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); |
509 ec_frame_init_npwr(&frame, master, slave->station_address, 0x0800, |
752 ec_command_init_npwr(&command, slave->station_address, 0x0800, |
510 EC_SYNC_SIZE * slave->base_sync_count, data); |
753 EC_SYNC_SIZE * slave->base_sync_count, data); |
511 if (unlikely(ec_frame_send_receive(&frame))) { |
754 if (unlikely(ec_master_simple_io(master, &command))) { |
512 EC_ERR("Resetting sync managers failed on slave %i!\n", |
755 EC_ERR("Resetting sync managers failed on slave %i!\n", |
513 slave->ring_position); |
756 slave->ring_position); |
514 return -1; |
757 return -1; |
515 } |
758 } |
516 } |
759 } |
598 } |
841 } |
599 |
842 |
600 /*****************************************************************************/ |
843 /*****************************************************************************/ |
601 |
844 |
602 /** |
845 /** |
|
846 Sendet und empfängt Kommandos. |
|
847 |
|
848 \return 0 bei Erfolg, sonst < 0 |
|
849 */ |
|
850 |
|
851 void EtherCAT_rt_master_xio(ec_master_t *master) |
|
852 { |
|
853 ec_command_t *command, *next; |
|
854 unsigned int commands_sent; |
|
855 cycles_t t_start, t_end, t_timeout; |
|
856 |
|
857 ec_master_output_stats(master); |
|
858 |
|
859 if (unlikely(!master->device->link_state)) { |
|
860 // Link DOWN, keines der Kommandos kann gesendet werden. |
|
861 list_for_each_entry_safe(command, next, &master->commands, list) { |
|
862 command->state = EC_CMD_ERROR; |
|
863 list_del_init(&command->list); |
|
864 } |
|
865 |
|
866 // Device-Zustand abfragen |
|
867 ec_device_call_isr(master->device); |
|
868 return; |
|
869 } |
|
870 |
|
871 // Rahmen senden |
|
872 ec_master_send_commands(master); |
|
873 |
|
874 t_start = get_cycles(); // Sendezeit nehmen |
|
875 t_timeout = 100 * cpu_khz / 1000; // 100us |
|
876 |
|
877 do { |
|
878 ec_device_call_isr(master->device); |
|
879 |
|
880 t_end = get_cycles(); // Aktuelle Zeit nehmen |
|
881 if (t_end - t_start >= t_timeout) break; // Timeout |
|
882 |
|
883 commands_sent = 0; |
|
884 list_for_each_entry_safe(command, next, &master->commands, list) { |
|
885 if (command->state == EC_CMD_RECEIVED) |
|
886 list_del_init(&command->list); |
|
887 else if (command->state == EC_CMD_SENT) |
|
888 commands_sent++; |
|
889 } |
|
890 } while (commands_sent); |
|
891 |
|
892 // Zeit abgelaufen. Alle verbleibenden Kommandos entfernen. |
|
893 list_for_each_entry_safe(command, next, &master->commands, list) { |
|
894 switch (command->state) { |
|
895 case EC_CMD_SENT: |
|
896 case EC_CMD_QUEUED: |
|
897 command->state = EC_CMD_TIMEOUT; |
|
898 master->stats.timeouts++; |
|
899 ec_master_output_stats(master); |
|
900 break; |
|
901 case EC_CMD_RECEIVED: |
|
902 master->stats.delayed++; |
|
903 ec_master_output_stats(master); |
|
904 break; |
|
905 default: |
|
906 break; |
|
907 } |
|
908 list_del_init(&command->list); |
|
909 } |
|
910 } |
|
911 |
|
912 /*****************************************************************************/ |
|
913 |
|
914 /** |
603 Setzt die Debug-Ebene des Masters. |
915 Setzt die Debug-Ebene des Masters. |
604 |
916 |
605 Folgende Debug-level sind definiert: |
917 Folgende Debug-Level sind definiert: |
606 |
918 |
607 - 1: Nur Positionsmarken in bestimmten Funktionen |
919 - 1: Nur Positionsmarken in bestimmten Funktionen |
608 - 2: Komplette Frame-Inhalte |
920 - 2: Komplette Frame-Inhalte |
609 */ |
921 */ |
610 |
922 |