|
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 |
|
30 /** |
|
31 \file |
|
32 EtherCAT EoE state machines. |
|
33 */ |
|
34 |
|
35 /*****************************************************************************/ |
|
36 |
|
37 #include "globals.h" |
|
38 #include "master.h" |
|
39 #include "mailbox.h" |
|
40 #include "fsm_eoe.h" |
|
41 |
|
42 /*****************************************************************************/ |
|
43 |
|
44 /** Maximum time to wait for a set IP parameter response. |
|
45 */ |
|
46 #define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms] |
|
47 |
|
48 /*****************************************************************************/ |
|
49 |
|
50 void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *); |
|
51 void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *); |
|
52 void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *); |
|
53 void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *); |
|
54 |
|
55 void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *); |
|
56 void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *); |
|
57 |
|
58 /*****************************************************************************/ |
|
59 |
|
60 /** Constructor. |
|
61 */ |
|
62 void ec_fsm_eoe_init( |
|
63 ec_fsm_eoe_t *fsm /**< finite state machine */ |
|
64 ) |
|
65 { |
|
66 fsm->slave = NULL; |
|
67 fsm->retries = 0; |
|
68 fsm->state = NULL; |
|
69 fsm->datagram = NULL; |
|
70 fsm->jiffies_start = 0; |
|
71 fsm->request = NULL; |
|
72 } |
|
73 |
|
74 /*****************************************************************************/ |
|
75 |
|
76 /** Destructor. |
|
77 */ |
|
78 void ec_fsm_eoe_clear( |
|
79 ec_fsm_eoe_t *fsm /**< finite state machine */ |
|
80 ) |
|
81 { |
|
82 } |
|
83 |
|
84 /*****************************************************************************/ |
|
85 |
|
86 /** Starts to set the EoE IP partameters of a slave. |
|
87 */ |
|
88 void ec_fsm_eoe_set_ip_param( |
|
89 ec_fsm_eoe_t *fsm, /**< State machine. */ |
|
90 ec_slave_t *slave, /**< EtherCAT slave. */ |
|
91 ec_eoe_request_t *request /**< EoE request. */ |
|
92 ) |
|
93 { |
|
94 fsm->slave = slave; |
|
95 fsm->request = request; |
|
96 fsm->state = ec_fsm_eoe_set_ip_start; |
|
97 } |
|
98 |
|
99 /*****************************************************************************/ |
|
100 |
|
101 /** Executes the current state of the state machine. |
|
102 * |
|
103 * \return 1 if the datagram was used, else 0. |
|
104 */ |
|
105 int ec_fsm_eoe_exec( |
|
106 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
107 ec_datagram_t *datagram /**< Datagram to use. */ |
|
108 ) |
|
109 { |
|
110 int datagram_used = 0; |
|
111 |
|
112 if (fsm->datagram && |
|
113 (fsm->datagram->state == EC_DATAGRAM_INIT || |
|
114 fsm->datagram->state == EC_DATAGRAM_QUEUED || |
|
115 fsm->datagram->state == EC_DATAGRAM_SENT)) { |
|
116 // datagram not received yet |
|
117 return datagram_used; |
|
118 } |
|
119 |
|
120 fsm->state(fsm, datagram); |
|
121 |
|
122 datagram_used = |
|
123 fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error; |
|
124 |
|
125 if (datagram_used) { |
|
126 fsm->datagram = datagram; |
|
127 } else { |
|
128 fsm->datagram = NULL; |
|
129 } |
|
130 |
|
131 return datagram_used; |
|
132 } |
|
133 |
|
134 /*****************************************************************************/ |
|
135 |
|
136 /** Returns, if the state machine terminated with success. |
|
137 * |
|
138 * \return non-zero if successful. |
|
139 */ |
|
140 int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */) |
|
141 { |
|
142 return fsm->state == ec_fsm_eoe_end; |
|
143 } |
|
144 |
|
145 /****************************************************************************** |
|
146 * EoE set IP parameter state machine |
|
147 *****************************************************************************/ |
|
148 |
|
149 /** Prepare a set IP parameters operation. |
|
150 * |
|
151 * \return 0 on success, otherwise a negative error code. |
|
152 */ |
|
153 int ec_fsm_eoe_prepare_set( |
|
154 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
155 ec_datagram_t *datagram /**< Datagram to use. */ |
|
156 ) |
|
157 { |
|
158 uint8_t *data, *cur; |
|
159 ec_slave_t *slave = fsm->slave; |
|
160 ec_master_t *master = slave->master; |
|
161 ec_eoe_request_t *req = fsm->request; |
|
162 size_t size = 8; |
|
163 |
|
164 if (req->mac_address_included) { |
|
165 size += ETH_ALEN; |
|
166 } |
|
167 |
|
168 if (req->ip_address_included) { |
|
169 size += 4; |
|
170 } |
|
171 |
|
172 if (req->subnet_mask_included) { |
|
173 size += 4; |
|
174 } |
|
175 |
|
176 if (req->gateway_included) { |
|
177 size += 4; |
|
178 } |
|
179 |
|
180 if (req->dns_included) { |
|
181 size += 4; |
|
182 } |
|
183 |
|
184 if (req->name_included) { |
|
185 size += EC_MAX_HOSTNAME_SIZE; |
|
186 } |
|
187 |
|
188 data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE, |
|
189 size); |
|
190 if (IS_ERR(data)) { |
|
191 return PTR_ERR(data); |
|
192 } |
|
193 |
|
194 EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req. |
|
195 EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps |
|
196 EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no. |
|
197 |
|
198 EC_WRITE_U32(data + 4, |
|
199 ((req->mac_address_included != 0) << 0) | |
|
200 ((req->ip_address_included != 0) << 1) | |
|
201 ((req->subnet_mask_included != 0) << 2) | |
|
202 ((req->gateway_included != 0) << 3) | |
|
203 ((req->dns_included != 0) << 4) | |
|
204 ((req->name_included != 0) << 5) |
|
205 ); |
|
206 |
|
207 cur = data + 8; |
|
208 |
|
209 if (req->mac_address_included) { |
|
210 memcpy(cur, req->mac_address, ETH_ALEN); |
|
211 cur += ETH_ALEN; |
|
212 } |
|
213 |
|
214 if (req->ip_address_included) { |
|
215 memcpy(cur, &req->ip_address, 4); |
|
216 cur += 4; |
|
217 } |
|
218 |
|
219 if (req->subnet_mask_included) { |
|
220 memcpy(cur, &req->subnet_mask, 4); |
|
221 cur += 4; |
|
222 } |
|
223 |
|
224 if (req->gateway_included) { |
|
225 memcpy(cur, &req->gateway, 4); |
|
226 cur += 4; |
|
227 } |
|
228 |
|
229 if (req->dns_included) { |
|
230 memcpy(cur, &req->dns, 4); |
|
231 cur += 4; |
|
232 } |
|
233 |
|
234 if (req->name_included) { |
|
235 memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE); |
|
236 cur += EC_MAX_HOSTNAME_SIZE; |
|
237 } |
|
238 |
|
239 if (master->debug_level) { |
|
240 EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n"); |
|
241 ec_print_data(data, cur - data); |
|
242 } |
|
243 |
|
244 fsm->request->jiffies_sent = jiffies; |
|
245 |
|
246 return 0; |
|
247 } |
|
248 |
|
249 /*****************************************************************************/ |
|
250 |
|
251 /** EoE state: SET IP START. |
|
252 */ |
|
253 void ec_fsm_eoe_set_ip_start( |
|
254 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
255 ec_datagram_t *datagram /**< Datagram to use. */ |
|
256 ) |
|
257 { |
|
258 ec_slave_t *slave = fsm->slave; |
|
259 |
|
260 EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n"); |
|
261 |
|
262 if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) { |
|
263 EC_SLAVE_ERR(slave, "Slave does not support EoE!\n"); |
|
264 fsm->state = ec_fsm_eoe_error; |
|
265 return; |
|
266 } |
|
267 |
|
268 if (ec_fsm_eoe_prepare_set(fsm, datagram)) { |
|
269 fsm->state = ec_fsm_eoe_error; |
|
270 return; |
|
271 } |
|
272 |
|
273 fsm->retries = EC_FSM_RETRIES; |
|
274 fsm->state = ec_fsm_eoe_set_ip_request; |
|
275 } |
|
276 |
|
277 /*****************************************************************************/ |
|
278 |
|
279 /** EoE state: SET IP REQUEST. |
|
280 */ |
|
281 void ec_fsm_eoe_set_ip_request( |
|
282 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
283 ec_datagram_t *datagram /**< Datagram to use. */ |
|
284 ) |
|
285 { |
|
286 ec_slave_t *slave = fsm->slave; |
|
287 |
|
288 if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { |
|
289 if (ec_fsm_eoe_prepare_set(fsm, datagram)) { |
|
290 fsm->state = ec_fsm_eoe_error; |
|
291 } |
|
292 return; |
|
293 } |
|
294 |
|
295 if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { |
|
296 fsm->state = ec_fsm_eoe_error; |
|
297 EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter" |
|
298 " request: "); |
|
299 ec_datagram_print_state(fsm->datagram); |
|
300 return; |
|
301 } |
|
302 |
|
303 if (fsm->datagram->working_counter != 1) { |
|
304 unsigned long diff_ms = |
|
305 (jiffies - fsm->request->jiffies_sent) * 1000 / HZ; |
|
306 |
|
307 if (!fsm->datagram->working_counter) { |
|
308 if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) { |
|
309 // no response; send request datagram again |
|
310 if (ec_fsm_eoe_prepare_set(fsm, datagram)) { |
|
311 fsm->state = ec_fsm_eoe_error; |
|
312 } |
|
313 return; |
|
314 } |
|
315 } |
|
316 fsm->state = ec_fsm_eoe_error; |
|
317 EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request" |
|
318 " failed after %lu ms: ", diff_ms); |
|
319 ec_datagram_print_wc_error(fsm->datagram); |
|
320 return; |
|
321 } |
|
322 |
|
323 fsm->jiffies_start = fsm->datagram->jiffies_sent; |
|
324 ec_slave_mbox_prepare_check(slave, datagram); // can not fail. |
|
325 fsm->retries = EC_FSM_RETRIES; |
|
326 fsm->state = ec_fsm_eoe_set_ip_check; |
|
327 } |
|
328 |
|
329 /*****************************************************************************/ |
|
330 |
|
331 /** EoE state: SET IP CHECK. |
|
332 */ |
|
333 void ec_fsm_eoe_set_ip_check( |
|
334 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
335 ec_datagram_t *datagram /**< Datagram to use. */ |
|
336 ) |
|
337 { |
|
338 ec_slave_t *slave = fsm->slave; |
|
339 |
|
340 if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { |
|
341 ec_slave_mbox_prepare_check(slave, datagram); // can not fail. |
|
342 return; |
|
343 } |
|
344 |
|
345 if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { |
|
346 fsm->state = ec_fsm_eoe_error; |
|
347 EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: "); |
|
348 ec_datagram_print_state(fsm->datagram); |
|
349 return; |
|
350 } |
|
351 |
|
352 if (fsm->datagram->working_counter != 1) { |
|
353 fsm->state = ec_fsm_eoe_error; |
|
354 EC_SLAVE_ERR(slave, "Reception of EoE mailbox check" |
|
355 " datagram failed: "); |
|
356 ec_datagram_print_wc_error(fsm->datagram); |
|
357 return; |
|
358 } |
|
359 |
|
360 if (!ec_slave_mbox_check(fsm->datagram)) { |
|
361 unsigned long diff_ms = |
|
362 (fsm->datagram->jiffies_received - fsm->jiffies_start) * |
|
363 1000 / HZ; |
|
364 if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) { |
|
365 fsm->state = ec_fsm_eoe_error; |
|
366 EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for" |
|
367 " set IP parameter response.\n", diff_ms); |
|
368 return; |
|
369 } |
|
370 |
|
371 ec_slave_mbox_prepare_check(slave, datagram); // can not fail. |
|
372 fsm->retries = EC_FSM_RETRIES; |
|
373 return; |
|
374 } |
|
375 |
|
376 // fetch response |
|
377 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. |
|
378 fsm->retries = EC_FSM_RETRIES; |
|
379 fsm->state = ec_fsm_eoe_set_ip_response; |
|
380 } |
|
381 |
|
382 /*****************************************************************************/ |
|
383 |
|
384 /** EoE state: SET IP RESPONSE. |
|
385 */ |
|
386 void ec_fsm_eoe_set_ip_response( |
|
387 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
388 ec_datagram_t *datagram /**< Datagram to use. */ |
|
389 ) |
|
390 { |
|
391 ec_slave_t *slave = fsm->slave; |
|
392 ec_master_t *master = slave->master; |
|
393 uint8_t *data, mbox_prot, frame_type; |
|
394 size_t rec_size; |
|
395 ec_eoe_request_t *req = fsm->request; |
|
396 |
|
397 if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) { |
|
398 ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. |
|
399 return; |
|
400 } |
|
401 |
|
402 if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) { |
|
403 fsm->state = ec_fsm_eoe_error; |
|
404 EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: "); |
|
405 ec_datagram_print_state(fsm->datagram); |
|
406 return; |
|
407 } |
|
408 |
|
409 if (fsm->datagram->working_counter != 1) { |
|
410 fsm->state = ec_fsm_eoe_error; |
|
411 EC_SLAVE_ERR(slave, "Reception of EoE read response failed: "); |
|
412 ec_datagram_print_wc_error(fsm->datagram); |
|
413 return; |
|
414 } |
|
415 |
|
416 data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size); |
|
417 if (IS_ERR(data)) { |
|
418 fsm->state = ec_fsm_eoe_error; |
|
419 return; |
|
420 } |
|
421 |
|
422 if (master->debug_level) { |
|
423 EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n"); |
|
424 ec_print_data(data, rec_size); |
|
425 } |
|
426 |
|
427 if (mbox_prot != EC_MBOX_TYPE_EOE) { |
|
428 fsm->state = ec_fsm_eoe_error; |
|
429 EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n", |
|
430 mbox_prot); |
|
431 return; |
|
432 } |
|
433 |
|
434 if (rec_size < 4) { |
|
435 fsm->state = ec_fsm_eoe_error; |
|
436 EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response" |
|
437 " (%zu bytes)!\n", rec_size); |
|
438 ec_print_data(data, rec_size); |
|
439 return; |
|
440 } |
|
441 |
|
442 frame_type = EC_READ_U8(data) & 0x0f; |
|
443 |
|
444 if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) { |
|
445 EC_SLAVE_ERR(slave, "Received no set IP parameter response" |
|
446 " (frame type %x).\n", frame_type); |
|
447 ec_print_data(data, rec_size); |
|
448 fsm->state = ec_fsm_eoe_error; |
|
449 return; |
|
450 } |
|
451 |
|
452 req->result = EC_READ_U16(data + 2); |
|
453 |
|
454 if (req->result) { |
|
455 fsm->state = ec_fsm_eoe_error; |
|
456 EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code" |
|
457 " 0x%04X.\n", req->result); |
|
458 } else { |
|
459 fsm->state = ec_fsm_eoe_end; // success |
|
460 } |
|
461 } |
|
462 |
|
463 /*****************************************************************************/ |
|
464 |
|
465 /** State: ERROR. |
|
466 */ |
|
467 void ec_fsm_eoe_error( |
|
468 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
469 ec_datagram_t *datagram /**< Datagram to use. */ |
|
470 ) |
|
471 { |
|
472 } |
|
473 |
|
474 /*****************************************************************************/ |
|
475 |
|
476 /** State: END. |
|
477 */ |
|
478 void ec_fsm_eoe_end( |
|
479 ec_fsm_eoe_t *fsm, /**< finite state machine */ |
|
480 ec_datagram_t *datagram /**< Datagram to use. */ |
|
481 ) |
|
482 { |
|
483 } |
|
484 |
|
485 /*****************************************************************************/ |