IgH EtherCAT Master  1.5.3
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 
66 static 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;
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:225
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
Auto Increment Physical Read Multiple Write.
Definition: datagram.h:64
#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:66
#define EC_DATAGRAM_NAME_SIZE
Size of the datagram description string.
Definition: globals.h:104
Auto Increment Physical ReadWrite.
Definition: datagram.h:54
size_t data_size
Size of the data in data.
Definition: datagram.h:97
Broadcast ReadWrite.
Definition: datagram.h:60
unsigned long stats_output_jiffies
Last statistics output.
Definition: datagram.h:111
ec_origin_t data_origin
Origin of the data memory.
Definition: datagram.h:95
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:87
Logical Read.
Definition: datagram.h:61
char name[EC_DATAGRAM_NAME_SIZE]
Description of the datagram.
Definition: datagram.h:112
uint16_t working_counter
Working counter.
Definition: datagram.h:99
#define EC_WRITE_S16(DATA, VAL)
Write a 16-bit signed value to EtherCAT data.
Definition: ecrt.h:2428
Sent (still in the queue).
Definition: datagram.h:77
Configured Address Physical Read.
Definition: datagram.h:55
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:92
Logical Write.
Definition: datagram.h:62
EtherCAT master structure.
Internal.
Definition: globals.h:295
Initial state of a new datagram.
Definition: datagram.h:75
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:100
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2435
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:2418
External.
Definition: globals.h:296
Main device.
Definition: globals.h:190
unsigned int skip_count
Number of requeues when not yet received.
Definition: datagram.h:110
Auto Increment Physical Read.
Definition: datagram.h:52
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:132
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:59
ec_device_index_t device_index
Device via which the datagram shall be / was sent.
Definition: datagram.h:90
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:150
Configured Address Physical Read Multiple Write.
Definition: datagram.h:66
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:215
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:88
Queued for sending.
Definition: datagram.h:76
Logical ReadWrite.
Definition: datagram.h:63
Timed out (dequeued).
Definition: datagram.h:79
Broadcast Read.
Definition: datagram.h:58
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:94
Configured Address Physical ReadWrite.
Definition: datagram.h:57
struct list_head queue
Master datagram queue item.
Definition: datagram.h:88
size_t mem_size
Datagram data memory size.
Definition: datagram.h:96
Error while sending/receiving (dequeued).
Definition: datagram.h:80
Auto Increment Physical Write.
Definition: datagram.h:53
uint8_t address[EC_ADDR_LEN]
Recipient address.
Definition: datagram.h:93
Received (dequeued).
Definition: datagram.h:78
Configured Address Physical Write.
Definition: datagram.h:56
uint8_t index
Index (set by master).
Definition: datagram.h:98
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:108
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
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:118