IgH EtherCAT Master  1.6.1
fsm_eoe.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * Copyright (C) 2006-2014 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 
27 /****************************************************************************/
28 
29 #include "globals.h"
30 #include "master.h"
31 #include "mailbox.h"
32 #include "fsm_eoe.h"
33 
34 /****************************************************************************/
35 
38 #define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
39 
40 /****************************************************************************/
41 
42 // prototypes for private functions
43 void memcpy_swap32(void *, const void *);
44 
46 
51 
54 
55 /****************************************************************************/
56 
65 void memcpy_swap32(void *dst, const void *src)
66 {
67  int i;
68  for (i = 0; i < 4; i++) {
69  ((u8 *) dst)[i] = ((const u8 *) src)[3 - i];
70  }
71 }
72 
73 /****************************************************************************/
74 
78  ec_fsm_eoe_t *fsm
79  )
80 {
81  fsm->slave = NULL;
82  fsm->retries = 0;
83  fsm->state = NULL;
84  fsm->datagram = NULL;
85  fsm->jiffies_start = 0;
86  fsm->request = NULL;
87  fsm->frame_type_retries = 0;
88 }
89 
90 /****************************************************************************/
91 
95  ec_fsm_eoe_t *fsm
96  )
97 {
98 }
99 
100 /****************************************************************************/
101 
105  ec_fsm_eoe_t *fsm,
106  ec_slave_t *slave,
107  ec_eoe_request_t *request
108  )
109 {
110  fsm->slave = slave;
111  fsm->request = request;
113 }
114 
115 /****************************************************************************/
116 
122  ec_fsm_eoe_t *fsm,
123  ec_datagram_t *datagram
124  )
125 {
126  int datagram_used = 0;
127 
128  if (fsm->datagram &&
129  (fsm->datagram->state == EC_DATAGRAM_INIT ||
130  fsm->datagram->state == EC_DATAGRAM_QUEUED ||
131  fsm->datagram->state == EC_DATAGRAM_SENT)) {
132  // datagram not received yet
133  return datagram_used;
134  }
135 
136  fsm->state(fsm, datagram);
137 
138  datagram_used =
139  fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error;
140 
141  if (datagram_used) {
142  fsm->datagram = datagram;
143  } else {
144  fsm->datagram = NULL;
145  }
146 
147  return datagram_used;
148 }
149 
150 /****************************************************************************/
151 
157 {
158  return fsm->state == ec_fsm_eoe_end;
159 }
160 
161 /*****************************************************************************
162  * EoE set IP parameter state machine
163  ****************************************************************************/
164 
170  ec_fsm_eoe_t *fsm,
171  ec_datagram_t *datagram
172  )
173 {
174  uint8_t *data, *cur;
175  ec_slave_t *slave = fsm->slave;
176  ec_master_t *master = slave->master;
177  ec_eoe_request_t *req = fsm->request;
178 
179  // Note: based on wireshark packet filter it suggests that the EOE_INIT
180  // information is a fixed size with fixed information positions.
181  // see: packet-ecatmb.h and packet-ecatmb.c
182  // However, TwinCAT 2.1 testing also indicates that if a piece of
183  // information is missing then all subsequent items are ignored
184  // Also, if you want DHCP, then only set the mac address.
185  size_t size = 8 + // header + flags
186  ETH_ALEN + // mac address
187  4 + // ip address
188  4 + // subnet mask
189  4 + // gateway
190  4 + // dns server
191  EC_MAX_HOSTNAME_SIZE; // dns name
192 
193  data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
194  size);
195  if (IS_ERR(data)) {
196  return PTR_ERR(data);
197  }
198 
199  // zero data
200  memset(data, 0, size);
201 
202  // header
203  EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
204  EC_WRITE_U8(data + 1, 0x00); // not used
205  EC_WRITE_U16(data + 2, 0x0000); // not used
206 
207  EC_WRITE_U32(data + 4,
208  ((req->mac_address_included != 0) << 0) |
209  ((req->ip_address_included != 0) << 1) |
210  ((req->subnet_mask_included != 0) << 2) |
211  ((req->gateway_included != 0) << 3) |
212  ((req->dns_included != 0) << 4) |
213  ((req->name_included != 0) << 5)
214  );
215 
216  cur = data + 8;
217 
218  if (req->mac_address_included) {
219  memcpy(cur, req->mac_address, ETH_ALEN);
220  }
221  cur += ETH_ALEN;
222 
223  if (req->ip_address_included) {
224  memcpy_swap32(cur, &req->ip_address);
225  }
226  cur += 4;
227 
228  if (req->subnet_mask_included) {
229  memcpy_swap32(cur, &req->subnet_mask);
230  }
231  cur += 4;
232 
233  if (req->gateway_included) {
234  memcpy_swap32(cur, &req->gateway);
235  }
236  cur += 4;
237 
238  if (req->dns_included) {
239  memcpy_swap32(cur, &req->dns);
240  }
241  cur += 4;
242 
243  if (req->name_included) {
244  memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
245  }
246  cur += EC_MAX_HOSTNAME_SIZE;
247 
248  if (master->debug_level) {
249  EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
250  ec_print_data(data, cur - data);
251  }
252 
253  fsm->request->jiffies_sent = jiffies;
254 
255  return 0;
256 }
257 
258 /****************************************************************************/
259 
263  ec_fsm_eoe_t *fsm,
264  ec_datagram_t *datagram
265  )
266 {
267  ec_slave_t *slave = fsm->slave;
268 
269  EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
270 
271  if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
272  EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
273  fsm->state = ec_fsm_eoe_error;
274  return;
275  }
276 
277  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
278  fsm->state = ec_fsm_eoe_error;
279  return;
280  }
281 
282  fsm->retries = EC_FSM_RETRIES;
284 }
285 
286 /****************************************************************************/
287 
291  ec_fsm_eoe_t *fsm,
292  ec_datagram_t *datagram
293  )
294 {
295  ec_slave_t *slave = fsm->slave;
296 
297  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
298  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
299  fsm->state = ec_fsm_eoe_error;
300  }
301  return;
302  }
303 
304  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
305  fsm->state = ec_fsm_eoe_error;
306  EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
307  " request: ");
309  return;
310  }
311 
312  if (fsm->datagram->working_counter != 1) {
313  unsigned long diff_ms =
314  (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
315 
316  if (!fsm->datagram->working_counter) {
317  if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
318  // no response; send request datagram again
319  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
320  fsm->state = ec_fsm_eoe_error;
321  }
322  return;
323  }
324  }
325  fsm->state = ec_fsm_eoe_error;
326  EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
327  " failed after %lu ms: ", diff_ms);
329  return;
330  }
331 
332  fsm->jiffies_start = fsm->datagram->jiffies_sent;
333  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
334  fsm->retries = EC_FSM_RETRIES;
336  fsm->frame_type_retries = 10;
337 }
338 
339 /****************************************************************************/
340 
344  ec_fsm_eoe_t *fsm,
345  ec_datagram_t *datagram
346  )
347 {
348  ec_slave_t *slave = fsm->slave;
349 
350  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
351  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
352  return;
353  }
354 
355  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
356  fsm->state = ec_fsm_eoe_error;
357  EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
359  return;
360  }
361 
362  if (fsm->datagram->working_counter != 1) {
363  fsm->state = ec_fsm_eoe_error;
364  EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
365  " datagram failed: ");
367  return;
368  }
369 
370  if (!ec_slave_mbox_check(fsm->datagram)) {
371  unsigned long diff_ms =
372  (fsm->datagram->jiffies_received - fsm->jiffies_start) *
373  1000 / HZ;
374  if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
375  fsm->state = ec_fsm_eoe_error;
376  EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
377  " set IP parameter response.\n", diff_ms);
378  return;
379  }
380 
381  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
382  fsm->retries = EC_FSM_RETRIES;
383  return;
384  }
385 
386  // fetch response
387  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
388  fsm->retries = EC_FSM_RETRIES;
390 }
391 
392 /****************************************************************************/
393 
397  ec_fsm_eoe_t *fsm,
398  ec_datagram_t *datagram
399  )
400 {
401  ec_slave_t *slave = fsm->slave;
402  ec_master_t *master = slave->master;
403  uint8_t *data, mbox_prot, frame_type;
404  size_t rec_size;
405  ec_eoe_request_t *req = fsm->request;
406 
407  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
408  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
409  return;
410  }
411 
412  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
413  fsm->state = ec_fsm_eoe_error;
414  EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
416  return;
417  }
418 
419  if (fsm->datagram->working_counter != 1) {
420  fsm->state = ec_fsm_eoe_error;
421  EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
423  return;
424  }
425 
426  data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size);
427  if (IS_ERR(data)) {
428  fsm->state = ec_fsm_eoe_error;
429  return;
430  }
431 
432  if (master->debug_level) {
433  EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
434  ec_print_data(data, rec_size);
435  }
436 
437  if (mbox_prot != EC_MBOX_TYPE_EOE) {
438  fsm->state = ec_fsm_eoe_error;
439  EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
440  mbox_prot);
441  return;
442  }
443 
444  if (rec_size < 4) {
445  fsm->state = ec_fsm_eoe_error;
446  EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
447  " (%zu bytes)!\n", rec_size);
448  ec_print_data(data, rec_size);
449  return;
450  }
451 
452  frame_type = EC_READ_U8(data) & 0x0f;
453 
454  if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
455  if (master->debug_level) {
456  EC_SLAVE_DBG(slave, 0, "Received no set IP parameter response"
457  " (frame type %x).\n", frame_type);
458  ec_print_data(data, rec_size);
459  }
460  if (fsm->frame_type_retries--) {
461  // there may be an EoE segment left in the mailbox.
462  // discard it and receive again.
463  fsm->jiffies_start = fsm->datagram->jiffies_sent;
464  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
465  fsm->retries = EC_FSM_RETRIES;
467  return;
468  }
469  else {
470  EC_SLAVE_ERR(slave, "Received no set IP parameter response.\n");
471  fsm->state = ec_fsm_eoe_error;
472  return;
473  }
474  }
475 
476  req->result = EC_READ_U16(data + 2); // result code 0x0000 means success
477 
478  if (req->result) {
479  fsm->state = ec_fsm_eoe_error;
480  EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
481  " 0x%04X.\n", req->result);
482  } else {
483  fsm->state = ec_fsm_eoe_end; // success
484  }
485 }
486 
487 /****************************************************************************/
488 
492  ec_fsm_eoe_t *fsm,
493  ec_datagram_t *datagram
494  )
495 {
496 }
497 
498 /****************************************************************************/
499 
503  ec_fsm_eoe_t *fsm,
504  ec_datagram_t *datagram
505  )
506 {
507 }
508 
509 /****************************************************************************/
#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:121
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
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:98
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
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:98
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_eoe.h:44
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
EtherCAT datagram.
Definition: datagram.h:79
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3137
uint16_t working_counter
Working counter.
Definition: datagram.h:93
ec_eoe_request_t * request
EoE request.
Definition: fsm_eoe.h:50
void ec_fsm_eoe_init(ec_fsm_eoe_t *fsm)
Constructor.
Definition: fsm_eoe.c:77
unsigned long jiffies_sent
Jiffies, when the request was sent.
Definition: eoe_request.h:44
Sent (still in the queue).
Definition: datagram.h:69
#define EC_MAX_HOSTNAME_SIZE
Maximum hostname size.
Definition: globals.h:110
Set IP Parameter Request.
Definition: ethernet.h:46
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:104
Global definitions and macros.
EtherCAT master structure.
Initial state of a new datagram.
Definition: datagram.h:67
unsigned long jiffies_start
Timestamp.
Definition: fsm_eoe.h:49
EtherCAT slave.
Definition: slave.h:168
void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP CHECK.
Definition: fsm_eoe.c:343
ec_datagram_state_t state
State.
Definition: datagram.h:94
Initiate EoE Request.
Definition: ethernet.h:45
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3171
Ethernet over EtherCAT.
Definition: globals.h:145
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:139
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
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP START.
Definition: fsm_eoe.c:262
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3154
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_eoe.c:156
ec_master_t * master
Master owning the slave.
Definition: slave.h:170
void(* state)(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state function.
Definition: fsm_eoe.h:47
void memcpy_swap32(void *, const void *)
Host-architecture-independent 32-bit swap function.
Definition: fsm_eoe.c:65
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_eoe.c:491
Ethernet-over-EtherCAT set IP parameter request.
Definition: eoe_request.h:41
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:344
void ec_fsm_eoe_clear(ec_fsm_eoe_t *fsm)
Destructor.
Definition: fsm_eoe.c:94
unsigned int frame_type_retries
retries upon wrong frame type.
Definition: fsm_eoe.h:51
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
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *)
State: END.
Definition: fsm_eoe.c:502
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:557
Mailbox functionality.
#define EC_EOE_RESPONSE_TIMEOUT
Maximum time to wait for a set IP parameter response.
Definition: fsm_eoe.c:38
void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP RESPONSE.
Definition: fsm_eoe.c:396
Queued for sending.
Definition: datagram.h:68
Timed out (dequeued).
Definition: datagram.h:71
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3029
unsigned int retries
retries upon datagram timeout
Definition: fsm_eoe.h:45
Received (dequeued).
Definition: datagram.h:70
int ec_fsm_eoe_prepare_set(ec_fsm_eoe_t *, ec_datagram_t *)
Prepare a set IP parameters operation.
Definition: fsm_eoe.c:169
EtherCAT master.
Definition: master.h:187
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
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP REQUEST.
Definition: fsm_eoe.c:290
Finite state machines for the Ethernet over EtherCAT protocol.
Definition: fsm_eoe.h:43
ec_datagram_t * datagram
Datagram used in the previous step.
Definition: fsm_eoe.h:48