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?
209  voe->state(voe);
210  if (voe->request_state == EC_INT_REQUEST_BUSY) {
212  }
213  } else {
215  voe->request_state = EC_INT_REQUEST_FAILURE;
216  }
217 
219 }
220 
221 /*****************************************************************************
222  * State functions.
223  ****************************************************************************/
224 
228 {
229  ec_slave_t *slave = voe->config->slave;
230  uint8_t *data;
231 
232  if (slave->master->debug_level) {
233  EC_SLAVE_DBG(slave, 0, "Writing %zu bytes of VoE data.\n",
234  voe->data_size);
236  }
237 
238  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
239  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
241  voe->request_state = EC_INT_REQUEST_FAILURE;
242  return;
243  }
244 
245  data = ec_slave_mbox_prepare_send(slave, &voe->datagram,
246  EC_MBOX_TYPE_VOE, EC_VOE_HEADER_SIZE + voe->data_size);
247  if (IS_ERR(data)) {
249  voe->request_state = EC_INT_REQUEST_FAILURE;
250  return;
251  }
252 
253  EC_WRITE_U32(data, voe->vendor_id);
254  EC_WRITE_U16(data + 4, voe->vendor_type);
255  /* data already in datagram */
256 
257  voe->retries = EC_FSM_RETRIES;
258  voe->jiffies_start = jiffies;
260 }
261 
262 /****************************************************************************/
263 
267 {
268  ec_datagram_t *datagram = &voe->datagram;
269  ec_slave_t *slave = voe->config->slave;
270 
271  if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--)
272  return;
273 
274  if (datagram->state != EC_DATAGRAM_RECEIVED) {
276  voe->request_state = EC_INT_REQUEST_FAILURE;
277  EC_SLAVE_ERR(slave, "Failed to receive VoE write request datagram: ");
278  ec_datagram_print_state(datagram);
279  return;
280  }
281 
282  if (datagram->working_counter != 1) {
283  if (!datagram->working_counter) {
284  unsigned long diff_ms =
285  (jiffies - voe->jiffies_start) * 1000 / HZ;
286  if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
287  EC_SLAVE_DBG(slave, 1, "Slave did not respond to"
288  " VoE write request. Retrying after %lu ms...\n",
289  diff_ms);
290  // no response; send request datagram again
291  return;
292  }
293  }
295  voe->request_state = EC_INT_REQUEST_FAILURE;
296  EC_SLAVE_ERR(slave, "Reception of VoE write request failed: ");
297  ec_datagram_print_wc_error(datagram);
298  return;
299  }
300 
301  EC_CONFIG_DBG(voe->config, 1, "VoE write request successful.\n");
302 
303  voe->request_state = EC_INT_REQUEST_SUCCESS;
305 }
306 
307 /****************************************************************************/
308 
312 {
313  ec_slave_t *slave = voe->config->slave;
314 
315  EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
316 
317  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
318  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
320  voe->request_state = EC_INT_REQUEST_FAILURE;
321  return;
322  }
323 
324  voe->jiffies_start = jiffies;
325  ec_fsm_mbox_receive(&voe->fsm_mbox, slave, &slave->mbox_voe_data,
328  voe->state(voe);
329 }
330 
331 /****************************************************************************/
332 
339 {
340  ec_slave_t *slave = voe->config->slave;
341 
342  EC_SLAVE_DBG(slave, 1, "Reading VoE data.\n");
343 
344  if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) {
345  EC_SLAVE_ERR(slave, "Slave does not support VoE!\n");
347  voe->request_state = EC_INT_REQUEST_FAILURE;
348  return;
349  }
350 
351  voe->jiffies_start = jiffies;
352  ec_fsm_mbox_fetch_nosync(&voe->fsm_mbox, slave, &slave->mbox_voe_data,
355  voe->state(voe);
356 }
357 
358 /****************************************************************************/
359 
363 {
364  ec_slave_t *slave = voe->config->slave;
365  ec_master_t *master = voe->config->master;
366  uint8_t *data, mbox_prot;
367  size_t rec_size;
368 
369  if (ec_fsm_mbox_exec(&voe->fsm_mbox, &voe->datagram)) {
370  return;
371  }
372 
373  switch (ec_fsm_mbox_result(&voe->fsm_mbox)) {
374  case 0:
375  break;
376  case -ETIMEDOUT:
377  EC_SLAVE_ERR(slave, "Timeout while waiting for VoE data.\n");
379  voe->request_state = EC_INT_REQUEST_FAILURE;
380  return;
381  case -EAGAIN: // only in nosync mode
382  EC_SLAVE_DBG(slave, 1, "Slave did not send VoE data.\n");
384  voe->request_state = EC_INT_REQUEST_FAILURE;
385  return;
386  default:
388  voe->request_state = EC_INT_REQUEST_FAILURE;
389  return;
390  }
391 
392  data = ec_slave_mbox_fetch(slave, &slave->mbox_voe_data,
393  &mbox_prot, &rec_size);
394  if (IS_ERR(data)) {
396  voe->request_state = EC_INT_REQUEST_FAILURE;
397  return;
398  }
399 
400  if (mbox_prot != EC_MBOX_TYPE_VOE) {
402  voe->request_state = EC_INT_REQUEST_FAILURE;
403  EC_SLAVE_WARN(slave, "Received mailbox protocol 0x%02X"
404  " as response.\n", mbox_prot);
405  ec_print_data(data, rec_size);
406  return;
407  }
408 
409  if (rec_size < EC_VOE_HEADER_SIZE) {
411  voe->request_state = EC_INT_REQUEST_FAILURE;
412  EC_SLAVE_ERR(slave, "Received VoE header is"
413  " incomplete (%zu bytes)!\n", rec_size);
414  return;
415  }
416 
417  if (master->debug_level) {
418  EC_CONFIG_DBG(voe->config, 0, "VoE data:\n");
419  ec_print_data(data, rec_size);
420  }
421 
422  voe->data_size = rec_size - EC_VOE_HEADER_SIZE;
423  memcpy(voe->datagram.data + EC_MBOX_HEADER_SIZE, data, rec_size);
424  voe->request_state = EC_INT_REQUEST_SUCCESS;
425  voe->state = ec_voe_handler_state_end; // success
426 }
427 
428 /****************************************************************************/
429 
433 {
434 }
435 
436 /****************************************************************************/
437 
441 {
442 }
443 
444 /****************************************************************************/
445 
448 EXPORT_SYMBOL(ecrt_voe_handler_send_header);
449 EXPORT_SYMBOL(ecrt_voe_handler_received_header);
450 EXPORT_SYMBOL(ecrt_voe_handler_data);
451 EXPORT_SYMBOL(ecrt_voe_handler_data_size);
452 EXPORT_SYMBOL(ecrt_voe_handler_read);
453 EXPORT_SYMBOL(ecrt_voe_handler_write);
454 EXPORT_SYMBOL(ecrt_voe_handler_execute);
455 
458 /****************************************************************************/
#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:338
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:3387
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:284
#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:3370
#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:362
#define EC_READ_U32(DATA)
Read a 32-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3277
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
void ec_voe_handler_state_write_start(ec_voe_handler_t *)
Start writing VoE data.
Definition: voe_handler.c:227
#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:266
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:311
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:3261
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:440
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_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:432