IgH EtherCAT Master  1.6.1
datagram.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2008 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  if (datagram->data) {
152  kfree(datagram->data);
153  datagram->data = NULL;
154  datagram->mem_size = 0;
155  }
156 
157  if (!(datagram->data = kmalloc(size, GFP_KERNEL))) {
158  EC_ERR("Failed to allocate %zu bytes of datagram memory!\n", size);
159  return -ENOMEM;
160  }
161 
162  datagram->mem_size = size;
163  return 0;
164 }
165 
166 /****************************************************************************/
167 
171 {
172  memset(datagram->data, 0x00, datagram->data_size);
173 }
174 
175 /****************************************************************************/
176 
182  ec_datagram_t *datagram,
183  uint16_t ring_position,
184  uint16_t mem_address,
185  size_t data_size
186  )
187 {
188  int ret;
189  EC_FUNC_HEADER;
190  datagram->type = EC_DATAGRAM_APRD;
191  EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
192  EC_WRITE_U16(datagram->address + 2, mem_address);
193  EC_FUNC_FOOTER;
194 }
195 
196 /****************************************************************************/
197 
203  ec_datagram_t *datagram,
204  uint16_t ring_position,
205  uint16_t mem_address,
206  size_t data_size
207  )
208 {
209  int ret;
210  EC_FUNC_HEADER;
211  datagram->type = EC_DATAGRAM_APWR;
212  EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
213  EC_WRITE_U16(datagram->address + 2, mem_address);
214  EC_FUNC_FOOTER;
215 }
216 
217 /****************************************************************************/
218 
224  ec_datagram_t *datagram,
225  uint16_t ring_position,
226  uint16_t mem_address,
227  size_t data_size
228  )
229 {
230  int ret;
231  EC_FUNC_HEADER;
232  datagram->type = EC_DATAGRAM_APRW;
233  EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
234  EC_WRITE_U16(datagram->address + 2, mem_address);
235  EC_FUNC_FOOTER;
236 }
237 
238 /****************************************************************************/
239 
245  ec_datagram_t *datagram,
246  uint16_t ring_position,
247  uint16_t mem_address,
248  size_t data_size
249  )
250 {
251  int ret;
252  EC_FUNC_HEADER;
253  datagram->type = EC_DATAGRAM_ARMW;
254  EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1));
255  EC_WRITE_U16(datagram->address + 2, mem_address);
256  EC_FUNC_FOOTER;
257 }
258 
259 /****************************************************************************/
260 
266  ec_datagram_t *datagram,
267  uint16_t configured_address,
268  uint16_t mem_address,
269  size_t data_size
270  )
271 {
272  int ret;
273 
274  if (unlikely(configured_address == 0x0000))
275  EC_WARN("Using configured station address 0x0000!\n");
276 
277  EC_FUNC_HEADER;
278  datagram->type = EC_DATAGRAM_FPRD;
279  EC_WRITE_U16(datagram->address, configured_address);
280  EC_WRITE_U16(datagram->address + 2, mem_address);
281  EC_FUNC_FOOTER;
282 }
283 
284 /****************************************************************************/
285 
291  ec_datagram_t *datagram,
292  uint16_t configured_address,
293  uint16_t mem_address,
294  size_t data_size
295  )
296 {
297  int ret;
298 
299  if (unlikely(configured_address == 0x0000))
300  EC_WARN("Using configured station address 0x0000!\n");
301 
302  EC_FUNC_HEADER;
303  datagram->type = EC_DATAGRAM_FPWR;
304  EC_WRITE_U16(datagram->address, configured_address);
305  EC_WRITE_U16(datagram->address + 2, mem_address);
306  EC_FUNC_FOOTER;
307 }
308 
309 /****************************************************************************/
310 
316  ec_datagram_t *datagram,
317  uint16_t configured_address,
318  uint16_t mem_address,
319  size_t data_size
320  )
321 {
322  int ret;
323 
324  if (unlikely(configured_address == 0x0000))
325  EC_WARN("Using configured station address 0x0000!\n");
326 
327  EC_FUNC_HEADER;
328  datagram->type = EC_DATAGRAM_FPRW;
329  EC_WRITE_U16(datagram->address, configured_address);
330  EC_WRITE_U16(datagram->address + 2, mem_address);
331  EC_FUNC_FOOTER;
332 }
333 
334 /****************************************************************************/
335 
341  ec_datagram_t *datagram,
342  uint16_t configured_address,
343  uint16_t mem_address,
344  size_t data_size
345  )
346 {
347  int ret;
348 
349  if (unlikely(configured_address == 0x0000))
350  EC_WARN("Using configured station address 0x0000!\n");
351 
352  EC_FUNC_HEADER;
353  datagram->type = EC_DATAGRAM_FRMW;
354  EC_WRITE_U16(datagram->address, configured_address);
355  EC_WRITE_U16(datagram->address + 2, mem_address);
356  EC_FUNC_FOOTER;
357 }
358 
359 /****************************************************************************/
360 
366  ec_datagram_t *datagram,
367  uint16_t mem_address,
368  size_t data_size
369  )
370 {
371  int ret;
372  EC_FUNC_HEADER;
373  datagram->type = EC_DATAGRAM_BRD;
374  EC_WRITE_U16(datagram->address, 0x0000);
375  EC_WRITE_U16(datagram->address + 2, mem_address);
376  EC_FUNC_FOOTER;
377 }
378 
379 /****************************************************************************/
380 
386  ec_datagram_t *datagram,
387  uint16_t mem_address,
388  size_t data_size
389  )
390 {
391  int ret;
392  EC_FUNC_HEADER;
393  datagram->type = EC_DATAGRAM_BWR;
394  EC_WRITE_U16(datagram->address, 0x0000);
395  EC_WRITE_U16(datagram->address + 2, mem_address);
396  EC_FUNC_FOOTER;
397 }
398 
399 /****************************************************************************/
400 
406  ec_datagram_t *datagram,
407  uint16_t mem_address,
408  size_t data_size
409  )
410 {
411  int ret;
412  EC_FUNC_HEADER;
413  datagram->type = EC_DATAGRAM_BRW;
414  EC_WRITE_U16(datagram->address, 0x0000);
415  EC_WRITE_U16(datagram->address + 2, mem_address);
416  EC_FUNC_FOOTER;
417 }
418 
419 /****************************************************************************/
420 
426  ec_datagram_t *datagram,
427  uint32_t offset,
428  size_t data_size
429  )
430 {
431  int ret;
432  EC_FUNC_HEADER;
433  datagram->type = EC_DATAGRAM_LRD;
434  EC_WRITE_U32(datagram->address, offset);
435  EC_FUNC_FOOTER;
436 }
437 
438 /****************************************************************************/
439 
445  ec_datagram_t *datagram,
446  uint32_t offset,
447  size_t data_size
448  )
449 {
450  int ret;
451  EC_FUNC_HEADER;
452  datagram->type = EC_DATAGRAM_LWR;
453  EC_WRITE_U32(datagram->address, offset);
454  EC_FUNC_FOOTER;
455 }
456 
457 /****************************************************************************/
458 
464  ec_datagram_t *datagram,
465  uint32_t offset,
466  size_t data_size
467  )
468 {
469  int ret;
470  EC_FUNC_HEADER;
471  datagram->type = EC_DATAGRAM_LRW;
472  EC_WRITE_U32(datagram->address, offset);
473  EC_FUNC_FOOTER;
474 }
475 
476 /****************************************************************************/
477 
486  ec_datagram_t *datagram,
487  uint32_t offset,
488  size_t data_size,
489  uint8_t *external_memory
490  )
491 {
492  int ret;
493  datagram->data = external_memory;
494  datagram->data_origin = EC_ORIG_EXTERNAL;
495  EC_FUNC_HEADER;
496  datagram->type = EC_DATAGRAM_LRD;
497  EC_WRITE_U32(datagram->address, offset);
498  EC_FUNC_FOOTER;
499 }
500 
501 /****************************************************************************/
502 
511  ec_datagram_t *datagram,
512  uint32_t offset,
513  size_t data_size,
514  uint8_t *external_memory
515  )
516 {
517  int ret;
518  datagram->data = external_memory;
519  datagram->data_origin = EC_ORIG_EXTERNAL;
520  EC_FUNC_HEADER;
521  datagram->type = EC_DATAGRAM_LWR;
522  EC_WRITE_U32(datagram->address, offset);
523  EC_FUNC_FOOTER;
524 }
525 
526 /****************************************************************************/
527 
536  ec_datagram_t *datagram,
537  uint32_t offset,
538  size_t data_size,
539  uint8_t *external_memory
540  )
541 {
542  int ret;
543  datagram->data = external_memory;
544  datagram->data_origin = EC_ORIG_EXTERNAL;
545  EC_FUNC_HEADER;
546  datagram->type = EC_DATAGRAM_LRW;
547  EC_WRITE_U32(datagram->address, offset);
548  EC_FUNC_FOOTER;
549 }
550 
551 /****************************************************************************/
552 
558  const ec_datagram_t *datagram
559  )
560 {
561  printk(KERN_CONT "Datagram ");
562  switch (datagram->state) {
563  case EC_DATAGRAM_INIT:
564  printk(KERN_CONT "initialized");
565  break;
566  case EC_DATAGRAM_QUEUED:
567  printk(KERN_CONT "queued");
568  break;
569  case EC_DATAGRAM_SENT:
570  printk(KERN_CONT "sent");
571  break;
573  printk(KERN_CONT "received");
574  break;
576  printk(KERN_CONT "timed out");
577  break;
578  case EC_DATAGRAM_ERROR:
579  printk(KERN_CONT "error");
580  break;
581  default:
582  printk(KERN_CONT "???");
583  }
584 
585  printk(KERN_CONT ".\n");
586 }
587 
588 /****************************************************************************/
589 
595  const ec_datagram_t *datagram
596  )
597 {
598  if (datagram->working_counter == 0) {
599  printk(KERN_CONT "No response.");
600  }
601  else if (datagram->working_counter > 1) {
602  printk(KERN_CONT "%u slaves responded!", datagram->working_counter);
603  }
604  else {
605  printk(KERN_CONT "Success.");
606  }
607  printk(KERN_CONT "\n");
608 }
609 
610 /****************************************************************************/
611 
615  ec_datagram_t *datagram
616  )
617 {
618  if (jiffies - datagram->stats_output_jiffies > HZ) {
619  datagram->stats_output_jiffies = jiffies;
620 
621  if (unlikely(datagram->skip_count)) {
622  EC_WARN("Datagram %p (%s) was SKIPPED %u time%s.\n",
623  datagram, datagram->name,
624  datagram->skip_count,
625  datagram->skip_count == 1 ? "" : "s");
626  datagram->skip_count = 0;
627  }
628  }
629 }
630 
631 /****************************************************************************/
632 
638  const ec_datagram_t *datagram
639  )
640 {
641  return type_strings[datagram->type];
642 }
643 
644 /****************************************************************************/
#define EC_WARN(fmt, args...)
Convenience macro for printing EtherCAT-specific warnings to syslog.
Definition: globals.h:234
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:510
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:614
int ec_datagram_lwr(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LWR datagram.
Definition: datagram.c:444
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:181
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:304
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:202
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:170
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:340
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:594
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3154
External.
Definition: globals.h:305
Main device.
Definition: globals.h:199
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:365
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:290
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:485
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:265
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:223
int ec_datagram_lrd(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRD datagram.
Definition: datagram.c:425
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:315
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:557
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition: globals.h:224
int ec_datagram_brw(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BRW datagram.
Definition: datagram.c:405
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:535
const char * ec_datagram_type_string(const ec_datagram_t *datagram)
Returns a string describing the datagram type.
Definition: datagram.c:637
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:463
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:244
int ec_datagram_bwr(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BWR datagram.
Definition: datagram.c:385
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:110