IgH EtherCAT Master  1.6.10
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 
27 /****************************************************************************/
28 
29 #include <linux/slab.h>
30 
31 #include "datagram.h"
32 #include "master.h"
33 
34 /****************************************************************************/
35 
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 
52 /****************************************************************************/
53 
58 static 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;
574  case EC_DATAGRAM_QUEUED:
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;
586  case EC_DATAGRAM_ERROR:
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 /****************************************************************************/
#define EC_WARN(fmt, args...)
Convenience macro for printing EtherCAT-specific warnings to syslog.
Definition: globals.h:233
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:98
Auto Increment Physical Read Multiple Write.
Definition: datagram.h:56
#define EC_ADDR_LEN
Size of the EtherCAT address field.
Definition: globals.h:76
static const char * type_strings[]
Array of datagram type strings used in ec_datagram_type_string().
Definition: datagram.c:58
#define EC_DATAGRAM_NAME_SIZE
Size of the datagram description string.
Definition: globals.h:104
Auto Increment Physical ReadWrite.
Definition: datagram.h:46
size_t data_size
Size of the data in data.
Definition: datagram.h:91
Broadcast ReadWrite.
Definition: datagram.h:52
unsigned long stats_output_jiffies
Last statistics output.
Definition: datagram.h:105
ec_origin_t data_origin
Origin of the data memory.
Definition: datagram.h:89
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
EtherCAT datagram.
Definition: datagram.h:79
Logical Read.
Definition: datagram.h:53
char name[EC_DATAGRAM_NAME_SIZE]
Description of the datagram.
Definition: datagram.h:106
uint16_t working_counter
Working counter.
Definition: datagram.h:93
#define EC_WRITE_S16(DATA, VAL)
Write a 16-bit signed value to EtherCAT data.
Definition: ecrt.h:3164
Sent (still in the queue).
Definition: datagram.h:69
Configured Address Physical Read.
Definition: datagram.h:47
void ec_datagram_output_stats(ec_datagram_t *datagram)
Outputs datagram statistics at most every second.
Definition: datagram.c:622
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_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
ec_datagram_type_t type
Datagram type (APRD, BWR, etc.).
Definition: datagram.h:86
Logical Write.
Definition: datagram.h:54
EtherCAT master structure.
Internal.
Definition: globals.h:303
Initial state of a new datagram.
Definition: datagram.h:67
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
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
ec_datagram_state_t state
State.
Definition: datagram.h:94
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3171
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
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3154
External.
Definition: globals.h:304
Main device.
Definition: globals.h:198
unsigned int skip_count
Number of requeues when not yet received.
Definition: datagram.h:104
Auto Increment Physical Read.
Definition: datagram.h:44
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_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
void ec_datagram_unqueue(ec_datagram_t *datagram)
Unqueue datagram.
Definition: datagram.c:124
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
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
EtherCAT datagram structure.
Broadcast Write.
Definition: datagram.h:51
ec_device_index_t device_index
Device via which the datagram shall be / was sent.
Definition: datagram.h:84
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_lrd(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRD datagram.
Definition: datagram.c:433
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_prealloc(ec_datagram_t *datagram, size_t size)
Allocates internal payload memory.
Definition: datagram.c:142
Configured Address Physical Read Multiple Write.
Definition: datagram.h:58
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:223
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_init(ec_datagram_t *datagram)
Constructor.
Definition: datagram.c:80
Queued for sending.
Definition: datagram.h:68
Logical ReadWrite.
Definition: datagram.h:55
Timed out (dequeued).
Definition: datagram.h:71
Broadcast Read.
Definition: datagram.h:50
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
const char * ec_datagram_type_string(const ec_datagram_t *datagram)
Returns a string describing the datagram type.
Definition: datagram.c:645
uint8_t * data
Datagram payload.
Definition: datagram.h:88
Configured Address Physical ReadWrite.
Definition: datagram.h:49
struct list_head queue
Master datagram queue item, protected by user-supplied mutex.
Definition: datagram.h:80
size_t mem_size
Datagram data memory size.
Definition: datagram.h:90
Error while sending/receiving (dequeued).
Definition: datagram.h:72
Auto Increment Physical Write.
Definition: datagram.h:45
uint8_t address[EC_ADDR_LEN]
Recipient address.
Definition: datagram.h:87
Received (dequeued).
Definition: datagram.h:70
Configured Address Physical Write.
Definition: datagram.h:48
uint8_t index
Index (set by master).
Definition: datagram.h:92
int ec_datagram_lrw(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRW datagram.
Definition: datagram.c:471
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:102
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
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
#define EC_MAX_DATA_SIZE
Resulting maximum data size of a single datagram in a frame.
Definition: globals.h:79
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:110