1 /****************************************************************************** |
|
2 * |
|
3 * f r a m e . c |
|
4 * |
|
5 * Methoden für einen EtherCAT-Frame. |
|
6 * |
|
7 * $Id$ |
|
8 * |
|
9 *****************************************************************************/ |
|
10 |
|
11 #include <linux/slab.h> |
|
12 #include <linux/delay.h> |
|
13 |
|
14 #include "../include/EtherCAT_si.h" |
|
15 #include "frame.h" |
|
16 #include "master.h" |
|
17 |
|
18 /*****************************************************************************/ |
|
19 |
|
20 #define EC_FUNC_HEADER \ |
|
21 frame->master = master; \ |
|
22 frame->index = 0; \ |
|
23 frame->working_counter = 0; |
|
24 |
|
25 #define EC_FUNC_WRITE_FOOTER \ |
|
26 frame->data_length = length; \ |
|
27 memcpy(frame->data, data, length); |
|
28 |
|
29 #define EC_FUNC_READ_FOOTER \ |
|
30 frame->data_length = length; \ |
|
31 memset(frame->data, 0x00, length); |
|
32 |
|
33 /*****************************************************************************/ |
|
34 |
|
35 /** |
|
36 Initialisiert ein EtherCAT-NPRD-Kommando. |
|
37 |
|
38 Node-adressed physical read. |
|
39 */ |
|
40 |
|
41 void ec_frame_init_nprd(ec_frame_t *frame, |
|
42 /**< EtherCAT-Rahmen */ |
|
43 ec_master_t *master, |
|
44 /**< EtherCAT-Master */ |
|
45 uint16_t node_address, |
|
46 /**< Adresse des Knotens (Slaves) */ |
|
47 uint16_t offset, |
|
48 /**< Physikalische Speicheradresse im Slave */ |
|
49 unsigned int length |
|
50 /**< Länge der zu lesenden Daten */ |
|
51 ) |
|
52 { |
|
53 if (unlikely(node_address == 0x0000)) |
|
54 EC_WARN("Using node address 0x0000!\n"); |
|
55 |
|
56 EC_FUNC_HEADER; |
|
57 |
|
58 frame->type = ec_frame_type_nprd; |
|
59 frame->address.physical.slave = node_address; |
|
60 frame->address.physical.mem = offset; |
|
61 |
|
62 EC_FUNC_READ_FOOTER; |
|
63 } |
|
64 |
|
65 /*****************************************************************************/ |
|
66 |
|
67 /** |
|
68 Initialisiert ein EtherCAT-NPWR-Kommando. |
|
69 |
|
70 Node-adressed physical write. |
|
71 */ |
|
72 |
|
73 void ec_frame_init_npwr(ec_frame_t *frame, |
|
74 /**< EtherCAT-Rahmen */ |
|
75 ec_master_t *master, |
|
76 /**< EtherCAT-Master */ |
|
77 uint16_t node_address, |
|
78 /**< Adresse des Knotens (Slaves) */ |
|
79 uint16_t offset, |
|
80 /**< Physikalische Speicheradresse im Slave */ |
|
81 unsigned int length, |
|
82 /**< Länge der zu schreibenden Daten */ |
|
83 const uint8_t *data |
|
84 /**< Zeiger auf Speicher mit zu schreibenden Daten */ |
|
85 ) |
|
86 { |
|
87 if (unlikely(node_address == 0x0000)) |
|
88 EC_WARN("Using node address 0x0000!\n"); |
|
89 |
|
90 EC_FUNC_HEADER; |
|
91 |
|
92 frame->type = ec_frame_type_npwr; |
|
93 frame->address.physical.slave = node_address; |
|
94 frame->address.physical.mem = offset; |
|
95 |
|
96 EC_FUNC_WRITE_FOOTER; |
|
97 } |
|
98 |
|
99 /*****************************************************************************/ |
|
100 |
|
101 /** |
|
102 Initialisiert ein EtherCAT-APRD-Kommando. |
|
103 |
|
104 Autoincrement physical read. |
|
105 */ |
|
106 |
|
107 void ec_frame_init_aprd(ec_frame_t *frame, |
|
108 /**< EtherCAT-Rahmen */ |
|
109 ec_master_t *master, |
|
110 /**< EtherCAT-Master */ |
|
111 uint16_t ring_position, |
|
112 /**< Position des Slaves im Bus */ |
|
113 uint16_t offset, |
|
114 /**< Physikalische Speicheradresse im Slave */ |
|
115 unsigned int length |
|
116 /**< Länge der zu lesenden Daten */ |
|
117 ) |
|
118 { |
|
119 EC_FUNC_HEADER; |
|
120 |
|
121 frame->type = ec_frame_type_aprd; |
|
122 frame->address.physical.slave = (int16_t) ring_position * (-1); |
|
123 frame->address.physical.mem = offset; |
|
124 |
|
125 EC_FUNC_READ_FOOTER; |
|
126 } |
|
127 |
|
128 /*****************************************************************************/ |
|
129 |
|
130 /** |
|
131 Initialisiert ein EtherCAT-APWR-Kommando. |
|
132 |
|
133 Autoincrement physical write. |
|
134 */ |
|
135 |
|
136 void ec_frame_init_apwr(ec_frame_t *frame, |
|
137 /**< EtherCAT-Rahmen */ |
|
138 ec_master_t *master, |
|
139 /**< EtherCAT-Master */ |
|
140 uint16_t ring_position, |
|
141 /**< Position des Slaves im Bus */ |
|
142 uint16_t offset, |
|
143 /**< Physikalische Speicheradresse im Slave */ |
|
144 unsigned int length, |
|
145 /**< Länge der zu schreibenden Daten */ |
|
146 const uint8_t *data |
|
147 /**< Zeiger auf Speicher mit zu schreibenden Daten */ |
|
148 ) |
|
149 { |
|
150 EC_FUNC_HEADER; |
|
151 |
|
152 frame->type = ec_frame_type_apwr; |
|
153 frame->address.physical.slave = (int16_t) ring_position * (-1); |
|
154 frame->address.physical.mem = offset; |
|
155 |
|
156 EC_FUNC_WRITE_FOOTER; |
|
157 } |
|
158 |
|
159 /*****************************************************************************/ |
|
160 |
|
161 /** |
|
162 Initialisiert ein EtherCAT-BRD-Kommando. |
|
163 |
|
164 Broadcast read. |
|
165 */ |
|
166 |
|
167 void ec_frame_init_brd(ec_frame_t *frame, |
|
168 /**< EtherCAT-Rahmen */ |
|
169 ec_master_t *master, |
|
170 /**< EtherCAT-Master */ |
|
171 uint16_t offset, |
|
172 /**< Physikalische Speicheradresse im Slave */ |
|
173 unsigned int length |
|
174 /**< Länge der zu lesenden Daten */ |
|
175 ) |
|
176 { |
|
177 EC_FUNC_HEADER; |
|
178 |
|
179 frame->type = ec_frame_type_brd; |
|
180 frame->address.physical.slave = 0x0000; |
|
181 frame->address.physical.mem = offset; |
|
182 |
|
183 EC_FUNC_READ_FOOTER; |
|
184 } |
|
185 |
|
186 /*****************************************************************************/ |
|
187 |
|
188 /** |
|
189 Initialisiert ein EtherCAT-BWR-Kommando. |
|
190 |
|
191 Broadcast write. |
|
192 */ |
|
193 |
|
194 void ec_frame_init_bwr(ec_frame_t *frame, |
|
195 /**< EtherCAT-Rahmen */ |
|
196 ec_master_t *master, |
|
197 /**< EtherCAT-Master */ |
|
198 uint16_t offset, |
|
199 /**< Physikalische Speicheradresse im Slave */ |
|
200 unsigned int length, |
|
201 /**< Länge der zu schreibenden Daten */ |
|
202 const uint8_t *data |
|
203 /**< Zeiger auf Speicher mit zu schreibenden Daten */ |
|
204 ) |
|
205 { |
|
206 EC_FUNC_HEADER; |
|
207 |
|
208 frame->type = ec_frame_type_bwr; |
|
209 frame->address.physical.slave = 0x0000; |
|
210 frame->address.physical.mem = offset; |
|
211 |
|
212 EC_FUNC_WRITE_FOOTER; |
|
213 } |
|
214 |
|
215 /*****************************************************************************/ |
|
216 |
|
217 /** |
|
218 Initialisiert ein EtherCAT-LRW-Kommando. |
|
219 |
|
220 Logical read write. |
|
221 */ |
|
222 |
|
223 void ec_frame_init_lrw(ec_frame_t *frame, |
|
224 /**< EtherCAT-Rahmen */ |
|
225 ec_master_t *master, |
|
226 /**< EtherCAT-Master */ |
|
227 uint32_t offset, |
|
228 /**< Logische Startadresse */ |
|
229 unsigned int length, |
|
230 /**< Länge der zu lesenden/schreibenden Daten */ |
|
231 uint8_t *data |
|
232 /**< Zeiger auf die Daten */ |
|
233 ) |
|
234 { |
|
235 EC_FUNC_HEADER; |
|
236 |
|
237 frame->type = ec_frame_type_lrw; |
|
238 frame->address.logical = offset; |
|
239 |
|
240 EC_FUNC_WRITE_FOOTER; |
|
241 } |
|
242 |
|
243 /*****************************************************************************/ |
|
244 |
|
245 /** |
|
246 Sendet einen einzelnen EtherCAT-Rahmen. |
|
247 |
|
248 \return 0 bei Erfolg, sonst < 0 |
|
249 */ |
|
250 |
|
251 int ec_frame_send(ec_frame_t *frame /**< Rahmen zum Senden */) |
|
252 { |
|
253 unsigned int command_size, frame_size, i; |
|
254 uint8_t *data; |
|
255 |
|
256 if (unlikely(!frame->master->device.link_state)) |
|
257 return -1; |
|
258 |
|
259 if (unlikely(frame->master->debug_level > 0)) { |
|
260 EC_DBG("ec_frame_send\n"); |
|
261 } |
|
262 |
|
263 command_size = frame->data_length + EC_COMMAND_HEADER_SIZE |
|
264 + EC_COMMAND_FOOTER_SIZE; |
|
265 frame_size = command_size + EC_FRAME_HEADER_SIZE; |
|
266 |
|
267 if (unlikely(frame_size > EC_MAX_FRAME_SIZE)) { |
|
268 EC_ERR("Frame too long (%i)!\n", frame_size); |
|
269 return -1; |
|
270 } |
|
271 |
|
272 if (frame_size < EC_MIN_FRAME_SIZE) frame_size = EC_MIN_FRAME_SIZE; |
|
273 |
|
274 if (unlikely(frame->master->debug_level > 0)) { |
|
275 EC_DBG("Frame length: %i\n", frame_size); |
|
276 } |
|
277 |
|
278 frame->index = frame->master->command_index; |
|
279 frame->master->command_index = (frame->master->command_index + 1) % 0x0100; |
|
280 |
|
281 if (unlikely(frame->master->debug_level > 0)) { |
|
282 EC_DBG("Sending command index 0x%X\n", frame->index); |
|
283 } |
|
284 |
|
285 // Zeiger auf Socket-Buffer holen |
|
286 data = ec_device_prepare(&frame->master->device); |
|
287 |
|
288 // EtherCAT frame header |
|
289 EC_WRITE_U16(data, (command_size & 0x7FF) | 0x1000); |
|
290 data += EC_FRAME_HEADER_SIZE; |
|
291 |
|
292 // EtherCAT command header |
|
293 EC_WRITE_U8 (data, frame->type); |
|
294 EC_WRITE_U8 (data + 1, frame->index); |
|
295 EC_WRITE_U32(data + 2, frame->address.logical); |
|
296 EC_WRITE_U16(data + 6, frame->data_length & 0x7FF); |
|
297 EC_WRITE_U16(data + 8, 0x0000); |
|
298 data += EC_COMMAND_HEADER_SIZE; |
|
299 |
|
300 // EtherCAT command data |
|
301 memcpy(data, frame->data, frame->data_length); |
|
302 data += frame->data_length; |
|
303 |
|
304 // EtherCAT command footer |
|
305 EC_WRITE_U16(data, frame->working_counter); |
|
306 data += EC_COMMAND_FOOTER_SIZE; |
|
307 |
|
308 // Pad with zeros |
|
309 for (i = EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE |
|
310 + frame->data_length + EC_COMMAND_FOOTER_SIZE; |
|
311 i < EC_MIN_FRAME_SIZE; i++) |
|
312 EC_WRITE_U8(data++, 0x00); |
|
313 |
|
314 // Send frame |
|
315 ec_device_send(&frame->master->device, frame_size); |
|
316 |
|
317 return 0; |
|
318 } |
|
319 |
|
320 /*****************************************************************************/ |
|
321 |
|
322 /** |
|
323 Wertet empfangene Daten zu einem Rahmen aus. |
|
324 |
|
325 \return 0 bei Erfolg, sonst < 0 |
|
326 */ |
|
327 |
|
328 int ec_frame_receive(ec_frame_t *frame /**< Gesendeter Rahmen */) |
|
329 { |
|
330 unsigned int received_length, frame_length, data_length; |
|
331 uint8_t *data; |
|
332 uint8_t command_type, command_index; |
|
333 ec_device_t *device; |
|
334 |
|
335 device = &frame->master->device; |
|
336 |
|
337 if (!(received_length = ec_device_received(device))) return -1; |
|
338 |
|
339 device->state = EC_DEVICE_STATE_READY; |
|
340 |
|
341 if (unlikely(received_length < EC_FRAME_HEADER_SIZE)) { |
|
342 EC_ERR("Received frame with incomplete EtherCAT frame header!\n"); |
|
343 ec_device_debug(device); |
|
344 return -1; |
|
345 } |
|
346 |
|
347 data = ec_device_data(device); |
|
348 |
|
349 // Länge des gesamten Frames prüfen |
|
350 frame_length = EC_READ_U16(data) & 0x07FF; |
|
351 data += EC_FRAME_HEADER_SIZE; |
|
352 |
|
353 if (unlikely(frame_length > received_length)) { |
|
354 EC_ERR("Received corrupted frame (length does not match)!\n"); |
|
355 ec_device_debug(device); |
|
356 return -1; |
|
357 } |
|
358 |
|
359 // Command header |
|
360 command_type = EC_READ_U8(data); |
|
361 command_index = EC_READ_U8(data + 1); |
|
362 data_length = EC_READ_U16(data + 6) & 0x07FF; |
|
363 data += EC_COMMAND_HEADER_SIZE; |
|
364 |
|
365 if (unlikely(EC_FRAME_HEADER_SIZE + EC_COMMAND_HEADER_SIZE |
|
366 + data_length + EC_COMMAND_FOOTER_SIZE > received_length)) { |
|
367 EC_ERR("Received frame with incomplete command data!\n"); |
|
368 ec_device_debug(device); |
|
369 return -1; |
|
370 } |
|
371 |
|
372 if (unlikely(frame->type != command_type |
|
373 || frame->index != command_index |
|
374 || frame->data_length != data_length)) |
|
375 { |
|
376 EC_WARN("WARNING - Send/Receive anomaly!\n"); |
|
377 ec_device_debug(device); |
|
378 ec_device_call_isr(device); // Empfangenes "vergessen" |
|
379 return -1; |
|
380 } |
|
381 |
|
382 // Empfangene Daten in Kommandodatenspeicher kopieren |
|
383 memcpy(frame->data, data, data_length); |
|
384 data += data_length; |
|
385 |
|
386 // Working-Counter setzen |
|
387 frame->working_counter = EC_READ_U16(data); |
|
388 |
|
389 return 0; |
|
390 } |
|
391 |
|
392 /*****************************************************************************/ |
|
393 |
|
394 /** |
|
395 Sendet einen einzeln Rahmen und wartet auf dessen Empfang. |
|
396 |
|
397 Wenn der Working-Counter nicht gesetzt wurde, wird der Rahmen |
|
398 nochmals gesendet. |
|
399 |
|
400 \todo Das ist noch nicht schön, da hier zwei Protokollschichten |
|
401 vermischt werden. |
|
402 |
|
403 \return 0 bei Erfolg, sonst < 0 |
|
404 */ |
|
405 |
|
406 int ec_frame_send_receive(ec_frame_t *frame |
|
407 /**< Rahmen zum Senden/Empfangen */ |
|
408 ) |
|
409 { |
|
410 unsigned int timeout_tries_left, response_tries_left; |
|
411 unsigned int tries; |
|
412 |
|
413 tries = 0; |
|
414 response_tries_left = 10; |
|
415 do |
|
416 { |
|
417 tries++; |
|
418 if (unlikely(ec_frame_send(frame) < 0)) { |
|
419 EC_ERR("Frame sending failed!\n"); |
|
420 return -1; |
|
421 } |
|
422 |
|
423 timeout_tries_left = 20; |
|
424 do |
|
425 { |
|
426 udelay(1); |
|
427 ec_device_call_isr(&frame->master->device); |
|
428 timeout_tries_left--; |
|
429 } |
|
430 while (unlikely(!ec_device_received(&frame->master->device) |
|
431 && timeout_tries_left)); |
|
432 |
|
433 if (unlikely(!timeout_tries_left)) { |
|
434 EC_ERR("Frame timeout!\n"); |
|
435 return -1; |
|
436 } |
|
437 |
|
438 if (unlikely(ec_frame_receive(frame) < 0)) { |
|
439 EC_ERR("Frame receiving failed!\n"); |
|
440 return -1; |
|
441 } |
|
442 |
|
443 response_tries_left--; |
|
444 } |
|
445 while (unlikely(!frame->working_counter && response_tries_left)); |
|
446 |
|
447 if (unlikely(!response_tries_left)) { |
|
448 EC_ERR("No response!"); |
|
449 return -1; |
|
450 } |
|
451 |
|
452 if (tries > 1) EC_WARN("%i tries necessary...\n", tries); |
|
453 |
|
454 return 0; |
|
455 } |
|
456 |
|
457 /*****************************************************************************/ |
|
458 |
|
459 /* Emacs-Konfiguration |
|
460 ;;; Local Variables: *** |
|
461 ;;; c-basic-offset:4 *** |
|
462 ;;; End: *** |
|
463 */ |
|