IgH EtherCAT Master  1.5.2
datagram.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 <linux/slab.h>
38
39#include "datagram.h"
40#include "master.h"
41
42/*****************************************************************************/
43
46#define EC_FUNC_HEADER \
47 ret = ec_datagram_prealloc(datagram, data_size); \
48 if (unlikely(ret)) \
49 return ret; \
50 datagram->index = 0; \
51 datagram->working_counter = 0; \
52 datagram->state = EC_DATAGRAM_INIT;
53
54#define EC_FUNC_FOOTER \
55 datagram->data_size = data_size; \
56 return 0;
57
60/*****************************************************************************/
61
66static const char *type_strings[] = {
67 "?",
68 "APRD",
69 "APWR",
70 "APRW",
71 "FPRD",
72 "FPWR",
73 "FPRW",
74 "BRD",
75 "BWR",
76 "BRW",
77 "LRD",
78 "LWR",
79 "LRW",
80 "ARMW",
81 "FRMW"
82};
83
84/*****************************************************************************/
85
89{
90 INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
91 datagram->device_index = EC_DEVICE_MAIN;
92 datagram->type = EC_DATAGRAM_NONE;
93 memset(datagram->address, 0x00, EC_ADDR_LEN);
94 datagram->data = NULL;
95 datagram->data_origin = EC_ORIG_INTERNAL;
96 datagram->mem_size = 0;
97 datagram->data_size = 0;
98 datagram->index = 0x00;
99 datagram->working_counter = 0x0000;
100 datagram->state = EC_DATAGRAM_INIT;
101#ifdef EC_HAVE_CYCLES
102 datagram->cycles_sent = 0;
103#endif
104 datagram->jiffies_sent = 0;
105#ifdef EC_HAVE_CYCLES
106 datagram->cycles_received = 0;
107#endif
108 datagram->jiffies_received = 0;
109 datagram->skip_count = 0;
110 datagram->stats_output_jiffies = 0;
111 memset(datagram->name, 0x00, EC_DATAGRAM_NAME_SIZE);
112}
113
114/*****************************************************************************/
115
119{
120 ec_datagram_unqueue(datagram);
121
122 if (datagram->data_origin == EC_ORIG_INTERNAL && datagram->data) {
123 kfree(datagram->data);
124 datagram->data = NULL;
125 }
126}
127
128/*****************************************************************************/
129
133{
134 if (!list_empty(&datagram->queue)) {
135 list_del_init(&datagram->queue);
136 }
137}
138
139/*****************************************************************************/
140
151 ec_datagram_t *datagram,
152 size_t size
153 )
154{
155 if (datagram->data_origin == EC_ORIG_EXTERNAL
156 || size <= datagram->mem_size)
157 return 0;
158
159 if (datagram->data) {
160 kfree(datagram->data);
161 datagram->data = NULL;
162 datagram->mem_size = 0;
163 }
164
165 if (!(datagram->data = kmalloc(size, GFP_KERNEL))) {
166 EC_ERR("Failed to allocate %zu bytes of datagram memory!\n", size);
167 return -ENOMEM;
168 }
169
170 datagram->mem_size = size;
171 return 0;
172}
173
174/*****************************************************************************/
175
179{
180 memset(datagram->data, 0x00, datagram->data_size);
181}
182
183/*****************************************************************************/
184
190 ec_datagram_t *datagram,
191 uint16_t ring_position,
192 uint16_t mem_address,
193 size_t data_size
194 )
195{
196 int ret;
197 EC_FUNC_HEADER;
198 datagram->type = EC_DATAGRAM_APRD;
199 EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
200 EC_WRITE_U16(datagram->address + 2, mem_address);
201 EC_FUNC_FOOTER;
202}
203
204/*****************************************************************************/
205
211 ec_datagram_t *datagram,
212 uint16_t ring_position,
213 uint16_t mem_address,
214 size_t data_size
215 )
216{
217 int ret;
218 EC_FUNC_HEADER;
219 datagram->type = EC_DATAGRAM_APWR;
220 EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
221 EC_WRITE_U16(datagram->address + 2, mem_address);
222 EC_FUNC_FOOTER;
223}
224
225/*****************************************************************************/
226
232 ec_datagram_t *datagram,
233 uint16_t ring_position,
234 uint16_t mem_address,
235 size_t data_size
236 )
237{
238 int ret;
239 EC_FUNC_HEADER;
240 datagram->type = EC_DATAGRAM_APRW;
241 EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
242 EC_WRITE_U16(datagram->address + 2, mem_address);
243 EC_FUNC_FOOTER;
244}
245
246/*****************************************************************************/
247
253 ec_datagram_t *datagram,
254 uint16_t ring_position,
255 uint16_t mem_address,
256 size_t data_size
257 )
258{
259 int ret;
260 EC_FUNC_HEADER;
261 datagram->type = EC_DATAGRAM_ARMW;
262 EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
263 EC_WRITE_U16(datagram->address + 2, mem_address);
264 EC_FUNC_FOOTER;
265}
266
267/*****************************************************************************/
268
274 ec_datagram_t *datagram,
275 uint16_t configured_address,
276 uint16_t mem_address,
277 size_t data_size
278 )
279{
280 int ret;
281
282 if (unlikely(configured_address == 0x0000))
283 EC_WARN("Using configured station address 0x0000!\n");
284
285 EC_FUNC_HEADER;
286 datagram->type = EC_DATAGRAM_FPRD;
287 EC_WRITE_U16(datagram->address, configured_address);
288 EC_WRITE_U16(datagram->address + 2, mem_address);
289 EC_FUNC_FOOTER;
290}
291
292/*****************************************************************************/
293
299 ec_datagram_t *datagram,
300 uint16_t configured_address,
301 uint16_t mem_address,
302 size_t data_size
303 )
304{
305 int ret;
306
307 if (unlikely(configured_address == 0x0000))
308 EC_WARN("Using configured station address 0x0000!\n");
309
310 EC_FUNC_HEADER;
311 datagram->type = EC_DATAGRAM_FPWR;
312 EC_WRITE_U16(datagram->address, configured_address);
313 EC_WRITE_U16(datagram->address + 2, mem_address);
314 EC_FUNC_FOOTER;
315}
316
317/*****************************************************************************/
318
324 ec_datagram_t *datagram,
325 uint16_t configured_address,
326 uint16_t mem_address,
327 size_t data_size
328 )
329{
330 int ret;
331
332 if (unlikely(configured_address == 0x0000))
333 EC_WARN("Using configured station address 0x0000!\n");
334
335 EC_FUNC_HEADER;
336 datagram->type = EC_DATAGRAM_FPRW;
337 EC_WRITE_U16(datagram->address, configured_address);
338 EC_WRITE_U16(datagram->address + 2, mem_address);
339 EC_FUNC_FOOTER;
340}
341
342/*****************************************************************************/
343
349 ec_datagram_t *datagram,
350 uint16_t configured_address,
351 uint16_t mem_address,
352 size_t data_size
353 )
354{
355 int ret;
356
357 if (unlikely(configured_address == 0x0000))
358 EC_WARN("Using configured station address 0x0000!\n");
359
360 EC_FUNC_HEADER;
361 datagram->type = EC_DATAGRAM_FRMW;
362 EC_WRITE_U16(datagram->address, configured_address);
363 EC_WRITE_U16(datagram->address + 2, mem_address);
364 EC_FUNC_FOOTER;
365}
366
367/*****************************************************************************/
368
374 ec_datagram_t *datagram,
375 uint16_t mem_address,
376 size_t data_size
377 )
378{
379 int ret;
380 EC_FUNC_HEADER;
381 datagram->type = EC_DATAGRAM_BRD;
382 EC_WRITE_U16(datagram->address, 0x0000);
383 EC_WRITE_U16(datagram->address + 2, mem_address);
384 EC_FUNC_FOOTER;
385}
386
387/*****************************************************************************/
388
394 ec_datagram_t *datagram,
395 uint16_t mem_address,
396 size_t data_size
397 )
398{
399 int ret;
400 EC_FUNC_HEADER;
401 datagram->type = EC_DATAGRAM_BWR;
402 EC_WRITE_U16(datagram->address, 0x0000);
403 EC_WRITE_U16(datagram->address + 2, mem_address);
404 EC_FUNC_FOOTER;
405}
406
407/*****************************************************************************/
408
414 ec_datagram_t *datagram,
415 uint16_t mem_address,
416 size_t data_size
417 )
418{
419 int ret;
420 EC_FUNC_HEADER;
421 datagram->type = EC_DATAGRAM_BRW;
422 EC_WRITE_U16(datagram->address, 0x0000);
423 EC_WRITE_U16(datagram->address + 2, mem_address);
424 EC_FUNC_FOOTER;
425}
426
427/*****************************************************************************/
428
434 ec_datagram_t *datagram,
435 uint32_t offset,
436 size_t data_size
437 )
438{
439 int ret;
440 EC_FUNC_HEADER;
441 datagram->type = EC_DATAGRAM_LRD;
442 EC_WRITE_U32(datagram->address, offset);
443 EC_FUNC_FOOTER;
444}
445
446/*****************************************************************************/
447
453 ec_datagram_t *datagram,
454 uint32_t offset,
455 size_t data_size
456 )
457{
458 int ret;
459 EC_FUNC_HEADER;
460 datagram->type = EC_DATAGRAM_LWR;
461 EC_WRITE_U32(datagram->address, offset);
462 EC_FUNC_FOOTER;
463}
464
465/*****************************************************************************/
466
472 ec_datagram_t *datagram,
473 uint32_t offset,
474 size_t data_size
475 )
476{
477 int ret;
478 EC_FUNC_HEADER;
479 datagram->type = EC_DATAGRAM_LRW;
480 EC_WRITE_U32(datagram->address, offset);
481 EC_FUNC_FOOTER;
482}
483
484/*****************************************************************************/
485
494 ec_datagram_t *datagram,
495 uint32_t offset,
496 size_t data_size,
497 uint8_t *external_memory
498 )
499{
500 int ret;
501 datagram->data = external_memory;
502 datagram->data_origin = EC_ORIG_EXTERNAL;
503 EC_FUNC_HEADER;
504 datagram->type = EC_DATAGRAM_LRD;
505 EC_WRITE_U32(datagram->address, offset);
506 EC_FUNC_FOOTER;
507}
508
509/*****************************************************************************/
510
519 ec_datagram_t *datagram,
520 uint32_t offset,
521 size_t data_size,
522 uint8_t *external_memory
523 )
524{
525 int ret;
526 datagram->data = external_memory;
527 datagram->data_origin = EC_ORIG_EXTERNAL;
528 EC_FUNC_HEADER;
529 datagram->type = EC_DATAGRAM_LWR;
530 EC_WRITE_U32(datagram->address, offset);
531 EC_FUNC_FOOTER;
532}
533
534/*****************************************************************************/
535
544 ec_datagram_t *datagram,
545 uint32_t offset,
546 size_t data_size,
547 uint8_t *external_memory
548 )
549{
550 int ret;
551 datagram->data = external_memory;
552 datagram->data_origin = EC_ORIG_EXTERNAL;
553 EC_FUNC_HEADER;
554 datagram->type = EC_DATAGRAM_LRW;
555 EC_WRITE_U32(datagram->address, offset);
556 EC_FUNC_FOOTER;
557}
558
559/*****************************************************************************/
560
566 const ec_datagram_t *datagram
567 )
568{
569 printk(KERN_CONT "Datagram ");
570 switch (datagram->state) {
571 case EC_DATAGRAM_INIT:
572 printk(KERN_CONT "initialized");
573 break;
575 printk(KERN_CONT "queued");
576 break;
577 case EC_DATAGRAM_SENT:
578 printk(KERN_CONT "sent");
579 break;
581 printk(KERN_CONT "received");
582 break;
584 printk(KERN_CONT "timed out");
585 break;
587 printk(KERN_CONT "error");
588 break;
589 default:
590 printk(KERN_CONT "???");
591 }
592
593 printk(KERN_CONT ".\n");
594}
595
596/*****************************************************************************/
597
603 const ec_datagram_t *datagram
604 )
605{
606 if (datagram->working_counter == 0) {
607 printk(KERN_CONT "No response.");
608 }
609 else if (datagram->working_counter > 1) {
610 printk(KERN_CONT "%u slaves responded!", datagram->working_counter);
611 }
612 else {
613 printk(KERN_CONT "Success.");
614 }
615 printk(KERN_CONT "\n");
616}
617
618/*****************************************************************************/
619
623 ec_datagram_t *datagram
624 )
625{
626 if (jiffies - datagram->stats_output_jiffies > HZ) {
627 datagram->stats_output_jiffies = jiffies;
628
629 if (unlikely(datagram->skip_count)) {
630 EC_WARN("Datagram %p (%s) was SKIPPED %u time%s.\n",
631 datagram, datagram->name,
632 datagram->skip_count,
633 datagram->skip_count == 1 ? "" : "s");
634 datagram->skip_count = 0;
635 }
636 }
637}
638
639/*****************************************************************************/
640
646 const ec_datagram_t *datagram
647 )
648{
649 return type_strings[datagram->type];
650}
651
652/*****************************************************************************/
int ec_datagram_brw(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BRW datagram.
Definition: datagram.c:413
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
int ec_datagram_frmw(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FRMW datagram.
Definition: datagram.c:348
int ec_datagram_lrw_ext(ec_datagram_t *datagram, uint32_t offset, size_t data_size, uint8_t *external_memory)
Initializes an EtherCAT LRW datagram with external memory.
Definition: datagram.c:543
int ec_datagram_aprw(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APRW datagram.
Definition: datagram.c:231
int ec_datagram_prealloc(ec_datagram_t *datagram, size_t size)
Allocates internal payload memory.
Definition: datagram.c:150
int ec_datagram_fprw(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRW datagram.
Definition: datagram.c:323
int ec_datagram_lrd_ext(ec_datagram_t *datagram, uint32_t offset, size_t data_size, uint8_t *external_memory)
Initializes an EtherCAT LRD datagram with external memory.
Definition: datagram.c:493
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
int ec_datagram_lwr_ext(ec_datagram_t *datagram, uint32_t offset, size_t data_size, uint8_t *external_memory)
Initializes an EtherCAT LWR datagram with external memory.
Definition: datagram.c:518
int ec_datagram_apwr(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APWR datagram.
Definition: datagram.c:210
int ec_datagram_brd(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BRD datagram.
Definition: datagram.c:373
int ec_datagram_bwr(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BWR datagram.
Definition: datagram.c:393
static const char * type_strings[]
Array of datagram type strings used in ec_datagram_type_string().
Definition: datagram.c:66
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
void ec_datagram_output_stats(ec_datagram_t *datagram)
Outputs datagram statistics at most every second.
Definition: datagram.c:622
int ec_datagram_armw(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT ARMW datagram.
Definition: datagram.c:252
const char * ec_datagram_type_string(const ec_datagram_t *datagram)
Returns a string describing the datagram type.
Definition: datagram.c:645
int ec_datagram_lwr(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LWR datagram.
Definition: datagram.c:452
int ec_datagram_lrd(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRD datagram.
Definition: datagram.c:433
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:118
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
int ec_datagram_lrw(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRW datagram.
Definition: datagram.c:471
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
int ec_datagram_aprd(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APRD datagram.
Definition: datagram.c:189
void ec_datagram_unqueue(ec_datagram_t *datagram)
Unqueue datagram.
Definition: datagram.c:132
void ec_datagram_init(ec_datagram_t *datagram)
Constructor.
Definition: datagram.c:88
EtherCAT datagram structure.
@ EC_DATAGRAM_FPWR
Configured Address Physical Write.
Definition: datagram.h:56
@ EC_DATAGRAM_APRW
Auto Increment Physical ReadWrite.
Definition: datagram.h:54
@ EC_DATAGRAM_ARMW
Auto Increment Physical Read Multiple Write.
Definition: datagram.h:64
@ EC_DATAGRAM_FPRD
Configured Address Physical Read.
Definition: datagram.h:55
@ EC_DATAGRAM_NONE
Dummy.
Definition: datagram.h:51
@ EC_DATAGRAM_APRD
Auto Increment Physical Read.
Definition: datagram.h:52
@ EC_DATAGRAM_BRD
Broadcast Read.
Definition: datagram.h:58
@ EC_DATAGRAM_LRW
Logical ReadWrite.
Definition: datagram.h:63
@ EC_DATAGRAM_BRW
Broadcast ReadWrite.
Definition: datagram.h:60
@ EC_DATAGRAM_LWR
Logical Write.
Definition: datagram.h:62
@ EC_DATAGRAM_FRMW
Configured Address Physical Read Multiple Write.
Definition: datagram.h:66
@ EC_DATAGRAM_FPRW
Configured Address Physical ReadWrite.
Definition: datagram.h:57
@ EC_DATAGRAM_BWR
Broadcast Write.
Definition: datagram.h:59
@ EC_DATAGRAM_APWR
Auto Increment Physical Write.
Definition: datagram.h:53
@ EC_DATAGRAM_LRD
Logical Read.
Definition: datagram.h:61
@ EC_DATAGRAM_INIT
Initial state of a new datagram.
Definition: datagram.h:75
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition: datagram.h:78
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition: datagram.h:79
@ EC_DATAGRAM_SENT
Sent (still in the queue).
Definition: datagram.h:77
@ EC_DATAGRAM_QUEUED
Queued for sending.
Definition: datagram.h:76
@ EC_DATAGRAM_ERROR
Error while sending/receiving (dequeued).
Definition: datagram.h:80
#define EC_WARN(fmt, args...)
Convenience macro for printing EtherCAT-specific warnings to syslog.
Definition: globals.h:225
#define EC_ADDR_LEN
Size of the EtherCAT address field.
Definition: globals.h:76
@ EC_ORIG_EXTERNAL
External.
Definition: globals.h:296
@ EC_ORIG_INTERNAL
Internal.
Definition: globals.h:295
#define EC_DATAGRAM_NAME_SIZE
Size of the datagram description string.
Definition: globals.h:104
@ EC_DEVICE_MAIN
Main device.
Definition: globals.h:190
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:215
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2300
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2283
#define EC_WRITE_S16(DATA, VAL)
Write a 16-bit signed value to EtherCAT data.
Definition: ecrt.h:2293
EtherCAT master structure.
EtherCAT datagram.
Definition: datagram.h:87
size_t mem_size
Datagram data memory size.
Definition: datagram.h:96
uint16_t working_counter
Working counter.
Definition: datagram.h:99
size_t data_size
Size of the data in data.
Definition: datagram.h:97
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
ec_datagram_type_t type
Datagram type (APRD, BWR, etc.).
Definition: datagram.h:92
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
struct list_head queue
Master datagram queue item.
Definition: datagram.h:88
uint8_t index
Index (set by master).
Definition: datagram.h:98
ec_datagram_state_t state
State.
Definition: datagram.h:100
ec_device_index_t device_index
Device via which the datagram shall be / was sent.
Definition: datagram.h:90
unsigned long stats_output_jiffies
Last statistics output.
Definition: datagram.h:111
uint8_t address[EC_ADDR_LEN]
Recipient address.
Definition: datagram.h:93
uint8_t * data
Datagram payload.
Definition: datagram.h:94
ec_origin_t data_origin
Origin of the data memory.
Definition: datagram.h:95
char name[EC_DATAGRAM_NAME_SIZE]
Description of the datagram.
Definition: datagram.h:112
unsigned int skip_count
Number of requeues when not yet received.
Definition: datagram.h:110