IgH EtherCAT Master  1.7.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 
42 // prototypes for private functions
43 void memcpy_swap32(void *, const void *);
44 
46 
50 
53 
54 /****************************************************************************/
55 
64 void memcpy_swap32(void *dst, const void *src)
65 {
66  int i;
67  for (i = 0; i < 4; i++) {
68  ((u8 *) dst)[i] = ((const u8 *) src)[3 - i];
69  }
70 }
71 
72 /****************************************************************************/
73 
77  ec_fsm_eoe_t *fsm
78  )
79 {
80  fsm->slave = NULL;
81  fsm->retries = 0;
82  fsm->state = NULL;
83  fsm->datagram = NULL;
84  fsm->jiffies_start = 0;
85  fsm->request = NULL;
86  fsm->frame_type_retries = 0;
88 }
89 
90 /****************************************************************************/
91 
95  ec_fsm_eoe_t *fsm
96  )
97 {
99 }
100 
101 /****************************************************************************/
102 
106  ec_fsm_eoe_t *fsm,
107  ec_slave_t *slave,
108  ec_eoe_request_t *request
109  )
110 {
111  fsm->slave = slave;
112  fsm->request = request;
114 }
115 
116 /****************************************************************************/
117 
123  ec_fsm_eoe_t *fsm,
124  ec_datagram_t *datagram
125  )
126 {
127  if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error)
128  return 0;
129 
130  if (fsm->datagram &&
131  (fsm->datagram->state == EC_DATAGRAM_INIT ||
132  fsm->datagram->state == EC_DATAGRAM_QUEUED ||
133  fsm->datagram->state == EC_DATAGRAM_SENT)) {
134  // datagram not received yet
135  if (datagram != fsm->datagram)
136  datagram->state = EC_DATAGRAM_UNUSED;
137  return 1;
138  }
139 
140  fsm->state(fsm, datagram);
141 
142  if (fsm->state == ec_fsm_eoe_end || fsm->state == ec_fsm_eoe_error) {
143  fsm->datagram = NULL;
144  return 0;
145  }
146 
147  fsm->datagram = datagram;
148  return 1;
149 }
150 
151 /****************************************************************************/
152 
158 {
159  return fsm->state == ec_fsm_eoe_end;
160 }
161 
162 /****************************************************************************/
163 
169 static void ec_fsm_eoe_receive(
170  ec_fsm_eoe_t *fsm,
171  ec_datagram_t *datagram
172  )
173 {
174  ec_fsm_mbox_receive(&fsm->fsm_mbox, fsm->slave,
175  &fsm->slave->mbox_eoe_data, fsm->jiffies_start,
178  fsm->state(fsm, datagram);
179 }
180 
181 /*****************************************************************************
182  * EoE set IP parameter state machine
183  ****************************************************************************/
184 
190  ec_fsm_eoe_t *fsm,
191  ec_datagram_t *datagram
192  )
193 {
194  uint8_t *data, *cur;
195  ec_slave_t *slave = fsm->slave;
196  ec_master_t *master = slave->master;
197  ec_eoe_request_t *req = fsm->request;
198 
199  // Note: based on wireshark packet filter it suggests that the EOE_INIT
200  // information is a fixed size with fixed information positions.
201  // see: packet-ecatmb.h and packet-ecatmb.c
202  // However, TwinCAT 2.1 testing also indicates that if a piece of
203  // information is missing then all subsequent items are ignored
204  // Also, if you want DHCP, then only set the mac address.
205  size_t size = 8 + // header + flags
206  ETH_ALEN + // mac address
207  4 + // ip address
208  4 + // subnet mask
209  4 + // gateway
210  4 + // dns server
211  EC_MAX_HOSTNAME_SIZE; // dns name
212 
213  data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
214  size);
215  if (IS_ERR(data)) {
216  return PTR_ERR(data);
217  }
218 
219  // zero data
220  memset(data, 0, size);
221 
222  // header
223  EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
224  EC_WRITE_U8(data + 1, 0x00); // not used
225  EC_WRITE_U16(data + 2, 0x0000); // not used
226 
227  EC_WRITE_U32(data + 4,
228  ((req->mac_address_included != 0) << 0) |
229  ((req->ip_address_included != 0) << 1) |
230  ((req->subnet_mask_included != 0) << 2) |
231  ((req->gateway_included != 0) << 3) |
232  ((req->dns_included != 0) << 4) |
233  ((req->name_included != 0) << 5)
234  );
235 
236  cur = data + 8;
237 
238  if (req->mac_address_included) {
239  memcpy(cur, req->mac_address, ETH_ALEN);
240  }
241  cur += ETH_ALEN;
242 
243  if (req->ip_address_included) {
244  memcpy_swap32(cur, &req->ip_address);
245  }
246  cur += 4;
247 
248  if (req->subnet_mask_included) {
249  memcpy_swap32(cur, &req->subnet_mask);
250  }
251  cur += 4;
252 
253  if (req->gateway_included) {
254  memcpy_swap32(cur, &req->gateway);
255  }
256  cur += 4;
257 
258  if (req->dns_included) {
259  memcpy_swap32(cur, &req->dns);
260  }
261  cur += 4;
262 
263  if (req->name_included) {
264  memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
265  }
266  cur += EC_MAX_HOSTNAME_SIZE;
267 
268  if (master->debug_level) {
269  EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
270  ec_print_data(data, cur - data);
271  }
272 
273  fsm->request->jiffies_sent = jiffies;
274 
275  return 0;
276 }
277 
278 /****************************************************************************/
279 
283  ec_fsm_eoe_t *fsm,
284  ec_datagram_t *datagram
285  )
286 {
287  ec_slave_t *slave = fsm->slave;
288 
289  EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
290 
291  if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
292  EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
293  fsm->state = ec_fsm_eoe_error;
294  return;
295  }
296 
297  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
298  fsm->state = ec_fsm_eoe_error;
299  return;
300  }
301 
302  fsm->retries = EC_FSM_RETRIES;
304 }
305 
306 /****************************************************************************/
307 
311  ec_fsm_eoe_t *fsm,
312  ec_datagram_t *datagram
313  )
314 {
315  ec_slave_t *slave = fsm->slave;
316 
317  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
318  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
319  fsm->state = ec_fsm_eoe_error;
320  }
321  return;
322  }
323 
324  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
325  fsm->state = ec_fsm_eoe_error;
326  EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
327  " request: ");
329  return;
330  }
331 
332  if (fsm->datagram->working_counter != 1) {
333  unsigned long diff_ms =
334  (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
335 
336  if (!fsm->datagram->working_counter) {
337  if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
338  // no response; send request datagram again
339  if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
340  fsm->state = ec_fsm_eoe_error;
341  }
342  return;
343  }
344  }
345  fsm->state = ec_fsm_eoe_error;
346  EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
347  " failed after %lu ms: ", diff_ms);
349  return;
350  }
351 
352  fsm->jiffies_start = fsm->datagram->jiffies_sent;
353  fsm->frame_type_retries = 10;
354 
355  ec_fsm_eoe_receive(fsm, datagram);
356 }
357 
358 /****************************************************************************/
359 
363  ec_fsm_eoe_t *fsm,
364  ec_datagram_t *datagram
365  )
366 {
367  ec_slave_t *slave = fsm->slave;
368  ec_master_t *master = slave->master;
369  uint8_t *data, mbox_prot, frame_type;
370  size_t rec_size;
371  ec_eoe_request_t *req = fsm->request;
372 
373  if (ec_fsm_mbox_exec(&fsm->fsm_mbox, datagram)) {
374  return;
375  }
376 
377  if (ec_fsm_mbox_result(&fsm->fsm_mbox)) {
378  fsm->state = ec_fsm_eoe_error;
379  if (ec_fsm_mbox_result(&fsm->fsm_mbox) == -ETIMEDOUT) {
380  EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
381  " set IP parameter response.\n",
382  (jiffies - fsm->jiffies_start) * 1000 / HZ);
383  }
384  return;
385  }
386 
387  data = ec_slave_mbox_fetch(slave, &slave->mbox_eoe_data,
388  &mbox_prot, &rec_size);
389  if (IS_ERR(data)) {
390  fsm->state = ec_fsm_eoe_error;
391  return;
392  }
393 
394  if (master->debug_level) {
395  EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
396  ec_print_data(data, rec_size);
397  }
398 
399  if (mbox_prot != EC_MBOX_TYPE_EOE) {
400  fsm->state = ec_fsm_eoe_error;
401  EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
402  mbox_prot);
403  return;
404  }
405 
406  if (rec_size < 4) {
407  fsm->state = ec_fsm_eoe_error;
408  EC_SLAVE_ERR(slave, "Received corrupted EoE set IP parameter response"
409  " (%zu bytes)!\n", rec_size);
410  ec_print_data(data, rec_size);
411  return;
412  }
413 
414  frame_type = EC_READ_U8(data) & 0x0f;
415 
416  if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
417  if (master->debug_level) {
418  EC_SLAVE_DBG(slave, 0, "Received no set IP parameter response"
419  " (frame type %x).\n", frame_type);
420  ec_print_data(data, rec_size);
421  }
422  if (fsm->frame_type_retries--) {
423  // there may be an EoE segment left in the mailbox.
424  // discard it and receive again.
425  fsm->jiffies_start = jiffies;
426  ec_fsm_eoe_receive(fsm, datagram);
427  return;
428  }
429  else {
430  EC_SLAVE_ERR(slave, "Received no set IP parameter response.\n");
431  fsm->state = ec_fsm_eoe_error;
432  return;
433  }
434  }
435 
436  req->result = EC_READ_U16(data + 2); // result code 0x0000 means success
437 
438  if (req->result) {
439  fsm->state = ec_fsm_eoe_error;
440  EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
441  " 0x%04X.\n", req->result);
442  } else {
443  fsm->state = ec_fsm_eoe_end; // success
444  }
445 }
446 
447 /****************************************************************************/
448 
452  ec_fsm_eoe_t *fsm,
453  ec_datagram_t *datagram
454  )
455 {
456 }
457 
458 /****************************************************************************/
459 
463  ec_fsm_eoe_t *fsm,
464  ec_datagram_t *datagram
465  )
466 {
467 }
468 
469 /****************************************************************************/
#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:122
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
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:101
ec_fsm_mbox_t fsm_mbox
Mailbox receive state machine.
Definition: fsm_eoe.h:51
ec_sii_t sii
Extracted SII data.
Definition: slave.h:218
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:100
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_eoe.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
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
Not used by its state machine in this cycle and not to be queued.
Definition: datagram.h:73
EtherCAT datagram.
Definition: datagram.h:81
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3353
ec_mbox_data_t mbox_eoe_data
Received mailbox data for EoE.
Definition: slave.h:236
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
ec_eoe_request_t * request
EoE request.
Definition: fsm_eoe.h:52
void ec_fsm_eoe_init(ec_fsm_eoe_t *fsm)
Constructor.
Definition: fsm_eoe.c:76
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:116
Set IP Parameter Request.
Definition: ethernet.h:47
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:105
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:50
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
Initiate EoE Request.
Definition: ethernet.h:46
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3387
Ethernet over EtherCAT.
Definition: globals.h:151
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition: slave.h:141
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
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP START.
Definition: fsm_eoe.c:282
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3370
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_eoe.c:157
static void ec_fsm_eoe_receive(ec_fsm_eoe_t *fsm, ec_datagram_t *datagram)
Waits for the set IP parameter response.
Definition: fsm_eoe.c:169
ec_master_t * master
Master owning the slave.
Definition: slave.h:172
void(* state)(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state function.
Definition: fsm_eoe.h:48
void memcpy_swap32(void *, const void *)
Host-architecture-independent 32-bit swap function.
Definition: fsm_eoe.c:64
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_eoe.c:451
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:348
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:53
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3261
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *)
State: END.
Definition: fsm_eoe.c:462
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
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:362
Queued for sending.
Definition: datagram.h:68
Timed out (dequeued).
Definition: datagram.h:71
void ec_fsm_mbox_init(ec_fsm_mbox_t *fsm)
Constructor.
Definition: fsm_mbox.c:45
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3245
unsigned int retries
retries upon datagram timeout
Definition: fsm_eoe.h:46
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:189
EtherCAT master.
Definition: master.h:194
void ec_fsm_mbox_clear(ec_fsm_mbox_t *fsm)
Destructor.
Definition: fsm_mbox.c:64
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP REQUEST.
Definition: fsm_eoe.c:310
Finite state machines for the Ethernet over EtherCAT protocol.
Definition: fsm_eoe.h:44
ec_datagram_t * datagram
Datagram used in the previous step.
Definition: fsm_eoe.h:49