IgH EtherCAT Master  1.6.9
voe_handler.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
25
26/****************************************************************************/
27
28#include <linux/module.h>
29
30#include "master.h"
31#include "slave_config.h"
32#include "mailbox.h"
33#include "voe_handler.h"
34
37#define EC_VOE_HEADER_SIZE 6
38
41#define EC_VOE_RESPONSE_TIMEOUT 500
42
43/****************************************************************************/
44
47
51
54
57
58/****************************************************************************/
59
65 ec_voe_handler_t *voe,
67 size_t size
68 )
69{
70 voe->config = sc;
71 voe->vendor_id = 0x00000000;
72 voe->vendor_type = 0x0000;
73 voe->data_size = 0;
74 voe->dir = EC_DIR_INVALID;
76 voe->request_state = EC_INT_REQUEST_INIT;
77
79 return ec_datagram_prealloc(&voe->datagram,
81}
82
83/****************************************************************************/
84
93
94/****************************************************************************/
95
101 const ec_voe_handler_t *voe
102 )
103{
105 return voe->datagram.mem_size -
107 else
108 return 0;
109}
110
111/*****************************************************************************
112 * Application interface.
113 ****************************************************************************/
114
116 uint16_t vendor_type)
117{
118 voe->vendor_id = vendor_id;
119 voe->vendor_type = vendor_type;
120 return 0;
121}
122
123/****************************************************************************/
124
126 uint32_t *vendor_id, uint16_t *vendor_type)
127{
128 uint8_t *header = voe->datagram.data + EC_MBOX_HEADER_SIZE;
129
130 if (vendor_id)
131 *vendor_id = EC_READ_U32(header);
132 if (vendor_type)
133 *vendor_type = EC_READ_U16(header + 4);
134 return 0;
135}
136
137/****************************************************************************/
138
143
144/****************************************************************************/
145
147{
148 return voe->data_size;
149}
150
151/****************************************************************************/
152
154{
155 voe->dir = EC_DIR_INPUT;
157 voe->request_state = EC_INT_REQUEST_BUSY;
158 return 0;
159}
160
161/****************************************************************************/
162
164{
165 voe->dir = EC_DIR_INPUT;
167 voe->request_state = EC_INT_REQUEST_BUSY;
168 return 0;
169}
170
171/****************************************************************************/
172
174{
175 voe->dir = EC_DIR_OUTPUT;
176 voe->data_size = size;
178 voe->request_state = EC_INT_REQUEST_BUSY;
179 return 0;
180}
181
182/****************************************************************************/
183
185{
186 if (voe->config->slave) { // FIXME locking?
187 voe->state(voe);
188 if (voe->request_state == EC_INT_REQUEST_BUSY) {
190 }
191 } else {
193 voe->request_state = EC_INT_REQUEST_FAILURE;
194 }
195
197}
198
199/*****************************************************************************
200 * State functions.
201 ****************************************************************************/
202
206{
207 ec_slave_t *slave = voe->config->slave;
208 uint8_t *data;
209
210 if (slave->master->debug_level) {
211 EC_SLAVE_DBG(slave, 0, "Writing %zu bytes of VoE data.\n",
212 voe->data_size);
214 }
215
216 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
217 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
219 voe->request_state = EC_INT_REQUEST_FAILURE;
220 return;
221 }
222
223 data = ec_slave_mbox_prepare_send(slave, &voe->datagram,
224 EC_MBOX_TYPE_VOE, EC_VOE_HEADER_SIZE + voe->data_size);
225 if (IS_ERR(data)) {
227 voe->request_state = EC_INT_REQUEST_FAILURE;
228 return;
229 }
230
231 EC_WRITE_U32(data, voe->vendor_id);
232 EC_WRITE_U16(data + 4, voe->vendor_type);
233 /* data already in datagram */
234
235 voe->retries = EC_FSM_RETRIES;
236 voe->jiffies_start = jiffies;
238}
239
240/****************************************************************************/
241
245{
246 ec_datagram_t *datagram = &voe->datagram;
247 ec_slave_t *slave = voe->config->slave;
248
249 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
250 return;
251
252 if (datagram->state != EC_DATAGRAM_RECEIVED) {
254 voe->request_state = EC_INT_REQUEST_FAILURE;
255 EC_SLAVE_ERR(slave, "Failed to receive VoE write request datagram: ");
256 ec_datagram_print_state(datagram);
257 return;
258 }
259
260 if (datagram->working_counter != 1) {
261 if (!datagram->working_counter) {
262 unsigned long diff_ms =
263 (jiffies - voe->jiffies_start) * 1000 / HZ;
264 if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
265 EC_SLAVE_DBG(slave, 1, "Slave did not respond to"
266 " VoE write request. Retrying after %lu ms...\n",
267 diff_ms);
268 // no response; send request datagram again
269 return;
270 }
271 }
273 voe->request_state = EC_INT_REQUEST_FAILURE;
274 EC_SLAVE_ERR(slave, "Reception of VoE write request failed: ");
276 return;
277 }
278
279 EC_CONFIG_DBG(voe->config, 1, "VoE write request successful.\n");
280
281 voe->request_state = EC_INT_REQUEST_SUCCESS;
283}
284
285/****************************************************************************/
286
290{
291 ec_datagram_t *datagram = &voe->datagram;
292 ec_slave_t *slave = voe->config->slave;
293
294 EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
295
296 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
297 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
299 voe->request_state = EC_INT_REQUEST_FAILURE;
300 return;
301 }
302
303 ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
304
305 voe->jiffies_start = jiffies;
306 voe->retries = EC_FSM_RETRIES;
308}
309
310/****************************************************************************/
311
315{
316 ec_datagram_t *datagram = &voe->datagram;
317 ec_slave_t *slave = voe->config->slave;
318
319 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
320 return;
321
322 if (datagram->state != EC_DATAGRAM_RECEIVED) {
324 voe->request_state = EC_INT_REQUEST_FAILURE;
325 EC_SLAVE_ERR(slave, "Failed to receive VoE mailbox check datagram: ");
326 ec_datagram_print_state(datagram);
327 return;
328 }
329
330 if (datagram->working_counter != 1) {
332 voe->request_state = EC_INT_REQUEST_FAILURE;
333 EC_SLAVE_ERR(slave, "Reception of VoE mailbox check"
334 " datagram failed: ");
336 return;
337 }
338
339 if (!ec_slave_mbox_check(datagram)) {
340 unsigned long diff_ms =
341 (datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
342 if (diff_ms >= EC_VOE_RESPONSE_TIMEOUT) {
344 voe->request_state = EC_INT_REQUEST_FAILURE;
345 EC_SLAVE_ERR(slave, "Timeout while waiting for VoE data.\n");
346 return;
347 }
348
349 ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
350 voe->retries = EC_FSM_RETRIES;
351 return;
352 }
353
354 // Fetch response
355 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
356 voe->retries = EC_FSM_RETRIES;
358}
359
360/****************************************************************************/
361
365{
366 ec_datagram_t *datagram = &voe->datagram;
367 ec_slave_t *slave = voe->config->slave;
368 ec_master_t *master = voe->config->master;
369 uint8_t *data, mbox_prot;
370 size_t rec_size;
371
372 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
373 return;
374
375 if (datagram->state != EC_DATAGRAM_RECEIVED) {
377 voe->request_state = EC_INT_REQUEST_FAILURE;
378 EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
379 ec_datagram_print_state(datagram);
380 return;
381 }
382
383 if (datagram->working_counter != 1) {
385 voe->request_state = EC_INT_REQUEST_FAILURE;
386 EC_SLAVE_ERR(slave, "Reception of VoE read response failed: ");
388 return;
389 }
390
391 data = ec_slave_mbox_fetch(slave, datagram, &mbox_prot, &rec_size);
392 if (IS_ERR(data)) {
394 voe->request_state = EC_INT_REQUEST_FAILURE;
395 return;
396 }
397
398 if (mbox_prot != EC_MBOX_TYPE_VOE) {
400 voe->request_state = EC_INT_REQUEST_FAILURE;
401 EC_SLAVE_WARN(slave, "Received mailbox protocol 0x%02X"
402 " as response.\n", mbox_prot);
403 ec_print_data(data, rec_size);
404 return;
405 }
406
407 if (rec_size < EC_VOE_HEADER_SIZE) {
409 voe->request_state = EC_INT_REQUEST_FAILURE;
410 EC_SLAVE_ERR(slave, "Received VoE header is"
411 " incomplete (%zu bytes)!\n", rec_size);
412 return;
413 }
414
415 if (master->debug_level) {
416 EC_CONFIG_DBG(voe->config, 0, "VoE data:\n");
417 ec_print_data(data, rec_size);
418 }
419
420 voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
421 voe->request_state = EC_INT_REQUEST_SUCCESS;
422 voe->state = ec_voe_handler_state_end; // success
423}
424
425/****************************************************************************/
426
430{
431 ec_datagram_t *datagram = &voe->datagram;
432 ec_slave_t *slave = voe->config->slave;
433
434 EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
435
436 if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
437 EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
439 voe->request_state = EC_INT_REQUEST_FAILURE;
440 return;
441 }
442
443 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
444
445 voe->jiffies_start = jiffies;
446 voe->retries = EC_FSM_RETRIES;
448}
449
450/****************************************************************************/
451
456{
457 ec_datagram_t *datagram = &voe->datagram;
458 ec_slave_t *slave = voe->config->slave;
459 ec_master_t *master = voe->config->master;
460 uint8_t *data, mbox_prot;
461 size_t rec_size;
462
463 if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
464 return;
465
466 if (datagram->state != EC_DATAGRAM_RECEIVED) {
468 voe->request_state = EC_INT_REQUEST_FAILURE;
469 EC_SLAVE_ERR(slave, "Failed to receive VoE read datagram: ");
470 ec_datagram_print_state(datagram);
471 return;
472 }
473
474 if (datagram->working_counter == 0) {
476 voe->request_state = EC_INT_REQUEST_FAILURE;
477 EC_SLAVE_DBG(slave, 1, "Slave did not send VoE data.\n");
478 return;
479 }
480
481 if (datagram->working_counter != 1) {
483 voe->request_state = EC_INT_REQUEST_FAILURE;
484 EC_SLAVE_WARN(slave, "Reception of VoE read response failed: ");
486 return;
487 }
488
489 if (!(data = ec_slave_mbox_fetch(slave, datagram,
490 &mbox_prot, &rec_size))) {
492 voe->request_state = EC_INT_REQUEST_FAILURE;
493 return;
494 }
495
496 if (mbox_prot != EC_MBOX_TYPE_VOE) {
498 voe->request_state = EC_INT_REQUEST_FAILURE;
499 EC_SLAVE_WARN(slave, "Received mailbox protocol 0x%02X"
500 " as response.\n", mbox_prot);
501 ec_print_data(data, rec_size);
502 return;
503 }
504
505 if (rec_size < EC_VOE_HEADER_SIZE) {
507 voe->request_state = EC_INT_REQUEST_FAILURE;
508 EC_SLAVE_ERR(slave, "Received VoE header is"
509 " incomplete (%zu bytes)!\n", rec_size);
510 return;
511 }
512
513 if (master->debug_level) {
514 EC_CONFIG_DBG(voe->config, 1, "VoE data:\n");
515 ec_print_data(data, rec_size);
516 }
517
518 voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
519 voe->request_state = EC_INT_REQUEST_SUCCESS;
520 voe->state = ec_voe_handler_state_end; // success
521}
522
523/****************************************************************************/
524
530
531/****************************************************************************/
532
538
539/****************************************************************************/
540
542
543EXPORT_SYMBOL(ecrt_voe_handler_send_header);
545EXPORT_SYMBOL(ecrt_voe_handler_data);
546EXPORT_SYMBOL(ecrt_voe_handler_data_size);
547EXPORT_SYMBOL(ecrt_voe_handler_read);
548EXPORT_SYMBOL(ecrt_voe_handler_write);
549EXPORT_SYMBOL(ecrt_voe_handler_execute);
550
552
553/****************************************************************************/
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_prealloc(ec_datagram_t *datagram, size_t size)
Allocates internal payload memory.
Definition datagram.c:142
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition datagram.c:557
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition datagram.c:110
void ec_datagram_init(ec_datagram_t *datagram)
Constructor.
Definition datagram.c:80
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
#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:658
@ EC_MBOX_VOE
Vendor specific.
Definition globals.h:149
struct ec_slave ec_slave_t
Definition globals.h:310
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition module.c:344
uint8_t * ecrt_voe_handler_data(const ec_voe_handler_t *voe)
Access to the VoE handler's data.
struct ec_voe_handler ec_voe_handler_t
Definition ecrt.h:315
struct ec_master ec_master_t
Definition ecrt.h:300
int ecrt_voe_handler_read(ec_voe_handler_t *voe)
Start a VoE read operation.
int 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.
struct ec_slave_config ec_slave_config_t
Definition ecrt.h:303
size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
Returns the current data size.
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition ecrt.h:3074
int ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
Start a VoE write operation.
int 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.
int ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe)
Start a VoE read operation without querying the sync manager status.
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition ecrt.h:2948
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
Execute the handler.
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition ecrt.h:2964
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition ecrt.h:3057
ec_request_state_t
Request state.
Definition ecrt.h:604
@ EC_DIR_INVALID
Invalid direction.
Definition ecrt.h:505
@ EC_DIR_INPUT
Values read by the master.
Definition ecrt.h:507
@ EC_DIR_OUTPUT
Values written by the master.
Definition ecrt.h:506
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:157
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:88
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:119
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:43
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition mailbox.c:107
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:962
EtherCAT master structure.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition slave.h:98
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition slave.h:68
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition slave.h:82
EtherCAT slave configuration structure.
#define EC_CONFIG_DBG(sc, level, fmt, args...)
Convenience macro for printing configuration-specific debug messages to syslog.
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
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition datagram.h:102
ec_datagram_state_t state
State.
Definition datagram.h:94
uint8_t * data
Datagram payload.
Definition datagram.h:88
unsigned int debug_level
Master debug level.
Definition master.h:275
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition slave.h:139
ec_master_t * master
Master owning the slave configuration.
ec_slave_t * slave
Slave pointer.
ec_sii_t sii
Extracted SII data.
Definition slave.h:215
ec_master_t * master
Master owning the slave.
Definition slave.h:170
ec_internal_request_state_t request_state
Handler state.
Definition voe_handler.h:52
ec_slave_config_t * config
Parent slave configuration.
Definition voe_handler.h:43
void(* state)(ec_voe_handler_t *)
State function.
Definition voe_handler.h:51
ec_datagram_t datagram
State machine datagram.
Definition voe_handler.h:44
uint32_t vendor_id
Vendor ID for the header.
Definition voe_handler.h:45
unsigned long jiffies_start
Timestamp for timeout calculation.
Definition voe_handler.h:54
ec_direction_t dir
Direction.
Definition voe_handler.h:48
size_t data_size
Size of VoE data.
Definition voe_handler.h:47
unsigned int retries
retries upon datagram timeout
Definition voe_handler.h:53
uint16_t vendor_type
Vendor type for the header.
Definition voe_handler.h:46
void ec_voe_handler_state_read_response(ec_voe_handler_t *)
Read the pending mailbox data.
void ec_voe_handler_state_read_check(ec_voe_handler_t *)
Check for new data in the mailbox.
void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *)
Read the pending mailbox data without sending a sync message before.
void ec_voe_handler_state_end(ec_voe_handler_t *)
Successful termination state function.
void ec_voe_handler_state_error(ec_voe_handler_t *)
Failure termination state function.
#define EC_VOE_RESPONSE_TIMEOUT
VoE response timeout in [ms].
Definition voe_handler.c:41
void ec_voe_handler_clear(ec_voe_handler_t *voe)
VoE handler destructor.
Definition voe_handler.c:87
void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *)
Start reading VoE data without sending a sync message before.
void ec_voe_handler_state_write_start(ec_voe_handler_t *)
Start writing VoE data.
void ec_voe_handler_state_read_start(ec_voe_handler_t *)
Start reading VoE data.
#define EC_VOE_HEADER_SIZE
VoE header size.
Definition voe_handler.c:37
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:64
size_t ec_voe_handler_mem_size(const ec_voe_handler_t *voe)
Get usable memory size.
void ec_voe_handler_state_write_response(ec_voe_handler_t *)
Wait for the mailbox response.
Vendor specific over EtherCAT protocol handler.