IgH EtherCAT Master  1.6.0
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 
46 
49 
50 /****************************************************************************/
51 
55  ec_fsm_eoe_t *fsm
56  )
57 {
58  fsm->slave = NULL;
59  fsm->retries = 0;
60  fsm->state = NULL;
61  fsm->datagram = NULL;
62  fsm->jiffies_start = 0;
63  fsm->request = NULL;
64 }
65 
66 /****************************************************************************/
67 
71  ec_fsm_eoe_t *fsm
72  )
73 {
74 }
75 
76 /****************************************************************************/
77 
81  ec_fsm_eoe_t *fsm,
82  ec_slave_t *slave,
83  ec_eoe_request_t *request
84  )
85 {
86  fsm->slave = slave;
87  fsm->request = request;
89 }
90 
91 /****************************************************************************/
92 
98  ec_fsm_eoe_t *fsm,
99  ec_datagram_t *datagram
100  )
101 {
102  int datagram_used = 0;
103 
104  if (fsm->datagram &&
105  (fsm->datagram->state == EC_DATAGRAM_INIT ||
106  fsm->datagram->state == EC_DATAGRAM_QUEUED ||
107  fsm->datagram->state == EC_DATAGRAM_SENT)) {
108  // datagram not received yet
109  return datagram_used;
110  }
111 
112  fsm->state(fsm, datagram);
113 
114  datagram_used =
115  fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error;
116 
117  if (datagram_used) {
118  fsm->datagram = datagram;
119  } else {
120  fsm->datagram = NULL;
121  }
122 
123  return datagram_used;
124 }
125 
126 /****************************************************************************/
127 
133 {
134  return fsm->state == ec_fsm_eoe_end;
135 }
136 
137 /*****************************************************************************
138  * EoE set IP parameter state machine
139  ****************************************************************************/
140 
146  ec_fsm_eoe_t *fsm,
147  ec_datagram_t *datagram
148  )
149 {
150  uint8_t *data, *cur;
151  ec_slave_t *slave = fsm->slave;
152  ec_master_t *master = slave->master;
153  ec_eoe_request_t *req = fsm->request;
154 
155  // Note: based on wireshark packet filter it suggests that the EOE_INIT
156  // information is a fixed size with fixed information positions.
157  // see: packet-ecatmb.h and packet-ecatmb.c
158  // However, TwinCAT 2.1 testing also indicates that if a piece of
159  // information is missing then all subsequent items are ignored
160  // Also, if you want DHCP, then only set the mac address.
161  size_t size = 8 + // header + flags
162  ETH_ALEN + // mac address
163  4 + // ip address
164  4 + // subnet mask
165  4 + // gateway
166  4 + // dns server
167  EC_MAX_HOSTNAME_SIZE; // dns name
168 
169  data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
170  size);
171  if (IS_ERR(data)) {
172  return PTR_ERR(data);
173  }
174 
175  // zero data
176  memset(data, 0, size);
177 
178  // header
179  EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
180  EC_WRITE_U8(data + 1, 0x00); // not used
181  EC_WRITE_U16(data + 2, 0x0000); // not used
182 
183  EC_WRITE_U32(data + 4,
184  ((req->mac_address_included != 0) << 0) |
185  ((req->ip_address_included != 0) << 1) |
186  ((req->subnet_mask_included != 0) << 2) |
187  ((req->gateway_included != 0) << 3) |
188  ((req->dns_included != 0) << 4) |
189  ((req->name_included != 0) << 5)
190  );
191 
192  cur = data + 8;
193 
194  if (req->mac_address_included) {
195  memcpy(cur, req->mac_address, ETH_ALEN);
196  }
197  cur += ETH_ALEN;
198 
199  if (req->ip_address_included) {
200  uint32_t swapped = htonl(req->ip_address);
201  memcpy(cur, &swapped, 4);
202  }
203  cur += 4;
204 
205  if (req->subnet_mask_included) {
206  uint32_t swapped = htonl(req->subnet_mask);
207  memcpy(cur, &swapped, 4);
208  }
209  cur += 4;
210 
211  if (req->gateway_included) {
212  uint32_t swapped = htonl(req->gateway);
213  memcpy(cur, &swapped, 4);
214  }
215  cur += 4;
216 
217  if (req->dns_included) {
218  uint32_t swapped = htonl(req->dns);
219  memcpy(cur, &swapped, 4);
220  }
221  cur += 4;
222 
223  if (req->name_included) {
224  memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
225  }
226  cur += EC_MAX_HOSTNAME_SIZE;
227 
228  if (master->debug_level) {
229  EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
230  ec_print_data(data, cur - data);
231  }
232 
233  fsm->request->jiffies_sent = jiffies;
234 
235  return 0;
236 }
237 
238 /****************************************************************************/
239 
243  ec_fsm_eoe_t *fsm,
244  ec_datagram_t *datagram
245  )
246 {
247  ec_slave_t *slave = fsm->slave;
248 
249  EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
250 
251  if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
252  EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
253  fsm->state = ec_fsm_eoe_error;
254  return;
255  }
256 
257  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
258  fsm->state = ec_fsm_eoe_error;
259  return;
260  }
261 
262  fsm->retries = EC_FSM_RETRIES;
264 }
265 
266 /****************************************************************************/
267 
271  ec_fsm_eoe_t *fsm,
272  ec_datagram_t *datagram
273  )
274 {
275  ec_slave_t *slave = fsm->slave;
276 
277  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
278  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
279  fsm->state = ec_fsm_eoe_error;
280  }
281  return;
282  }
283 
284  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
285  fsm->state = ec_fsm_eoe_error;
286  EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
287  " request: ");
289  return;
290  }
291 
292  if (fsm->datagram->working_counter != 1) {
293  unsigned long diff_ms =
294  (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
295 
296  if (!fsm->datagram->working_counter) {
297  if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
298  // no response; send request datagram again
299  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
300  fsm->state = ec_fsm_eoe_error;
301  }
302  return;
303  }
304  }
305  fsm->state = ec_fsm_eoe_error;
306  EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
307  " failed after %lu ms: ", diff_ms);
309  return;
310  }
311 
312  fsm->jiffies_start = fsm->datagram->jiffies_sent;
313  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
314  fsm->retries = EC_FSM_RETRIES;
316 }
317 
318 /****************************************************************************/
319 
323  ec_fsm_eoe_t *fsm,
324  ec_datagram_t *datagram
325  )
326 {
327  ec_slave_t *slave = fsm->slave;
328 
329  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
330  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
331  return;
332  }
333 
334  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
335  fsm->state = ec_fsm_eoe_error;
336  EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
338  return;
339  }
340 
341  if (fsm->datagram->working_counter != 1) {
342  fsm->state = ec_fsm_eoe_error;
343  EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
344  " datagram failed: ");
346  return;
347  }
348 
349  if (!ec_slave_mbox_check(fsm->datagram)) {
350  unsigned long diff_ms =
351  (fsm->datagram->jiffies_received - fsm->jiffies_start) *
352  1000 / HZ;
353  if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
354  fsm->state = ec_fsm_eoe_error;
355  EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
356  " set IP parameter response.\n", diff_ms);
357  return;
358  }
359 
360  ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
361  fsm->retries = EC_FSM_RETRIES;
362  return;
363  }
364 
365  // fetch response
366  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
367  fsm->retries = EC_FSM_RETRIES;
369 }
370 
371 /****************************************************************************/
372 
376  ec_fsm_eoe_t *fsm,
377  ec_datagram_t *datagram
378  )
379 {
380  ec_slave_t *slave = fsm->slave;
381  ec_master_t *master = slave->master;
382  uint8_t *data, mbox_prot, frame_type;
383  size_t rec_size;
384  ec_eoe_request_t *req = fsm->request;
385 
386  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
387  ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
388  return;
389  }
390 
391  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
392  fsm->state = ec_fsm_eoe_error;
393  EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
395  return;
396  }
397 
398  if (fsm->datagram->working_counter != 1) {
399  fsm->state = ec_fsm_eoe_error;
400  EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
402  return;
403  }
404 
405  data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size);
406  if (IS_ERR(data)) {
407  fsm->state = ec_fsm_eoe_error;
408  return;
409  }
410 
411  if (master->debug_level) {
412  EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
413  ec_print_data(data, rec_size);
414  }
415 
416  if (mbox_prot != EC_MBOX_TYPE_EOE) {
417  fsm->state = ec_fsm_eoe_error;
418  EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
419  mbox_prot);
420  return;
421  }
422 
423  if (rec_size < 4) {
424  fsm->state = ec_fsm_eoe_error;
425  EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
426  " (%zu bytes)!\n", rec_size);
427  ec_print_data(data, rec_size);
428  return;
429  }
430 
431  frame_type = EC_READ_U8(data) & 0x0f;
432 
433  if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
434  EC_SLAVE_ERR(slave, "Received no set IP parameter response"
435  " (frame type %x).\n", frame_type);
436  ec_print_data(data, rec_size);
437  fsm->state = ec_fsm_eoe_error;
438  return;
439  }
440 
441  req->result = EC_READ_U16(data + 2);
442 
443  if (req->result) {
444  fsm->state = ec_fsm_eoe_error;
445  EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
446  " 0x%04X.\n", req->result);
447  } else {
448  fsm->state = ec_fsm_eoe_end; // success
449  }
450 }
451 
452 /****************************************************************************/
453 
457  ec_fsm_eoe_t *fsm,
458  ec_datagram_t *datagram
459  )
460 {
461 }
462 
463 /****************************************************************************/
464 
468  ec_fsm_eoe_t *fsm,
469  ec_datagram_t *datagram
470  )
471 {
472 }
473 
474 /****************************************************************************/
#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:97
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:96
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:2699
uint16_t working_counter
Working counter.
Definition: datagram.h:91
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:54
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:80
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:322
ec_datagram_state_t state
State.
Definition: datagram.h:92
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:2733
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:271
#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:242
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2716
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_eoe.c:132
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 ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_eoe.c:456
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:342
void ec_fsm_eoe_clear(ec_fsm_eoe_t *fsm)
Destructor.
Definition: fsm_eoe.c:70
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:2611
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *)
State: END.
Definition: fsm_eoe.c:467
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:375
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:2595
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 *fsm, ec_datagram_t *datagram)
Prepare a set IP parameters operation.
Definition: fsm_eoe.c:145
EtherCAT master.
Definition: master.h:183
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:100
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:270
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