IgH EtherCAT Master  1.5.2
fsm_change.c
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 2006-2008 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
35/*****************************************************************************/
36
37#include "globals.h"
38#include "master.h"
39#include "fsm_change.h"
40
41/*****************************************************************************/
42
45#define EC_AL_STATE_CHANGE_TIMEOUT 5
46
47/*****************************************************************************/
48
58
59/*****************************************************************************/
60
66 ec_datagram_t *datagram
67 )
68{
69 fsm->state = NULL;
70 fsm->datagram = datagram;
71 fsm->spontaneous_change = 0;
72}
73
74/*****************************************************************************/
75
81{
82}
83
84/*****************************************************************************/
85
91 ec_slave_t *slave,
92 ec_slave_state_t state
93 )
94{
96 fsm->slave = slave;
97 fsm->requested_state = state;
99}
100
101/*****************************************************************************/
102
108 ec_slave_t *slave
109 )
110{
112 fsm->slave = slave;
115}
116
117/*****************************************************************************/
118
125{
126 fsm->state(fsm);
127
128 return fsm->state != ec_fsm_change_state_end
130}
131
132/*****************************************************************************/
133
140{
141 return fsm->state == ec_fsm_change_state_end;
142}
143
144/******************************************************************************
145 * state change state machine
146 *****************************************************************************/
147
154{
155 ec_datagram_t *datagram = fsm->datagram;
156 ec_slave_t *slave = fsm->slave;
157
158 fsm->take_time = 1;
159 fsm->old_state = fsm->slave->current_state;
160
161 // write new state to slave
162 ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
163 EC_WRITE_U16(datagram->data, fsm->requested_state);
164 fsm->retries = EC_FSM_RETRIES;
166}
167
168/*****************************************************************************/
169
176{
177 ec_datagram_t *datagram = fsm->datagram;
178 ec_slave_t *slave = fsm->slave;
179
180 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
181 return;
182
183 if (datagram->state != EC_DATAGRAM_RECEIVED) {
185 EC_SLAVE_ERR(slave, "Failed to receive state datagram: ");
186 ec_datagram_print_state(datagram);
187 return;
188 }
189
190 if (fsm->take_time) {
191 fsm->take_time = 0;
192 fsm->jiffies_start = datagram->jiffies_sent;
193 }
194
195 if (datagram->working_counter == 0) {
196 if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
197 char state_str[EC_STATE_STRING_SIZE];
198 ec_state_string(fsm->requested_state, state_str, 0);
200 EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
202 return;
203 }
204
205 // repeat writing new state to slave
206 ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
207 EC_WRITE_U16(datagram->data, fsm->requested_state);
208 fsm->retries = EC_FSM_RETRIES;
209 return;
210 }
211
212 if (unlikely(datagram->working_counter > 1)) {
213 char state_str[EC_STATE_STRING_SIZE];
214 ec_state_string(fsm->requested_state, state_str, 0);
216 EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
218 return;
219 }
220
221 fsm->take_time = 1;
222
223 // read AL status from slave
224 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
225 ec_datagram_zero(datagram);
226 fsm->retries = EC_FSM_RETRIES;
227 fsm->spontaneous_change = 0;
229}
230
231/*****************************************************************************/
232
239{
240 ec_datagram_t *datagram = fsm->datagram;
241 ec_slave_t *slave = fsm->slave;
242
243 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
244 return;
245
246 if (datagram->state != EC_DATAGRAM_RECEIVED) {
248 EC_SLAVE_ERR(slave, "Failed to receive state checking datagram: ");
249 ec_datagram_print_state(datagram);
250 return;
251 }
252
253 if (datagram->working_counter != 1) {
254 char req_state[EC_STATE_STRING_SIZE];
255 ec_state_string(fsm->requested_state, req_state, 0);
257 EC_SLAVE_ERR(slave, "Failed to check state %s: ", req_state);
259 return;
260 }
261
262 if (fsm->take_time) {
263 fsm->take_time = 0;
264 fsm->jiffies_start = datagram->jiffies_sent;
265 }
266
267 slave->current_state = EC_READ_U8(datagram->data);
268
269 if (slave->current_state == fsm->requested_state) {
270 // state has been set successfully
272 return;
273 }
274
275 if (slave->current_state != fsm->old_state) { // state changed
276 char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
277
278 ec_state_string(slave->current_state, cur_state, 0);
279
280 if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
281 // Slave spontaneously changed its state just before the new state
282 // was written. Accept current state as old state and wait for
283 // state change
284 fsm->spontaneous_change = 1;
285 fsm->old_state = slave->current_state;
286 EC_SLAVE_WARN(slave, "Changed to %s in the meantime.\n",
287 cur_state);
288 goto check_again;
289 }
290
291 // state change error
292
293 slave->error_flag = 1;
294 ec_state_string(fsm->requested_state, req_state, 0);
295
296 EC_SLAVE_ERR(slave, "Failed to set %s state, slave refused state"
297 " change (%s).\n", req_state, cur_state);
298
300 return;
301 }
302
303 // still old state
304
305 if (datagram->jiffies_received - fsm->jiffies_start >=
307 // timeout while checking
308 char state_str[EC_STATE_STRING_SIZE];
309 ec_state_string(fsm->requested_state, state_str, 0);
311 EC_SLAVE_ERR(slave, "Timeout while setting state %s.\n", state_str);
312 return;
313 }
314
315 check_again:
316 // no timeout yet. check again
317 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
318 ec_datagram_zero(datagram);
319 fsm->retries = EC_FSM_RETRIES;
320}
321
322/*****************************************************************************/
323
327 ec_fsm_change_t *fsm
328 )
329{
330 ec_slave_t *slave = fsm->slave;
331 ec_datagram_t *datagram = fsm->datagram;
332
333 // fetch AL status error code
334 ec_datagram_fprd(datagram, slave->station_address, 0x0134, 2);
335 ec_datagram_zero(datagram);
336 fsm->retries = EC_FSM_RETRIES;
338}
339
340/*****************************************************************************/
341
347 {0x0000, "No error"},
348 {0x0001, "Unspecified error"},
349 {0x0002, "No Memory"},
350 {0x0011, "Invalid requested state change"},
351 {0x0012, "Unknown requested state"},
352 {0x0013, "Bootstrap not supported"},
353 {0x0014, "No valid firmware"},
354 {0x0015, "Invalid mailbox configuration"},
355 {0x0016, "Invalid mailbox configuration"},
356 {0x0017, "Invalid sync manager configuration"},
357 {0x0018, "No valid inputs available"},
358 {0x0019, "No valid outputs"},
359 {0x001A, "Synchronization error"},
360 {0x001B, "Sync manager watchdog"},
361 {0x001C, "Invalid sync manager types"},
362 {0x001D, "Invalid output configuration"},
363 {0x001E, "Invalid input configuration"},
364 {0x001F, "Invalid watchdog configuration"},
365 {0x0020, "Slave needs cold start"},
366 {0x0021, "Slave needs INIT"},
367 {0x0022, "Slave needs PREOP"},
368 {0x0023, "Slave needs SAFEOP"},
369 {0x0024, "Invalid Input Mapping"},
370 {0x0025, "Invalid Output Mapping"},
371 {0x0026, "Inconsistent Settings"},
372 {0x0027, "Freerun not supported"},
373 {0x0028, "Synchronization not supported"},
374 {0x0029, "Freerun needs 3 Buffer Mode"},
375 {0x002A, "Background Watchdog"},
376 {0x002B, "No Valid Inputs and Outputs"},
377 {0x002C, "Fatal Sync Error"},
378 {0x002D, "No Sync Error"},
379 {0x0030, "Invalid DC SYNCH configuration"},
380 {0x0031, "Invalid DC latch configuration"},
381 {0x0032, "PLL error"},
382 {0x0033, "DC Sync IO Error"},
383 {0x0034, "DC Sync Timeout Error"},
384 {0x0035, "DC Invalid Sync Cycle Time"},
385 {0x0036, "DC Sync0 Cycle Time"},
386 {0x0037, "DC Sync1 Cycle Time"},
387 {0x0041, "MBX_AOE"},
388 {0x0042, "MBX_EOE"},
389 {0x0043, "MBX_COE"},
390 {0x0044, "MBX_FOE"},
391 {0x0045, "MBX_SOE"},
392 {0x004F, "MBX_VOE"},
393 {0x0050, "EEPROM No Access"},
394 {0x0051, "EEPROM Error"},
395 {0x0060, "Slave Restarted Locally"},
396 {0xffff}
397};
398
399
400/*****************************************************************************/
401
408{
409 ec_datagram_t *datagram = fsm->datagram;
410 uint32_t code;
411 const ec_code_msg_t *al_msg;
412
413 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
414 return;
415
416 if (datagram->state != EC_DATAGRAM_RECEIVED) {
418 EC_SLAVE_ERR(fsm->slave, "Failed to receive"
419 " AL status code datagram: ");
420 ec_datagram_print_state(datagram);
421 return;
422 }
423
424 if (datagram->working_counter != 1) {
425 EC_SLAVE_WARN(fsm->slave, "Reception of AL status code"
426 " datagram failed: ");
428 } else {
429 code = EC_READ_U16(datagram->data);
430 for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
431 if (al_msg->code != code) {
432 continue;
433 }
434
435 EC_SLAVE_ERR(fsm->slave, "AL status message 0x%04X: \"%s\".\n",
436 al_msg->code, al_msg->message);
437 break;
438 }
439 if (al_msg->code == 0xffff) { /* not found in our list. */
440 EC_SLAVE_ERR(fsm->slave, "Unknown AL status code 0x%04X.\n",
441 code);
442 }
443 }
444
445 // acknowledge "old" slave state
446 ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0120, 2);
447 EC_WRITE_U16(datagram->data, fsm->slave->current_state);
448 fsm->retries = EC_FSM_RETRIES;
450}
451
452/*****************************************************************************/
453
459{
460 ec_datagram_t *datagram = fsm->datagram;
461 ec_slave_t *slave = fsm->slave;
462
463 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
464 return;
465
466 if (datagram->state != EC_DATAGRAM_RECEIVED) {
468 EC_SLAVE_ERR(slave, "Failed to receive state ack datagram: ");
469 ec_datagram_print_state(datagram);
470 return;
471 }
472
473 if (datagram->working_counter != 1) {
475 EC_SLAVE_ERR(slave, "Reception of state ack datagram failed: ");
477 return;
478 }
479
480 fsm->take_time = 1;
481
482 // read new AL status
483 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
484 ec_datagram_zero(datagram);
485 fsm->retries = EC_FSM_RETRIES;
487}
488
489/*****************************************************************************/
490
497{
498 ec_datagram_t *datagram = fsm->datagram;
499 ec_slave_t *slave = fsm->slave;
500
501 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
502 return;
503
504 if (datagram->state != EC_DATAGRAM_RECEIVED) {
506 EC_SLAVE_ERR(slave, "Failed to receive state ack check datagram: ");
507 ec_datagram_print_state(datagram);
508 return;
509 }
510
511 if (datagram->working_counter != 1) {
513 EC_SLAVE_ERR(slave, "Reception of state ack check datagram failed: ");
515 return;
516 }
517
518 if (fsm->take_time) {
519 fsm->take_time = 0;
520 fsm->jiffies_start = datagram->jiffies_sent;
521 }
522
523 slave->current_state = EC_READ_U8(datagram->data);
524
525 if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
526 char state_str[EC_STATE_STRING_SIZE];
527 ec_state_string(slave->current_state, state_str, 0);
528 if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
530 }
531 else { // EC_FSM_CHANGE_MODE_ACK_ONLY
533 }
534 EC_SLAVE_INFO(slave, "Acknowledged state %s.\n", state_str);
535 return;
536 }
537
538 if (datagram->jiffies_received - fsm->jiffies_start >=
540 // timeout while checking
541 char state_str[EC_STATE_STRING_SIZE];
542 ec_state_string(slave->current_state, state_str, 0);
544 EC_SLAVE_ERR(slave, "Timeout while acknowledging state %s.\n",
545 state_str);
546 return;
547 }
548
549 // reread new AL status
550 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
551 ec_datagram_zero(datagram);
552 fsm->retries = EC_FSM_RETRIES;
553}
554
555/*****************************************************************************/
556
563{
564}
565
566/*****************************************************************************/
567
574{
575}
576
577/*****************************************************************************/
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
int ec_datagram_fpwr(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPWR datagram.
Definition: datagram.c:298
int ec_datagram_fprd(ec_datagram_t *datagram, uint16_t configured_address, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT FPRD datagram.
Definition: datagram.c:273
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition: datagram.h:78
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition: datagram.h:79
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:139
void ec_fsm_change_state_ack(ec_fsm_change_t *)
Change state: ACK.
Definition: fsm_change.c:458
void ec_fsm_change_state_start(ec_fsm_change_t *)
Change state: START.
Definition: fsm_change.c:152
void ec_fsm_change_init(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_change.c:65
void ec_fsm_change_state_check(ec_fsm_change_t *)
Change state: CHECK.
Definition: fsm_change.c:174
void ec_fsm_change_state_code(ec_fsm_change_t *)
Change state: CODE.
Definition: fsm_change.c:406
void ec_fsm_change_state_check_ack(ec_fsm_change_t *)
Change state: CHECK ACK.
Definition: fsm_change.c:495
void ec_fsm_change_ack(ec_fsm_change_t *fsm, ec_slave_t *slave)
Starts the change state machine to only acknowlegde a slave's state.
Definition: fsm_change.c:107
const ec_code_msg_t al_status_messages[]
Application layer status messages.
Definition: fsm_change.c:346
void ec_fsm_change_start(ec_fsm_change_t *fsm, ec_slave_t *slave, ec_slave_state_t state)
Starts the change state machine.
Definition: fsm_change.c:90
void ec_fsm_change_clear(ec_fsm_change_t *fsm)
Destructor.
Definition: fsm_change.c:80
void ec_fsm_change_state_error(ec_fsm_change_t *)
State: ERROR.
Definition: fsm_change.c:561
void ec_fsm_change_state_status(ec_fsm_change_t *)
Change state: STATUS.
Definition: fsm_change.c:237
void ec_fsm_change_state_start_code(ec_fsm_change_t *)
Enter reading AL status code.
Definition: fsm_change.c:326
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:124
void ec_fsm_change_state_end(ec_fsm_change_t *)
State: END.
Definition: fsm_change.c:572
#define EC_AL_STATE_CHANGE_TIMEOUT
Timeout while waiting for AL state change [s].
Definition: fsm_change.c:45
EtherCAT state change FSM.
@ EC_FSM_CHANGE_MODE_FULL
full state change
Definition: fsm_change.h:51
@ EC_FSM_CHANGE_MODE_ACK_ONLY
only state acknowledgement
Definition: fsm_change.h:52
Global definitions and macros.
ec_slave_state_t
State of an EtherCAT slave.
Definition: globals.h:115
@ EC_SLAVE_STATE_UNKNOWN
unknown state
Definition: globals.h:116
@ EC_SLAVE_STATE_ACK_ERR
Acknowledge/Error bit (no actual state)
Definition: globals.h:128
#define EC_STATE_STRING_SIZE
Minimum size of a buffer used with ec_state_string().
Definition: globals.h:54
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
size_t ec_state_string(uint8_t, char *, uint8_t)
Prints slave states in clear text.
Definition: module.c:405
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2178
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2162
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2283
EtherCAT master structure.
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:62
Code/Message pair.
Definition: globals.h:266
uint32_t code
Code.
Definition: globals.h:267
const char * message
Message belonging to code.
Definition: globals.h:268
EtherCAT datagram.
Definition: datagram.h:87
uint16_t working_counter
Working counter.
Definition: datagram.h:99
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
ec_datagram_state_t state
State.
Definition: datagram.h:100
uint8_t * data
Datagram payload.
Definition: datagram.h:94
EtherCAT state change FSM.
Definition: fsm_change.h:65
unsigned int retries
retries upon datagram timeout
Definition: fsm_change.h:68
ec_slave_state_t old_state
prior slave state
Definition: fsm_change.h:73
ec_fsm_change_mode_t mode
full state change, or ack only.
Definition: fsm_change.h:71
ec_slave_state_t requested_state
input: state
Definition: fsm_change.h:72
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
uint8_t take_time
take sending timestamp
Definition: fsm_change.h:75
unsigned long jiffies_start
change timer
Definition: fsm_change.h:74
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_change.h:67
void(* state)(ec_fsm_change_t *)
slave state change state function
Definition: fsm_change.h:70
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_change.h:66
EtherCAT slave.
Definition: slave.h:177
ec_slave_state_t current_state
Current application state.
Definition: slave.h:192
uint16_t station_address
Configured station address.
Definition: slave.h:184
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:193