IgH EtherCAT Master  1.5.2
voe_handler.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
34/*****************************************************************************/
35
36#include <linux/module.h>
37
38#include "master.h"
39#include "slave_config.h"
40#include "mailbox.h"
41#include "voe_handler.h"
42
45#define EC_VOE_HEADER_SIZE 6
46
49#define EC_VOE_RESPONSE_TIMEOUT 500
50
51/*****************************************************************************/
52
55
59
62
65
66/*****************************************************************************/
67
73 ec_voe_handler_t *voe,
75 size_t size
76 )
77{
78 voe->config = sc;
79 voe->vendor_id = 0x00000000;
80 voe->vendor_type = 0x0000;
81 voe->data_size = 0;
82 voe->dir = EC_DIR_INVALID;
84 voe->request_state = EC_INT_REQUEST_INIT;
85
87 return ec_datagram_prealloc(&voe->datagram,
89}
90
91/*****************************************************************************/
92
97 )
98{
100}
101
102/*****************************************************************************/
103
109 const ec_voe_handler_t *voe
110 )
111{
113 return voe->datagram.mem_size -
115 else
116 return 0;
117}
118
119/*****************************************************************************
120 * Application interface.
121 ****************************************************************************/
122
123void ecrt_voe_handler_send_header(ec_voe_handler_t *voe, uint32_t vendor_id,
124 uint16_t vendor_type)
125{
126 voe->vendor_id = vendor_id;
127 voe->vendor_type = vendor_type;
128}
129
130/*****************************************************************************/
131
133 uint32_t *vendor_id, uint16_t *vendor_type)
134{
135 uint8_t *header = voe->datagram.data + EC_MBOX_HEADER_SIZE;
136
137 if (vendor_id)
138 *vendor_id = EC_READ_U32(header);
139 if (vendor_type)
140 *vendor_type = EC_READ_U16(header + 4);
141}
142
143/*****************************************************************************/
144
146{
148}
149
150/*****************************************************************************/
151
153{
154 return voe->data_size;
155}
156
157/*****************************************************************************/
158
160{
161 voe->dir = EC_DIR_INPUT;
163 voe->request_state = EC_INT_REQUEST_BUSY;
164}
165
166/*****************************************************************************/
167
169{
170 voe->dir = EC_DIR_INPUT;
172 voe->request_state = EC_INT_REQUEST_BUSY;
173}
174
175/*****************************************************************************/
176
178{
179 voe->dir = EC_DIR_OUTPUT;
180 voe->data_size = size;
182 voe->request_state = EC_INT_REQUEST_BUSY;
183}
184
185/*****************************************************************************/
186
188{
189 if (voe->config->slave) { // FIXME locking?
190 voe->state(voe);
191 if (voe->request_state == EC_INT_REQUEST_BUSY) {
193 }
194 } else {
196 voe->request_state = EC_INT_REQUEST_FAILURE;
197 }
198
200}
201
202/******************************************************************************
203 * State functions.
204 *****************************************************************************/
205
209{
210 ec_slave_t *slave = voe->config->slave;
211 uint8_t *data;
212
213 if (slave->master->debug_level) {
214 EC_SLAVE_DBG(slave, 0, "Writing %zu bytes of VoE data.\n",
215 voe->data_size);
217 }
218
219 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
220 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
222 voe->request_state = EC_INT_REQUEST_FAILURE;
223 return;
224 }
225
226 data = ec_slave_mbox_prepare_send(slave, &voe->datagram,
227 EC_MBOX_TYPE_VOE, EC_VOE_HEADER_SIZE + voe->data_size);
228 if (IS_ERR(data)) {
230 voe->request_state = EC_INT_REQUEST_FAILURE;
231 return;
232 }
233
234 EC_WRITE_U32(data, voe->vendor_id);
235 EC_WRITE_U16(data + 4, voe->vendor_type);
236 /* data already in datagram */
237
238 voe->retries = EC_FSM_RETRIES;
239 voe->jiffies_start = jiffies;
241}
242
243/*****************************************************************************/
244
248{
249 ec_datagram_t *datagram = &voe->datagram;
250 ec_slave_t *slave = voe->config->slave;
251
252 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
253 return;
254
255 if (datagram->state != EC_DATAGRAM_RECEIVED) {
257 voe->request_state = EC_INT_REQUEST_FAILURE;
258 EC_SLAVE_ERR(slave, "Failed to receive VoE write request datagram: ");
259 ec_datagram_print_state(datagram);
260 return;
261 }
262
263 if (datagram->working_counter != 1) {
264 if (!datagram->working_counter) {
265 unsigned long diff_ms =
266 (jiffies - voe->jiffies_start) * 1000 / HZ;
267 if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
268 EC_SLAVE_DBG(slave, 1, "Slave did not respond to"
269 " VoE write request. Retrying after %lu ms...\n",
270 diff_ms);
271 // no response; send request datagram again
272 return;
273 }
274 }
276 voe->request_state = EC_INT_REQUEST_FAILURE;
277 EC_SLAVE_ERR(slave, "Reception of VoE write request failed: ");
279 return;
280 }
281
282 EC_CONFIG_DBG(voe->config, 1, "VoE write request successful.\n");
283
284 voe->request_state = EC_INT_REQUEST_SUCCESS;
286}
287
288/*****************************************************************************/
289
293{
294 ec_datagram_t *datagram = &voe->datagram;
295 ec_slave_t *slave = voe->config->slave;
296
297 EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
298
299 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
300 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
302 voe->request_state = EC_INT_REQUEST_FAILURE;
303 return;
304 }
305
306 ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
307
308 voe->jiffies_start = jiffies;
309 voe->retries = EC_FSM_RETRIES;
311}
312
313/*****************************************************************************/
314
318{
319 ec_datagram_t *datagram = &voe->datagram;
320 ec_slave_t *slave = voe->config->slave;
321
322 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
323 return;
324
325 if (datagram->state != EC_DATAGRAM_RECEIVED) {
327 voe->request_state = EC_INT_REQUEST_FAILURE;
328 EC_SLAVE_ERR(slave, "Failed to receive VoE mailbox check datagram: ");
329 ec_datagram_print_state(datagram);
330 return;
331 }
332
333 if (datagram->working_counter != 1) {
335 voe->request_state = EC_INT_REQUEST_FAILURE;
336 EC_SLAVE_ERR(slave, "Reception of VoE mailbox check"
337 " datagram failed: ");
339 return;
340 }
341
342 if (!ec_slave_mbox_check(datagram)) {
343 unsigned long diff_ms =
344 (datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
345 if (diff_ms >= EC_VOE_RESPONSE_TIMEOUT) {
347 voe->request_state = EC_INT_REQUEST_FAILURE;
348 EC_SLAVE_ERR(slave, "Timeout while waiting for VoE data.\n");
349 return;
350 }
351
352 ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
353 voe->retries = EC_FSM_RETRIES;
354 return;
355 }
356
357 // Fetch response
358 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
359 voe->retries = EC_FSM_RETRIES;
361}
362
363/*****************************************************************************/
364
368{
369 ec_datagram_t *datagram = &voe->datagram;
370 ec_slave_t *slave = voe->config->slave;
371 ec_master_t *master = voe->config->master;
372 uint8_t *data, mbox_prot;
373 size_t rec_size;
374
375 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
376 return;
377
378 if (datagram->state != EC_DATAGRAM_RECEIVED) {
380 voe->request_state = EC_INT_REQUEST_FAILURE;
381 EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
382 ec_datagram_print_state(datagram);
383 return;
384 }
385
386 if (datagram->working_counter != 1) {
388 voe->request_state = EC_INT_REQUEST_FAILURE;
389 EC_SLAVE_ERR(slave, "Reception of VoE read response failed: ");
391 return;
392 }
393
394 data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
395 if (IS_ERR(data)) {
397 voe->request_state = EC_INT_REQUEST_FAILURE;
398 return;
399 }
400
401 if (mbox_prot != EC_MBOX_TYPE_VOE) {
403 voe->request_state = EC_INT_REQUEST_FAILURE;
404 EC_SLAVE_WARN(slave, "Received mailbox protocol 0x%02X"
405 " as response.\n", mbox_prot);
406 ec_print_data(data, rec_size);
407 return;
408 }
409
410 if (rec_size < EC_VOE_HEADER_SIZE) {
412 voe->request_state = EC_INT_REQUEST_FAILURE;
413 EC_SLAVE_ERR(slave, "Received VoE header is"
414 " incomplete (%zu bytes)!\n", rec_size);
415 return;
416 }
417
418 if (master->debug_level) {
419 EC_CONFIG_DBG(voe->config, 0, "VoE data:\n");
420 ec_print_data(data, rec_size);
421 }
422
423 voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
424 voe->request_state = EC_INT_REQUEST_SUCCESS;
425 voe->state = ec_voe_handler_state_end; // success
426}
427
428/*****************************************************************************/
429
433{
434 ec_datagram_t *datagram = &voe->datagram;
435 ec_slave_t *slave = voe->config->slave;
436
437 EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
438
439 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
440 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
442 voe->request_state = EC_INT_REQUEST_FAILURE;
443 return;
444 }
445
446 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
447
448 voe->jiffies_start = jiffies;
449 voe->retries = EC_FSM_RETRIES;
451}
452
453/*****************************************************************************/
454
459{
460 ec_datagram_t *datagram = &voe->datagram;
461 ec_slave_t *slave = voe->config->slave;
462 ec_master_t *master = voe->config->master;
463 uint8_t *data, mbox_prot;
464 size_t rec_size;
465
466 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
467 return;
468
469 if (datagram->state != EC_DATAGRAM_RECEIVED) {
471 voe->request_state = EC_INT_REQUEST_FAILURE;
472 EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
473 ec_datagram_print_state(datagram);
474 return;
475 }
476
477 if (datagram->working_counter == 0) {
479 voe->request_state = EC_INT_REQUEST_FAILURE;
480 EC_SLAVE_DBG(slave, 1, "Slave did not send VoE data.\n");
481 return;
482 }
483
484 if (datagram->working_counter != 1) {
486 voe->request_state = EC_INT_REQUEST_FAILURE;
487 EC_SLAVE_WARN(slave, "Reception of VoE read response failed: ");
489 return;
490 }
491
492 if (!(data = ec_slave_mbox_fetch(slave, datagram,
493 &mbox_prot, &rec_size))) {
495 voe->request_state = EC_INT_REQUEST_FAILURE;
496 return;
497 }
498
499 if (mbox_prot != EC_MBOX_TYPE_VOE) {
501 voe->request_state = EC_INT_REQUEST_FAILURE;
502 EC_SLAVE_WARN(slave, "Received mailbox protocol 0x%02X"
503 " as response.\n", mbox_prot);
504 ec_print_data(data, rec_size);
505 return;
506 }
507
508 if (rec_size < EC_VOE_HEADER_SIZE) {
510 voe->request_state = EC_INT_REQUEST_FAILURE;
511 EC_SLAVE_ERR(slave, "Received VoE header is"
512 " incomplete (%zu bytes)!\n", rec_size);
513 return;
514 }
515
516 if (master->debug_level) {
517 EC_CONFIG_DBG(voe->config, 1, "VoE data:\n");
518 ec_print_data(data, rec_size);
519 }
520
521 voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
522 voe->request_state = EC_INT_REQUEST_SUCCESS;
523 voe->state = ec_voe_handler_state_end; // success
524}
525
526/*****************************************************************************/
527
531{
532}
533
534/*****************************************************************************/
535
539{
540}
541
542/*****************************************************************************/
543
546EXPORT_SYMBOL(ecrt_voe_handler_send_header);
548EXPORT_SYMBOL(ecrt_voe_handler_data);
549EXPORT_SYMBOL(ecrt_voe_handler_data_size);
550EXPORT_SYMBOL(ecrt_voe_handler_read);
551EXPORT_SYMBOL(ecrt_voe_handler_write);
552EXPORT_SYMBOL(ecrt_voe_handler_execute);
553
556/*****************************************************************************/
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_prealloc(ec_datagram_t *datagram, size_t size)
Allocates internal payload memory.
Definition: datagram.c:150
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:118
void ec_datagram_init(ec_datagram_t *datagram)
Constructor.
Definition: datagram.c:88
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition: datagram.h:78
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition: datagram.h:79
#define EC_MBOX_HEADER_SIZE
Mailbox header size.
Definition: globals.h:83
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
const ec_request_state_t ec_request_state_translation_table[]
Global request state type translation table.
Definition: module.c:662
@ EC_MBOX_VOE
Vendor specific.
Definition: globals.h:140
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:348
void ecrt_voe_handler_send_header(ec_voe_handler_t *voe, uint32_t vendor_id, uint16_t vendor_type)
Sets the VoE header for future send operations.
Definition: voe_handler.c:123
void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
Start a VoE write operation.
Definition: voe_handler.c:177
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
Execute the handler.
Definition: voe_handler.c:187
void ecrt_voe_handler_read(ec_voe_handler_t *voe)
Start a VoE read operation.
Definition: voe_handler.c:159
uint8_t * ecrt_voe_handler_data(ec_voe_handler_t *voe)
Access to the VoE handler's data.
Definition: voe_handler.c:145
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2300
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2178
size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
Returns the current data size.
Definition: voe_handler.c:152
void ecrt_voe_handler_received_header(const ec_voe_handler_t *voe, uint32_t *vendor_id, uint16_t *vendor_type)
Reads the header data of a received VoE message.
Definition: voe_handler.c:132
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2194
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2283
void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
Start a VoE read operation without querying the sync manager status.
Definition: voe_handler.c:168
ec_request_state_t
Request state.
Definition: ecrt.h:530
@ EC_DIR_INVALID
Invalid direction.
Definition: ecrt.h:431
@ EC_DIR_INPUT
Values read by the master.
Definition: ecrt.h:433
@ EC_DIR_OUTPUT
Values written by the master.
Definition: ecrt.h:432
uint8_t * ec_slave_mbox_fetch(const ec_slave_t *slave, const ec_datagram_t *datagram, uint8_t *type, size_t *size)
Processes received mailbox data.
Definition: mailbox.c:165
int ec_slave_mbox_prepare_check(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram for checking the mailbox state.
Definition: mailbox.c:96
int ec_slave_mbox_prepare_fetch(const ec_slave_t *slave, ec_datagram_t *datagram)
Prepares a datagram to fetch mailbox data.
Definition: mailbox.c:127
uint8_t * ec_slave_mbox_prepare_send(const ec_slave_t *slave, ec_datagram_t *datagram, uint8_t type, size_t size)
Prepares a mailbox-send datagram.
Definition: mailbox.c:51
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition: mailbox.c:115
Mailbox functionality.
void ec_master_queue_datagram(ec_master_t *master, ec_datagram_t *datagram)
Places a datagram in the datagram queue.
Definition: master.c:952
EtherCAT master structure.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:106
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
EtherCAT slave configuration structure.
#define EC_CONFIG_DBG(sc, level, fmt, args...)
Convenience macro for printing configuration-specific debug messages to syslog.
Definition: slave_config.h:107
EtherCAT datagram.
Definition: datagram.h:87
size_t mem_size
Datagram data memory size.
Definition: datagram.h:96
uint16_t working_counter
Working counter.
Definition: datagram.h:99
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
ec_datagram_state_t state
State.
Definition: datagram.h:100
uint8_t * data
Datagram payload.
Definition: datagram.h:94
EtherCAT master.
Definition: master.h:194
unsigned int debug_level
Master debug level.
Definition: master.h:285
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:147
EtherCAT slave configuration.
Definition: slave_config.h:119
ec_master_t * master
Master owning the slave configuration.
Definition: slave_config.h:121
ec_slave_t * slave
Slave pointer.
Definition: slave_config.h:134
EtherCAT slave.
Definition: slave.h:177
ec_sii_t sii
Extracted SII data.
Definition: slave.h:223
ec_master_t * master
Master owning the slave.
Definition: slave.h:178
Vendor specific over EtherCAT handler.
Definition: voe_handler.h:49
ec_internal_request_state_t request_state
Handler state.
Definition: voe_handler.h:60
ec_slave_config_t * config
Parent slave configuration.
Definition: voe_handler.h:51
void(* state)(ec_voe_handler_t *)
State function.
Definition: voe_handler.h:59
ec_datagram_t datagram
State machine datagram.
Definition: voe_handler.h:52
uint32_t vendor_id
Vendor ID for the header.
Definition: voe_handler.h:53
unsigned long jiffies_start
Timestamp for timeout calculation.
Definition: voe_handler.h:62
ec_direction_t dir
Direction.
Definition: voe_handler.h:56
size_t data_size
Size of VoE data.
Definition: voe_handler.h:55
unsigned int retries
retries upon datagram timeout
Definition: voe_handler.h:61
uint16_t vendor_type
Vendor type for the header.
Definition: voe_handler.h:54
void ec_voe_handler_state_read_response(ec_voe_handler_t *)
Read the pending mailbox data.
Definition: voe_handler.c:367
void ec_voe_handler_state_read_check(ec_voe_handler_t *)
Check for new data in the mailbox.
Definition: voe_handler.c:317
void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *)
Read the pending mailbox data without sending a sync message before.
Definition: voe_handler.c:458
void ec_voe_handler_state_end(ec_voe_handler_t *)
Successful termination state function.
Definition: voe_handler.c:530
void ec_voe_handler_state_error(ec_voe_handler_t *)
Failure termination state function.
Definition: voe_handler.c:538
#define EC_VOE_RESPONSE_TIMEOUT
VoE response timeout in [ms].
Definition: voe_handler.c:49
void ec_voe_handler_clear(ec_voe_handler_t *voe)
VoE handler destructor.
Definition: voe_handler.c:95
void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *)
Start reading VoE data without sending a sync message before.
Definition: voe_handler.c:432
void ec_voe_handler_state_write_start(ec_voe_handler_t *)
Start writing VoE data.
Definition: voe_handler.c:208
void ec_voe_handler_state_read_start(ec_voe_handler_t *)
Start reading VoE data.
Definition: voe_handler.c:292
#define EC_VOE_HEADER_SIZE
VoE header size.
Definition: voe_handler.c:45
int ec_voe_handler_init(ec_voe_handler_t *voe, ec_slave_config_t *sc, size_t size)
VoE handler constructor.
Definition: voe_handler.c:72
size_t ec_voe_handler_mem_size(const ec_voe_handler_t *voe)
Get usable memory size.
Definition: voe_handler.c:108
void ec_voe_handler_state_write_response(ec_voe_handler_t *)
Wait for the mailbox response.
Definition: voe_handler.c:247
Vendor specific over EtherCAT protocol handler.