IgH EtherCAT Master  1.6.9
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
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 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;
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;
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/****************************************************************************/
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_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition datagram.c:594
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
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
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_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:315
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
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition datagram.c:170
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
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
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_bwr(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BWR datagram.
Definition datagram.c:385
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:557
void ec_datagram_output_stats(ec_datagram_t *datagram)
Outputs datagram statistics at most every second.
Definition datagram.c:614
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
const char * ec_datagram_type_string(const ec_datagram_t *datagram)
Returns a string describing the datagram type.
Definition datagram.c:637
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_lrd(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRD datagram.
Definition datagram.c:425
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:290
int ec_datagram_lrw(ec_datagram_t *datagram, uint32_t offset, size_t data_size)
Initializes an EtherCAT LRW datagram.
Definition datagram.c:463
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
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
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_WARN(fmt, args...)
Convenience macro for printing EtherCAT-specific warnings to syslog.
Definition globals.h:234
#define EC_ADDR_LEN
Size of the EtherCAT address field.
Definition globals.h:76
@ EC_ORIG_EXTERNAL
External.
Definition globals.h:305
@ EC_ORIG_INTERNAL
Internal.
Definition globals.h:304
#define EC_DATAGRAM_NAME_SIZE
Size of the datagram description string.
Definition globals.h:104
@ EC_DEVICE_MAIN
Main device.
Definition globals.h:199
#define EC_ERR(fmt, args...)
Convenience macro for printing EtherCAT-specific errors to syslog.
Definition globals.h:224
#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