IgH EtherCAT Master  1.6.9
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
26
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
43void memcpy_swap32(void *, const void *);
44
46
51
54
55/****************************************************************************/
56
65void 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 ||
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 }
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
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 =
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.
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/****************************************************************************/
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_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition datagram.c:557
@ EC_DATAGRAM_INIT
Initial state of a new datagram.
Definition datagram.h:67
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
@ EC_DATAGRAM_SENT
Sent (still in the queue).
Definition datagram.h:69
@ EC_DATAGRAM_QUEUED
Queued for sending.
Definition datagram.h:68
@ EC_EOE_FRAMETYPE_SET_IP_RES
Set IP Parameter Request.
Definition ethernet.h:46
@ EC_EOE_FRAMETYPE_SET_IP_REQ
Initiate EoE Request.
Definition ethernet.h:45
int ec_fsm_eoe_prepare_set(ec_fsm_eoe_t *, ec_datagram_t *)
Prepare a set IP parameters operation.
Definition fsm_eoe.c:169
void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP REQUEST.
Definition fsm_eoe.c:290
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
void memcpy_swap32(void *, const void *)
Host-architecture-independent 32-bit swap function.
Definition fsm_eoe.c:65
void ec_fsm_eoe_clear(ec_fsm_eoe_t *fsm)
Destructor.
Definition fsm_eoe.c:94
#define EC_EOE_RESPONSE_TIMEOUT
Maximum time to wait for a set IP parameter response.
Definition fsm_eoe.c:38
void ec_fsm_eoe_init(ec_fsm_eoe_t *fsm)
Constructor.
Definition fsm_eoe.c:77
void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP RESPONSE.
Definition fsm_eoe.c:396
void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP CHECK.
Definition fsm_eoe.c:343
void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *)
State: ERROR.
Definition fsm_eoe.c:491
void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *)
State: END.
Definition fsm_eoe.c:502
int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_eoe.c:156
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
void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state: SET IP START.
Definition fsm_eoe.c:262
EtherCAT EoE set IP parameter state machines.
struct ec_fsm_eoe ec_fsm_eoe_t
Definition fsm_eoe.h:39
Global definitions and macros.
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition globals.h:47
@ EC_MBOX_EOE
Ethernet over EtherCAT.
Definition globals.h:145
struct ec_slave ec_slave_t
Definition globals.h:310
#define EC_MAX_HOSTNAME_SIZE
Maximum hostname size.
Definition globals.h:110
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition module.c:344
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition ecrt.h:3040
struct ec_master ec_master_t
Definition ecrt.h:300
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition ecrt.h:3074
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition ecrt.h:2948
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition ecrt.h:2932
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition ecrt.h:3057
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
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
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
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
int ec_slave_mbox_check(const ec_datagram_t *datagram)
Processes a mailbox state checking datagram.
Definition mailbox.c:107
Mailbox functionality.
EtherCAT master structure.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition slave.h:98
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition slave.h:68
EtherCAT datagram.
Definition datagram.h:79
uint16_t working_counter
Working counter.
Definition datagram.h:93
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition datagram.h:102
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition datagram.h:98
ec_datagram_state_t state
State.
Definition datagram.h:94
Ethernet-over-EtherCAT set IP parameter request.
Definition eoe_request.h:41
unsigned long jiffies_sent
Jiffies, when the request was sent.
Definition eoe_request.h:44
unsigned int retries
retries upon datagram timeout
Definition fsm_eoe.h:45
unsigned long jiffies_start
Timestamp.
Definition fsm_eoe.h:49
void(* state)(ec_fsm_eoe_t *, ec_datagram_t *)
EoE state function.
Definition fsm_eoe.h:47
ec_datagram_t * datagram
Datagram used in the previous step.
Definition fsm_eoe.h:48
ec_eoe_request_t * request
EoE request.
Definition fsm_eoe.h:50
unsigned int frame_type_retries
retries upon wrong frame type.
Definition fsm_eoe.h:51
ec_slave_t * slave
slave the FSM runs on
Definition fsm_eoe.h:44
unsigned int debug_level
Master debug level.
Definition master.h:275
uint16_t mailbox_protocols
Supported mailbox protocols.
Definition slave.h:139
ec_sii_t sii
Extracted SII data.
Definition slave.h:215
ec_master_t * master
Master owning the slave.
Definition slave.h:170