IgH EtherCAT Master  1.6.12
datagram.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 2006-2026 Florian Pose, Ingenieurgemeinschaft IgH
4 *
5 * This file is part of the IgH EtherCAT Master.
6 *
7 * The IgH EtherCAT Master is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version 2, as
9 * published by the Free Software Foundation.
10 *
11 * The IgH EtherCAT Master is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 * Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with the IgH EtherCAT Master; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 ****************************************************************************/
21
26
27/****************************************************************************/
28
29#include <linux/slab.h>
30
31#include "datagram.h"
32#include "master.h"
33
34/****************************************************************************/
35
37
38#define EC_FUNC_HEADER \
39 ret = ec_datagram_prealloc(datagram, data_size); \
40 if (unlikely(ret)) \
41 return ret; \
42 datagram->index = 0; \
43 datagram->working_counter = 0; \
44 datagram->state = EC_DATAGRAM_INIT;
45
46#define EC_FUNC_FOOTER \
47 datagram->data_size = data_size; \
48 return 0;
49
51
52/****************************************************************************/
53
58static const char *type_strings[] = {
59 "?",
60 "APRD",
61 "APWR",
62 "APRW",
63 "FPRD",
64 "FPWR",
65 "FPRW",
66 "BRD",
67 "BWR",
68 "BRW",
69 "LRD",
70 "LWR",
71 "LRW",
72 "ARMW",
73 "FRMW"
74};
75
76/****************************************************************************/
77
81{
82 INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
83 datagram->device_index = EC_DEVICE_MAIN;
84 datagram->type = EC_DATAGRAM_NONE;
85 memset(datagram->address, 0x00, EC_ADDR_LEN);
86 datagram->data = NULL;
87 datagram->data_origin = EC_ORIG_INTERNAL;
88 datagram->mem_size = 0;
89 datagram->data_size = 0;
90 datagram->index = 0x00;
91 datagram->working_counter = 0x0000;
92 datagram->state = EC_DATAGRAM_INIT;
93#ifdef EC_HAVE_CYCLES
94 datagram->cycles_sent = 0;
95#endif
96 datagram->jiffies_sent = 0;
97#ifdef EC_HAVE_CYCLES
98 datagram->cycles_received = 0;
99#endif
100 datagram->jiffies_received = 0;
101 datagram->skip_count = 0;
102 datagram->stats_output_jiffies = 0;
103 memset(datagram->name, 0x00, EC_DATAGRAM_NAME_SIZE);
104}
105
106/****************************************************************************/
107
111{
112 ec_datagram_unqueue(datagram);
113
114 if (datagram->data_origin == EC_ORIG_INTERNAL && datagram->data) {
115 kfree(datagram->data);
116 datagram->data = NULL;
117 }
118}
119
120/****************************************************************************/
121
125{
126 if (!list_empty(&datagram->queue)) {
127 list_del_init(&datagram->queue);
128 }
129}
130
131/****************************************************************************/
132
143 ec_datagram_t *datagram,
144 size_t size
145 )
146{
147 if (datagram->data_origin == EC_ORIG_EXTERNAL
148 || size <= datagram->mem_size) {
149 return 0;
150 }
151
152 if (size > EC_MAX_DATA_SIZE) {
153 EC_ERR("%s(datagram = %p, size = %zu): Exceeding the"
154 " maximum datagram size of %u bytes.\n",
155 __func__, datagram, size, EC_MAX_DATA_SIZE);
156 return -EOVERFLOW;
157 }
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:142
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:58
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:110
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:124
void ec_datagram_init(ec_datagram_t *datagram)
Constructor.
Definition datagram.c:80
EtherCAT datagram structure.
@ EC_DATAGRAM_FPWR
Configured Address Physical Write.
Definition datagram.h:48
@ EC_DATAGRAM_APRW
Auto Increment Physical ReadWrite.
Definition datagram.h:46
@ EC_DATAGRAM_ARMW
Auto Increment Physical Read Multiple Write.
Definition datagram.h:56
@ EC_DATAGRAM_FPRD
Configured Address Physical Read.
Definition datagram.h:47
@ EC_DATAGRAM_NONE
Dummy.
Definition datagram.h:43
@ EC_DATAGRAM_APRD
Auto Increment Physical Read.
Definition datagram.h:44
@ EC_DATAGRAM_BRD
Broadcast Read.
Definition datagram.h:50
@ EC_DATAGRAM_LRW
Logical ReadWrite.
Definition datagram.h:55
@ EC_DATAGRAM_BRW
Broadcast ReadWrite.
Definition datagram.h:52
@ EC_DATAGRAM_LWR
Logical Write.
Definition datagram.h:54
@ EC_DATAGRAM_FRMW
Configured Address Physical Read Multiple Write.
Definition datagram.h:58
@ EC_DATAGRAM_FPRW
Configured Address Physical ReadWrite.
Definition datagram.h:49
@ EC_DATAGRAM_BWR
Broadcast Write.
Definition datagram.h:51
@ EC_DATAGRAM_APWR
Auto Increment Physical Write.
Definition datagram.h:45
@ EC_DATAGRAM_LRD
Logical Read.
Definition datagram.h:53
@ EC_DATAGRAM_INIT
Initial state of a new datagram.
Definition datagram.h:67
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
@ EC_DATAGRAM_SENT
Sent (still in the queue).
Definition datagram.h:69
@ EC_DATAGRAM_QUEUED
Queued for sending.
Definition datagram.h:68
@ EC_DATAGRAM_ERROR
Error while sending/receiving (dequeued).
Definition datagram.h:72
#define EC_MAX_DATA_SIZE
Resulting maximum data size of a single datagram in a frame.
Definition globals.h:79
#define EC_WARN(fmt, args...)
Convenience macro for printing EtherCAT-specific warnings to syslog.
Definition globals.h:233
#define EC_ADDR_LEN
Size of the EtherCAT address field.
Definition globals.h:76
@ EC_ORIG_EXTERNAL
External.
Definition globals.h:304
@ EC_ORIG_INTERNAL
Internal.
Definition globals.h:303
#define EC_DATAGRAM_NAME_SIZE
Size of the datagram description string.
Definition globals.h:104
@ EC_DEVICE_MAIN
Main device.
Definition globals.h:198
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition globals.h:223
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition ecrt.h:3074
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition ecrt.h:3057
#define EC_WRITE_S16(DATA, VAL)
Write a 16-bit signed value to EtherCAT data.
Definition ecrt.h:3067
EtherCAT master structure.
EtherCAT datagram.
Definition datagram.h:79
size_t mem_size
Datagram data memory size.
Definition datagram.h:90
uint16_t working_counter
Working counter.
Definition datagram.h:93
size_t data_size
Size of the data in data.
Definition datagram.h:91
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition datagram.h:102
ec_datagram_type_t type
Datagram type (APRD, BWR, etc.).
Definition datagram.h:86
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition datagram.h:98
struct list_head queue
Master datagram queue item, protected by user-supplied mutex.
Definition datagram.h:80
uint8_t index
Index (set by master).
Definition datagram.h:92
ec_datagram_state_t state
State.
Definition datagram.h:94
ec_device_index_t device_index
Device via which the datagram shall be / was sent.
Definition datagram.h:84
unsigned long stats_output_jiffies
Last statistics output.
Definition datagram.h:105
uint8_t address[EC_ADDR_LEN]
Recipient address.
Definition datagram.h:87
uint8_t * data
Datagram payload.
Definition datagram.h:88
ec_origin_t data_origin
Origin of the data memory.
Definition datagram.h:89
char name[EC_DATAGRAM_NAME_SIZE]
Description of the datagram.
Definition datagram.h:106
unsigned int skip_count
Number of requeues when not yet received.
Definition datagram.h:104