IgH EtherCAT Master  1.7.0
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 
55 /****************************************************************************/
56 
62  ec_voe_handler_t *voe,
63  ec_slave_config_t *sc,
64  size_t size
65  )
66 {
67  voe->config = sc;
68  voe->vendor_id = 0x00000000;
69  voe->vendor_type = 0x0000;
70  voe->data_size = 0;
71  voe->dir = EC_DIR_INVALID;
73  voe->request_state = EC_INT_REQUEST_INIT;
75 
77  return ec_datagram_prealloc(&voe->datagram,
79 }
80 
81 /****************************************************************************/
82 
86  ec_voe_handler_t *voe
87  )
88 {
91 }
92 
93 /****************************************************************************/
94 
102  ec_voe_handler_t *voe
103  )
104 {
105  if (ec_fsm_mbox_holds_lock(&voe->fsm_mbox)) {
107  voe->request_state = EC_INT_REQUEST_FAILURE;
108  }
109 
111 }
112 
113 /****************************************************************************/
114 
120  const ec_voe_handler_t *voe
121  )
122 {
124  return voe->datagram.mem_size -
126  else
127  return 0;
128 }
129 
130 /*****************************************************************************
131  * Application interface.
132  ****************************************************************************/
133 
134 int ecrt_voe_handler_send_header(ec_voe_handler_t *voe, uint32_t vendor_id,
135  uint16_t vendor_type)
136 {
137  voe->vendor_id = vendor_id;
138  voe->vendor_type = vendor_type;
139  return 0;
140 }
141 
142 /****************************************************************************/
143 
145  uint32_t *vendor_id, uint16_t *vendor_type)
146 {
147  uint8_t *header = voe->datagram.data + EC_MBOX_HEADER_SIZE;
148 
149  if (vendor_id)
150  *vendor_id = EC_READ_U32(header);
151  if (vendor_type)
152  *vendor_type = EC_READ_U16(header + 4);
153  return 0;
154 }
155 
156 /****************************************************************************/
157 
159 {
161 }
162 
163 /****************************************************************************/
164 
166 {
167  return voe->data_size;
168 }
169 
170 /****************************************************************************/
171 
173 {
175  voe->dir = EC_DIR_INPUT;
177  voe->request_state = EC_INT_REQUEST_BUSY;
178  return 0;
179 }
180 
181 /****************************************************************************/
182 
184 {
186  voe->dir = EC_DIR_INPUT;
188  voe->request_state = EC_INT_REQUEST_BUSY;
189  return 0;
190 }
191 
192 /****************************************************************************/
193 
195 {
197  voe->dir = EC_DIR_OUTPUT;
198  voe->data_size = size;
200  voe->request_state = EC_INT_REQUEST_BUSY;
201  return 0;
202 }
203 
204 /****************************************************************************/
205 
207 {
208  if (voe->config->slave) { // FIXME locking?
210  voe->state(voe);
211  if (voe->request_state == EC_INT_REQUEST_BUSY) {
213  }
214  } else {
216  voe->request_state = EC_INT_REQUEST_FAILURE;
217  }
218 
220 }
221 
222 /*****************************************************************************
223  * State functions.
224  ****************************************************************************/
225 
229 {
230  ec_slave_t *slave = voe->config->slave;
231  uint8_t *data;
232 
233  if (slave->master->debug_level) {
234  EC_SLAVE_DBG(slave, 0, "Writing %zu bytes of VoE data.\n",
235  voe->data_size);
237  }
238 
239  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
240  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
242  voe->request_state = EC_INT_REQUEST_FAILURE;
243  return;
244  }
245 
246  data = ec_slave_mbox_prepare_send(slave, &voe->datagram,
247  EC_MBOX_TYPE_VOE, EC_VOE_HEADER_SIZE + voe->data_size);
248  if (IS_ERR(data)) {
250  voe->request_state = EC_INT_REQUEST_FAILURE;
251  return;
252  }
253 
254  EC_WRITE_U32(data, voe->vendor_id);
255  EC_WRITE_U16(data + 4, voe->vendor_type);
256  /* data already in datagram */
257 
258  voe->retries = EC_FSM_RETRIES;
259  voe->jiffies_start = jiffies;
261 }
262 
263 /****************************************************************************/
264 
268 {
269  ec_datagram_t *datagram = &voe->datagram;
270  ec_slave_t *slave = voe->config->slave;
271 
272  if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
273  return;
274 
275  if (datagram->state != EC_DATAGRAM_RECEIVED) {
277  voe->request_state = EC_INT_REQUEST_FAILURE;
278  EC_SLAVE_ERR(slave, "Failed to receive VoE write request datagram: ");
279  ec_datagram_print_state(datagram);
280  return;
281  }
282 
283  if (datagram->working_counter != 1) {
284  if (!datagram->working_counter) {
285  unsigned long diff_ms =
286  (jiffies - voe->jiffies_start) * 1000 / HZ;
287  if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
288  EC_SLAVE_DBG(slave, 1, "Slave did not respond to"
289  " VoE write request. Retrying after %lu ms...\n",
290  diff_ms);
291  // no response; send request datagram again
292  return;
293  }
294  }
296  voe->request_state = EC_INT_REQUEST_FAILURE;
297  EC_SLAVE_ERR(slave, "Reception of VoE write request failed: ");
298  ec_datagram_print_wc_error(datagram);
299  return;
300  }
301 
302  EC_CONFIG_DBG(voe->config, 1, "VoE write request successful.\n");
303 
304  voe->request_state = EC_INT_REQUEST_SUCCESS;
306 }
307 
308 /****************************************************************************/
309 
313 {
314  ec_slave_t *slave = voe->config->slave;
315 
316  EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
317 
318  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
319  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
321  voe->request_state = EC_INT_REQUEST_FAILURE;
322  return;
323  }
324 
325  voe->jiffies_start = jiffies;
326  ec_fsm_mbox_receive(&voe->fsm_mbox, slave, &slave->mbox_voe_data,
329  voe->state(voe);
330 }
331 
332 /****************************************************************************/
333 
340 {
341  ec_slave_t *slave = voe->config->slave;
342 
343  EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
344 
345  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
346  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
348  voe->request_state = EC_INT_REQUEST_FAILURE;
349  return;
350  }
351 
352  voe->jiffies_start = jiffies;
353  ec_fsm_mbox_fetch_nosync(&voe->fsm_mbox, slave, &slave->mbox_voe_data,
356  voe->state(voe);
357 }
358 
359 /****************************************************************************/
360 
364 {
365  ec_slave_t *slave = voe->config->slave;
366  ec_master_t *master = voe->config->master;
367  uint8_t *data, mbox_prot;
368  size_t rec_size;
369 
370  if (ec_fsm_mbox_exec(&voe->fsm_mbox, &voe->datagram)) {
371  return;
372  }
373 
374  switch (ec_fsm_mbox_result(&voe->fsm_mbox)) {
375  case 0:
376  break;
377  case -ETIMEDOUT:
378  EC_SLAVE_ERR(slave, "Timeout while waiting for VoE data.\n");
380  voe->request_state = EC_INT_REQUEST_FAILURE;
381  return;
382  case -EAGAIN: // only in nosync mode
383  EC_SLAVE_DBG(slave, 1, "Slave did not send VoE data.\n");
385  voe->request_state = EC_INT_REQUEST_FAILURE;
386  return;
387  default:
389  voe->request_state = EC_INT_REQUEST_FAILURE;
390  return;
391  }
392 
393  data = ec_slave_mbox_fetch(slave, &slave->mbox_voe_data,
394  &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  memcpy(voe->datagram.data + EC_MBOX_HEADER_SIZE, data, rec_size);
425  voe->request_state = EC_INT_REQUEST_SUCCESS;
426  voe->state = ec_voe_handler_state_end; // success
427 }
428 
429 /****************************************************************************/
430 
434 {
435 }
436 
437 /****************************************************************************/
438 
442 {
443 }
444 
445 /****************************************************************************/
446 
449 EXPORT_SYMBOL(ecrt_voe_handler_send_header);
450 EXPORT_SYMBOL(ecrt_voe_handler_received_header);
451 EXPORT_SYMBOL(ecrt_voe_handler_data);
452 EXPORT_SYMBOL(ecrt_voe_handler_data_size);
453 EXPORT_SYMBOL(ecrt_voe_handler_read);
454 EXPORT_SYMBOL(ecrt_voe_handler_write);
455 EXPORT_SYMBOL(ecrt_voe_handler_execute);
456 
459 /****************************************************************************/
#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:143
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:339
ec_sii_t sii
Extracted SII data.
Definition: slave.h:218
void ec_voe_handler_release_mbox_lock(ec_voe_handler_t *voe)
Releases the mailbox read lock, if the handler holds it.
Definition: voe_handler.c:101
int ecrt_voe_handler_read(ec_voe_handler_t *voe)
Start a VoE read operation.
Definition: voe_handler.c:172
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:100
ec_datagram_t datagram
State machine datagram.
Definition: voe_handler.h:45
int ec_fsm_mbox_exec(ec_fsm_mbox_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_mbox.c:161
size_t ec_voe_handler_mem_size(const ec_voe_handler_t *voe)
Get usable memory size.
Definition: voe_handler.c:119
#define EC_VOE_HEADER_SIZE
VoE header size.
Definition: voe_handler.c:37
ec_fsm_mbox_t fsm_mbox
Mailbox receive state machine.
Definition: voe_handler.h:56
void ec_fsm_mbox_receive(ec_fsm_mbox_t *fsm, ec_slave_t *slave, ec_mbox_data_t *mbox_data, unsigned long jiffies_start, unsigned long timeout_ms)
Starts waiting for a mailbox response.
Definition: fsm_mbox.c:102
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:84
EtherCAT datagram.
Definition: datagram.h:81
int ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size)
Start a VoE write operation.
Definition: voe_handler.c:194
ec_master_t * master
Master owning the slave configuration.
Definition: slave_config.h:113
uint8_t * ec_slave_mbox_fetch(const ec_slave_t *slave, ec_mbox_data_t *response_data, uint8_t *type, size_t *size)
Processes received mailbox data.
Definition: mailbox.c:290
uint16_t working_counter
Working counter.
Definition: datagram.h:96
#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:47
void ec_fsm_mbox_fetch_nosync(ec_fsm_mbox_t *fsm, ec_slave_t *slave, ec_mbox_data_t *mbox_data, unsigned long jiffies_start, unsigned long timeout_ms)
Starts a single mailbox fetch without a preceding check.
Definition: fsm_mbox.c:140
EtherCAT master structure.
uint32_t vendor_id
Vendor ID for the header.
Definition: voe_handler.h:46
EtherCAT slave.
Definition: slave.h:170
int ec_fsm_mbox_result(const ec_fsm_mbox_t *fsm)
Returns the result of the terminated state machine.
Definition: fsm_mbox.c:195
ec_datagram_state_t state
State.
Definition: datagram.h:97
void(* state)(ec_voe_handler_t *)
State function.
Definition: voe_handler.h:52
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3400
void ec_fsm_mbox_abort(ec_fsm_mbox_t *fsm)
Aborts the state machine and releases the mailbox read lock, if held.
Definition: fsm_mbox.c:220
ec_internal_request_state_t request_state
Handler state.
Definition: voe_handler.h:53
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:141
size_t data_size
Size of VoE data.
Definition: voe_handler.h:48
unsigned int debug_level
Master debug level.
Definition: master.h:286
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:70
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:605
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:144
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3383
#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 *)
Wait for the VoE read response and process it.
Definition: voe_handler.c:363
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3290
unsigned long jiffies_start
Timestamp for timeout calculation.
Definition: voe_handler.h:55
Vendor specific over EtherCAT handler.
Definition: voe_handler.h:42
ec_master_t * master
Master owning the slave.
Definition: slave.h:172
void ec_master_queue_datagram(ec_master_t *master, ec_datagram_t *datagram)
Places a datagram in the datagram queue.
Definition: master.c:980
Values read by the master.
Definition: ecrt.h:525
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:61
ec_slave_t * slave
Slave pointer.
Definition: slave_config.h:133
ec_device_index_t device_index
Device via which the datagram shall be / was sent.
Definition: datagram.h:87
void ec_voe_handler_state_write_start(ec_voe_handler_t *)
Start writing VoE data.
Definition: voe_handler.c:228
#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:267
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:348
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:312
unsigned int retries
retries upon datagram timeout
Definition: voe_handler.h:54
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3274
ec_direction_t dir
Direction.
Definition: voe_handler.h:49
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
Mailbox functionality.
Invalid direction.
Definition: ecrt.h:523
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:158
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:134
void ec_fsm_mbox_init(ec_fsm_mbox_t *fsm)
Constructor.
Definition: fsm_mbox.c:45
ec_mbox_data_t mbox_voe_data
Received mailbox data for VoE.
Definition: slave.h:241
uint8_t * data
Datagram payload.
Definition: datagram.h:91
size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
Returns the current data size.
Definition: voe_handler.c:165
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
Execute the handler.
Definition: voe_handler.c:206
void ec_voe_handler_state_error(ec_voe_handler_t *)
Failure termination state function.
Definition: voe_handler.c:441
EtherCAT slave configuration.
Definition: slave_config.h:111
EtherCAT slave configuration structure.
size_t mem_size
Datagram data memory size.
Definition: datagram.h:93
ec_device_index_t device_index
Index of device the slave responds on.
Definition: slave.h:173
ec_request_state_t
Request state.
Definition: ecrt.h:658
ec_slave_config_t * config
Parent slave configuration.
Definition: voe_handler.h:44
int ec_fsm_mbox_holds_lock(const ec_fsm_mbox_t *fsm)
Checks, if the state machine holds the slave&#39;s mailbox read lock.
Definition: fsm_mbox.c:208
Values written by the master.
Definition: ecrt.h:524
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:661
EtherCAT master.
Definition: master.h:194
Vendor specific.
Definition: globals.h:155
void ec_fsm_mbox_clear(ec_fsm_mbox_t *fsm)
Destructor.
Definition: fsm_mbox.c:64
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:183
void ec_voe_handler_clear(ec_voe_handler_t *voe)
VoE handler destructor.
Definition: voe_handler.c:85
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:433