IgH EtherCAT Master  1.6.0-rc1
fsm_eoe.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2006-2014 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 
35 /*****************************************************************************/
36 
37 #include "globals.h"
38 #include "master.h"
39 #include "mailbox.h"
40 #include "fsm_eoe.h"
41 
42 /*****************************************************************************/
43 
46 #define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
47 
48 /*****************************************************************************/
49 
55 
58 
59 /*****************************************************************************/
60 
64  ec_fsm_eoe_t *fsm
65  )
66 {
67  fsm->slave = NULL;
68  fsm->retries = 0;
69  fsm->state = NULL;
70  fsm->datagram = NULL;
71  fsm->jiffies_start = 0;
72  fsm->request = NULL;
73 }
74 
75 /*****************************************************************************/
76 
80  ec_fsm_eoe_t *fsm
81  )
82 {
83 }
84 
85 /*****************************************************************************/
86 
90  ec_fsm_eoe_t *fsm,
91  ec_slave_t *slave,
92  ec_eoe_request_t *request
93  )
94 {
95  fsm->slave = slave;
96  fsm->request = request;
98 }
99 
100 /*****************************************************************************/
101 
107  ec_fsm_eoe_t *fsm,
108  ec_datagram_t *datagram
109  )
110 {
111  if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error)
112  return 0;
113 
114  if (fsm->datagram &&
115  (fsm->datagram->state == EC_DATAGRAM_INIT ||
116  fsm->datagram->state == EC_DATAGRAM_QUEUED ||
117  fsm->datagram->state == EC_DATAGRAM_SENT)) {
118  // datagram not received yet
119  if (datagram != fsm->datagram)
120  datagram->state = EC_DATAGRAM_INVALID;
121  return 1;
122  }
123 
124  fsm->state(fsm, datagram);
125 
126  if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error) {
127  fsm->datagram = NULL;
128  return 0;
129  }
130 
131  fsm->datagram = datagram;
132  return 1;
133 }
134 
135 /*****************************************************************************/
136 
142 {
143  return fsm->state == ec_fsm_eoe_end;
144 }
145 
146 /******************************************************************************
147  * EoE set IP parameter state machine
148  *****************************************************************************/
149 
155  ec_fsm_eoe_t *fsm,
156  ec_datagram_t *datagram
157  )
158 {
159  uint8_t *data, *cur;
160  ec_slave_t *slave = fsm->slave;
161  ec_master_t *master = slave->master;
162  ec_eoe_request_t *req = fsm->request;
163 
164  // Note: based on wireshark packet filter it suggests that the EOE_INIT
165  // information is a fixed size with fixed information positions.
166  // see: packet-ecatmb.h and packet-ecatmb.c
167  // However, TwinCAT 2.1 testing also indicates that if a piece of
168  // information is missing then all subsequent items are ignored
169  // Also, if you want DHCP, then only set the mac address.
170  size_t size = 8 + // header + flags
171  ETH_ALEN + // mac address
172  4 + // ip address
173  4 + // subnet mask
174  4 + // gateway
175  4 + // dns server
176  EC_MAX_HOSTNAME_SIZE; // dns name
177 
178  data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
179  size);
180  if (IS_ERR(data)) {
181  return PTR_ERR(data);
182  }
183 
184  // zero data
185  memset(data, 0, size);
186 
187  // header
188  EC_WRITE_U8(data, EC_EOE_TYPE_INIT_REQ); // Set IP parameter req.
189  EC_WRITE_U8(data + 1, 0x00); // not used
190  EC_WRITE_U16(data + 2, 0x0000); // not used
191 
192  EC_WRITE_U32(data + 4,
193  ((req->mac_address_included != 0) << 0) |
194  ((req->ip_address_included != 0) << 1) |
195  ((req->subnet_mask_included != 0) << 2) |
196  ((req->gateway_included != 0) << 3) |
197  ((req->dns_included != 0) << 4) |
198  ((req->name_included != 0) << 5)
199  );
200 
201  cur = data + 8;
202 
203  if (req->mac_address_included) {
204  memcpy(cur, req->mac_address, ETH_ALEN);
205  }
206  cur += ETH_ALEN;
207 
208  if (req->ip_address_included) {
209  uint32_t swapped = htonl(req->ip_address);
210  memcpy(cur, &swapped, 4);
211  }
212  cur += 4;
213 
214  if (req->subnet_mask_included) {
215  uint32_t swapped = htonl(req->subnet_mask);
216  memcpy(cur, &swapped, 4);
217  }
218  cur += 4;
219 
220  if (req->gateway_included) {
221  uint32_t swapped = htonl(req->gateway);
222  memcpy(cur, &swapped, 4);
223  }
224  cur += 4;
225 
226  if (req->dns_included) {
227  uint32_t swapped = htonl(req->dns);
228  memcpy(cur, &swapped, 4);
229  }
230  cur += 4;
231 
232  if (req->name_included) {
233  memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
234  }
235  cur += EC_MAX_HOSTNAME_SIZE;
236 
237  if (master->debug_level) {
238  EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
239  ec_print_data(data, cur - data);
240  }
241 
242  fsm->request->jiffies_sent = jiffies;
243 
244  return 0;
245 }
246 
247 /*****************************************************************************/
248 
252  ec_fsm_eoe_t *fsm,
253  ec_datagram_t *datagram
254  )
255 {
256  ec_slave_t *slave = fsm->slave;
257 
258  EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
259 
260  if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
261  EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
262  fsm->state = ec_fsm_eoe_error;
263  return;
264  }
265 
266  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
267  fsm->state = ec_fsm_eoe_error;
268  return;
269  }
270 
271  fsm->retries = EC_FSM_RETRIES;
273 }
274 
275 /*****************************************************************************/
276 
280  ec_fsm_eoe_t *fsm,
281  ec_datagram_t *datagram
282  )
283 {
284  ec_slave_t *slave = fsm->slave;
285 
286  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
287  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
288  fsm->state = ec_fsm_eoe_error;
289  }
290  return;
291  }
292 
293  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
294  fsm->state = ec_fsm_eoe_error;
295  EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
296  " request: ");
298  return;
299  }
300 
301  if (fsm->datagram->working_counter != 1) {
302  unsigned long diff_ms =
303  (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
304 
305  if (!fsm->datagram->working_counter) {
306  if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
307  // no response; send request datagram again
308  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
309  fsm->state = ec_fsm_eoe_error;
310  }
311  return;
312  }
313  }
314  fsm->state = ec_fsm_eoe_error;
315  EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
316  " failed after %lu ms: ", diff_ms);
318  return;
319  }
320 
321  fsm->jiffies_start = fsm->datagram->jiffies_sent;
322 
323  // mailbox read check is skipped if a read request is already ongoing
324  if (ec_read_mbox_locked(slave)) {
326  // the datagram is not used and marked as invalid
327  datagram->state = EC_DATAGRAM_INVALID;
328  } else {
329  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
330  fsm->retries = EC_FSM_RETRIES;
332  }
333 }
334 
335 /*****************************************************************************/
336 
340  ec_fsm_eoe_t *fsm,
341  ec_datagram_t *datagram
342  )
343 {
344  ec_slave_t *slave = fsm->slave;
345 
346  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
347  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
348  return;
349  }
350 
351  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
352  fsm->state = ec_fsm_eoe_error;
354  EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
356  return;
357  }
358 
359  if (fsm->datagram->working_counter != 1) {
360  fsm->state = ec_fsm_eoe_error;
362  EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
363  " datagram failed: ");
365  return;
366  }
367 
368  if (!ec_slave_mbox_check(fsm->datagram)) {
369  unsigned long diff_ms;
370 
371  // check that data is not already received by another read request
372  if (slave->mbox_eoe_init_data.payload_size > 0) {
375  fsm->state(fsm, datagram);
376  return;
377  }
378 
379  diff_ms = (fsm->datagram->jiffies_received - fsm->jiffies_start) *
380  1000 / HZ;
381  if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
382  fsm->state = ec_fsm_eoe_error;
384  EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
385  " set IP parameter response.\n", diff_ms);
386  return;
387  }
388 
389  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
390  fsm->retries = EC_FSM_RETRIES;
391  return;
392  }
393 
394  // fetch response
395  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
396  fsm->retries = EC_FSM_RETRIES;
398 }
399 
400 /*****************************************************************************/
401 
405  ec_fsm_eoe_t *fsm,
406  ec_datagram_t *datagram
407  )
408 {
409  ec_slave_t *slave = fsm->slave;
410 
411  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
412  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
413  return;
414  }
415 
416  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
417  fsm->state = ec_fsm_eoe_error;
419  EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
421  return;
422  }
423 
424  if (fsm->datagram->working_counter != 1) {
425  // only an error if data has not already been read by another read request
426  if (slave->mbox_eoe_init_data.payload_size == 0) {
427  fsm->state = ec_fsm_eoe_error;
429  EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
431  return;
432  }
433  }
436  fsm->state(fsm, datagram);
437 }
438 
439 /*****************************************************************************/
440 
444  ec_fsm_eoe_t *fsm,
445  ec_datagram_t *datagram
446  )
447 {
448  ec_slave_t *slave = fsm->slave;
449  ec_master_t *master = slave->master;
450  uint8_t *data, mbox_prot, eoe_type;
451  size_t rec_size;
452  ec_eoe_request_t *req = fsm->request;
453 
454  // process the data available or initiate a new mailbox read check
455  if (slave->mbox_eoe_init_data.payload_size > 0) {
456  slave->mbox_eoe_init_data.payload_size = 0;
457  } else {
458  // initiate a new mailbox read check if required data is not available
459  if (ec_read_mbox_locked(slave)) {
460  // await current read request and mark the datagram as invalid
461  datagram->state = EC_DATAGRAM_INVALID;
462  } else {
463  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
465  }
466  return;
467  }
468 
469  data = ec_slave_mbox_fetch(slave, &slave->mbox_eoe_init_data, &mbox_prot, &rec_size);
470  if (IS_ERR(data)) {
471  fsm->state = ec_fsm_eoe_error;
472  return;
473  }
474 
475  if (master->debug_level) {
476  EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
477  ec_print_data(data, rec_size);
478  }
479 
480  if (mbox_prot != EC_MBOX_TYPE_EOE) {
481  fsm->state = ec_fsm_eoe_error;
482  EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
483  mbox_prot);
484  return;
485  }
486 
487  if (rec_size < 4) {
488  fsm->state = ec_fsm_eoe_error;
489  EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
490  " (%zu bytes)!\n", rec_size);
491  ec_print_data(data, rec_size);
492  return;
493  }
494 
495  eoe_type = EC_READ_U8(data) & 0x0F;
496 
497  if (eoe_type != EC_EOE_TYPE_INIT_RES) {
498  EC_SLAVE_ERR(slave, "EoE Init handler received other EoE type response"
499  " (type %x). Dropping.\n", eoe_type);
500  ec_print_data(data, rec_size);
501  fsm->state = ec_fsm_eoe_error;
502  return;
503  }
504 
505  req->result = EC_READ_U16(data + 2);
506 
507  if (req->result) {
508  fsm->state = ec_fsm_eoe_error;
509  EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
510  " 0x%04X.\n", req->result);
511  } else {
512  fsm->state = ec_fsm_eoe_end; // success
513  }
514 }
515 
516 /*****************************************************************************/
517 
521  ec_fsm_eoe_t *fsm,
522  ec_datagram_t *datagram
523  )
524 {
525 }
526 
527 /*****************************************************************************/
528 
532  ec_fsm_eoe_t *fsm,
533  ec_datagram_t *datagram
534  )
535 {
536 }
537 
538 /*****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
int ec_fsm_eoe_exec(ec_fsm_eoe_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_eoe.c:106
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
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
ec_sii_t sii
Extracted SII data.
Definition: slave.h:246
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:107
ec_mbox_data_t mbox_eoe_init_data
Received mailbox data for EoE, type eoe init reponse.
Definition: slave.h:266
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_eoe.h:52
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:128
EtherCAT datagram.
Definition: datagram.h:88
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2338
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:166
void ec_fsm_eoe_set_ip_response_data(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP RESPONSE DATA.
Definition: fsm_eoe.c:443
uint16_t working_counter
Working counter.
Definition: datagram.h:100
ec_eoe_request_t * request
EoE request.
Definition: fsm_eoe.h:58
void ec_fsm_eoe_init(ec_fsm_eoe_t *fsm)
Constructor.
Definition: fsm_eoe.c:63
unsigned long jiffies_sent
Jiffies, when the request was sent.
Definition: eoe_request.h:52
Sent (still in the queue).
Definition: datagram.h:77
#define EC_MAX_HOSTNAME_SIZE
Maximum hostname size.
Definition: globals.h:116
EtherCAT EoE set IP parameter state machines.
void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *fsm, ec_slave_t *slave, ec_eoe_request_t *request)
Starts to set the EoE IP partameters of a slave.
Definition: fsm_eoe.c:89
Global definitions and macros.
EtherCAT master structure.
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *)
State: END.
Definition: fsm_eoe.c:531
Initial state of a new datagram.
Definition: datagram.h:75
unsigned long jiffies_start
Timestamp.
Definition: fsm_eoe.h:57
EtherCAT slave.
Definition: slave.h:199
ec_datagram_state_t state
State.
Definition: datagram.h:101
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP REQUEST.
Definition: fsm_eoe.c:279
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2372
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:170
unsigned int debug_level
Master debug level.
Definition: master.h:285
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:77
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:606
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2355
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_eoe.c:141
EoE Init, Set IP Parameter Request.
Definition: ethernet.h:56
Ethernet over EtherCAT.
Definition: globals.h:151
ec_master_t * master
Master owning the slave.
Definition: slave.h:201
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP START.
Definition: fsm_eoe.c:251
void(* state)(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state function.
Definition: fsm_eoe.h:55
int ec_read_mbox_locked(ec_slave_t *slave)
Return the current mailbox lock status and lock it if not locked.
Definition: slave.c:203
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_eoe.c:520
Ethernet-over-EtherCAT set IP parameter request.
Definition: eoe_request.h:49
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:345
void ec_fsm_eoe_clear(ec_fsm_eoe_t *fsm)
Destructor.
Definition: fsm_eoe.c:79
void ec_read_mbox_lock_clear(ec_slave_t *slave)
Clears the mailbox lock.
Definition: slave.c:190
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:97
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2250
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:566
Mailbox functionality.
#define EC_EOE_RESPONSE_TIMEOUT
Maximum time to wait for a set IP parameter response.
Definition: fsm_eoe.c:46
EoE Timestamp Response.
Definition: ethernet.h:55
Queued for sending.
Definition: datagram.h:76
Timed out (dequeued).
Definition: datagram.h:79
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2234
void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP CHECK.
Definition: fsm_eoe.c:339
Unused and should not be queued (dequeued).
Definition: datagram.h:81
unsigned int retries
retries upon datagram timeout
Definition: fsm_eoe.h:53
Received (dequeued).
Definition: datagram.h:78
int ec_fsm_eoe_prepare_set(ec_fsm_eoe_t *fsm, ec_datagram_t *datagram)
Prepare a set IP parameters operation.
Definition: fsm_eoe.c:154
void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP RESPONSE.
Definition: fsm_eoe.c:404
EtherCAT master.
Definition: master.h:189
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:110
size_t payload_size
Size of the mailbox response payload data.
Definition: datagram.h:125
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition: mailbox.c:116
Finite state machines for the Ethernet over EtherCAT protocol.
Definition: fsm_eoe.h:51
ec_datagram_t * datagram
Datagram used in the previous step.
Definition: fsm_eoe.h:56