IgH EtherCAT Master  1.6.1
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 
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,
66  ec_slave_config_t *sc,
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 
88  ec_voe_handler_t *voe
89  )
90 {
92 }
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 
115 int ecrt_voe_handler_send_header(ec_voe_handler_t *voe, uint32_t vendor_id,
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 
140 {
142 }
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: ");
275  ec_datagram_print_wc_error(datagram);
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: ");
335  ec_datagram_print_wc_error(datagram);
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: ");
387  ec_datagram_print_wc_error(datagram);
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: ");
485  ec_datagram_print_wc_error(datagram);
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 
528 {
529 }
530 
531 /****************************************************************************/
532 
536 {
537 }
538 
539 /****************************************************************************/
540 
543 EXPORT_SYMBOL(ecrt_voe_handler_send_header);
544 EXPORT_SYMBOL(ecrt_voe_handler_received_header);
545 EXPORT_SYMBOL(ecrt_voe_handler_data);
546 EXPORT_SYMBOL(ecrt_voe_handler_data_size);
547 EXPORT_SYMBOL(ecrt_voe_handler_read);
548 EXPORT_SYMBOL(ecrt_voe_handler_write);
549 EXPORT_SYMBOL(ecrt_voe_handler_execute);
550 
553 /****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
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
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:429
ec_sii_t sii
Extracted SII data.
Definition: slave.h:215
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 ecrt_voe_handler_read(ec_voe_handler_t *voe)
Start a VoE read operation.
Definition: voe_handler.c:153
void ec_voe_handler_state_read_check(ec_voe_handler_t *)
Check for new data in the mailbox.
Definition: voe_handler.c:314
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:98
ec_datagram_t datagram
State machine datagram.
Definition: voe_handler.h:44
size_t ec_voe_handler_mem_size(const ec_voe_handler_t *voe)
Get usable memory size.
Definition: voe_handler.c:100
#define EC_VOE_HEADER_SIZE
VoE header size.
Definition: voe_handler.c:37
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
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:82
EtherCAT datagram.
Definition: datagram.h:79
int ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
Start a VoE write operation.
Definition: voe_handler.c:173
ec_master_t * master
Master owning the slave configuration.
Definition: slave_config.h:113
uint16_t working_counter
Working counter.
Definition: datagram.h:93
#define EC_VOE_RESPONSE_TIMEOUT
VoE response timeout in [ms].
Definition: voe_handler.c:41
uint16_t vendor_type
Vendor type for the header.
Definition: voe_handler.h:46
EtherCAT master structure.
uint32_t vendor_id
Vendor ID for the header.
Definition: voe_handler.h:45
EtherCAT slave.
Definition: slave.h:168
ec_datagram_state_t state
State.
Definition: datagram.h:94
void(* state)(ec_voe_handler_t *)
State function.
Definition: voe_handler.h:51
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3171
ec_internal_request_state_t request_state
Handler state.
Definition: voe_handler.h:52
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:139
size_t data_size
Size of VoE data.
Definition: voe_handler.h:47
unsigned int debug_level
Master debug level.
Definition: master.h:275
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:68
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 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:125
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3154
#define EC_CONFIG_DBG(sc, level, fmt, args...)
Convenience macro for printing configuration-specific debug messages to syslog.
Definition: slave_config.h:99
void ec_voe_handler_state_read_response(ec_voe_handler_t *)
Read the pending mailbox data.
Definition: voe_handler.c:364
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3061
unsigned long jiffies_start
Timestamp for timeout calculation.
Definition: voe_handler.h:54
Vendor specific over EtherCAT handler.
Definition: voe_handler.h:41
ec_master_t * master
Master owning the slave.
Definition: slave.h:170
void ec_master_queue_datagram(ec_master_t *master, ec_datagram_t *datagram)
Places a datagram in the datagram queue.
Definition: master.c:954
Values read by the master.
Definition: ecrt.h:507
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
ec_slave_t * slave
Slave pointer.
Definition: slave_config.h:126
void ec_voe_handler_state_write_start(ec_voe_handler_t *)
Start writing VoE data.
Definition: voe_handler.c:205
#define EC_MBOX_HEADER_SIZE
Mailbox header size.
Definition: globals.h:83
void ec_voe_handler_state_write_response(ec_voe_handler_t *)
Wait for the mailbox response.
Definition: voe_handler.c:244
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:344
int ec_datagram_prealloc(ec_datagram_t *datagram, size_t size)
Allocates internal payload memory.
Definition: datagram.c:142
void ec_voe_handler_state_read_start(ec_voe_handler_t *)
Start reading VoE data.
Definition: voe_handler.c:289
unsigned int retries
retries upon datagram timeout
Definition: voe_handler.h:53
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
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3045
ec_direction_t dir
Direction.
Definition: voe_handler.h:48
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:557
Mailbox functionality.
Invalid direction.
Definition: ecrt.h:505
Vendor specific over EtherCAT protocol handler.
uint8_t * ecrt_voe_handler_data(const ec_voe_handler_t *voe)
Access to the VoE handler&#39;s data.
Definition: voe_handler.c:139
void ec_datagram_init(ec_datagram_t *datagram)
Constructor.
Definition: datagram.c:80
Timed out (dequeued).
Definition: datagram.h:71
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.
Definition: voe_handler.c:115
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:455
uint8_t * data
Datagram payload.
Definition: datagram.h:88
size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
Returns the current data size.
Definition: voe_handler.c:146
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
Execute the handler.
Definition: voe_handler.c:184
void ec_voe_handler_state_error(ec_voe_handler_t *)
Failure termination state function.
Definition: voe_handler.c:535
EtherCAT slave configuration.
Definition: slave_config.h:111
EtherCAT slave configuration structure.
size_t mem_size
Datagram data memory size.
Definition: datagram.h:90
ec_request_state_t
Request state.
Definition: ecrt.h:604
ec_slave_config_t * config
Parent slave configuration.
Definition: voe_handler.h:43
Values written by the master.
Definition: ecrt.h:506
Received (dequeued).
Definition: datagram.h:70
const ec_request_state_t ec_request_state_translation_table[]
Global request state type translation table.
Definition: module.c:658
EtherCAT master.
Definition: master.h:187
Vendor specific.
Definition: globals.h:149
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:102
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition: mailbox.c:107
int 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:163
void ec_voe_handler_clear(ec_voe_handler_t *voe)
VoE handler destructor.
Definition: voe_handler.c:87
void ec_datagram_clear(ec_datagram_t *datagram)
Destructor.
Definition: datagram.c:110
void ec_voe_handler_state_end(ec_voe_handler_t *)
Successful termination state function.
Definition: voe_handler.c:527