IgH EtherCAT Master  1.6.9
fsm_change.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 2006-2008 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 "fsm_change.h"
32#include "slave_config.h"
33
34/****************************************************************************/
35
36unsigned int ec_fsm_change_timeout_ms(const ec_fsm_change_t *);
37
47
48/****************************************************************************/
49
53
55 ec_datagram_t *datagram
56 )
57{
58 fsm->state = NULL;
59 fsm->datagram = datagram;
60 fsm->spontaneous_change = 0;
61}
62
63/****************************************************************************/
64
68
72
73/****************************************************************************/
74
80 const ec_fsm_change_t *fsm
81 )
82{
83 ec_slave_state_t from = fsm->old_state;
85
86 /* Search for specified timeout in slave configuration */
87 if (fsm->slave->config) {
88 unsigned int timeout_ms =
90 if (timeout_ms) {
91 return timeout_ms;
92 }
93 }
94
95 /* No specific timeout found. Use defaults from spec. */
96
97 if (from == EC_SLAVE_STATE_INIT &&
99 return 3000; // PreopTimeout
100 }
101 if ((from == EC_SLAVE_STATE_PREOP && to == EC_SLAVE_STATE_SAFEOP) ||
102 (from == EC_SLAVE_STATE_SAFEOP && to == EC_SLAVE_STATE_OP)) {
103 return 10000; // SafeopOpTimeout
104 }
105 if (to == EC_SLAVE_STATE_INIT ||
106 ((from == EC_SLAVE_STATE_OP || from == EC_SLAVE_STATE_SAFEOP)
107 && to == EC_SLAVE_STATE_PREOP)) {
108 return 5000; // BackToInitTimeout
109 }
110 if (from == EC_SLAVE_STATE_OP && to == EC_SLAVE_STATE_SAFEOP) {
111 return 200; // BackToSafeopTimeout
112 }
113
114 return 10000; // default [ms]
115}
116
117/****************************************************************************/
118
122
124 ec_slave_t *slave,
125 ec_slave_state_t state
126 )
127{
129 fsm->slave = slave;
130 fsm->requested_state = state;
132}
133
134/****************************************************************************/
135
139
149
150/****************************************************************************/
151
156
158{
159 fsm->state(fsm);
160
161 return fsm->state != ec_fsm_change_state_end
163}
164
165/****************************************************************************/
166
171
176
177/*****************************************************************************
178 * state change state machine
179 ****************************************************************************/
180
184
187{
188 ec_datagram_t *datagram = fsm->datagram;
189 ec_slave_t *slave = fsm->slave;
190
191 fsm->take_time = 1;
192 fsm->old_state = fsm->slave->current_state;
193
194 // write new state to slave
195 ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
196 EC_WRITE_U16(datagram->data, fsm->requested_state);
197 fsm->retries = EC_FSM_RETRIES;
199}
200
201/****************************************************************************/
202
206
209{
210 ec_datagram_t *datagram = fsm->datagram;
211 ec_slave_t *slave = fsm->slave;
212
213 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
214 return;
215
216 if (datagram->state != EC_DATAGRAM_RECEIVED) {
218 EC_SLAVE_ERR(slave, "Failed to receive state datagram: ");
219 ec_datagram_print_state(datagram);
220 return;
221 }
222
223 if (fsm->take_time) {
224 fsm->take_time = 0;
225 fsm->jiffies_start = datagram->jiffies_sent;
226 }
227
228 if (datagram->working_counter == 0) {
229 if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
230 char state_str[EC_STATE_STRING_SIZE];
231 ec_state_string(fsm->requested_state, state_str, 0);
233 EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
235 return;
236 }
237
238 // repeat writing new state to slave
239 ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
240 EC_WRITE_U16(datagram->data, fsm->requested_state);
241 fsm->retries = EC_FSM_RETRIES;
242 return;
243 }
244
245 if (unlikely(datagram->working_counter > 1)) {
246 char state_str[EC_STATE_STRING_SIZE];
247 ec_state_string(fsm->requested_state, state_str, 0);
249 EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
251 return;
252 }
253
254 fsm->take_time = 1;
255
256 // read AL status from slave
257 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
258 ec_datagram_zero(datagram);
259 fsm->retries = EC_FSM_RETRIES;
260 fsm->spontaneous_change = 0;
262}
263
264/****************************************************************************/
265
269
272{
273 ec_datagram_t *datagram = fsm->datagram;
274 ec_slave_t *slave = fsm->slave;
275 unsigned int timeout_ms;
276
277 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
278 return;
279
280 if (datagram->state != EC_DATAGRAM_RECEIVED) {
282 EC_SLAVE_ERR(slave, "Failed to receive state checking datagram: ");
283 ec_datagram_print_state(datagram);
284 return;
285 }
286
287 if (datagram->working_counter != 1) {
288 char req_state[EC_STATE_STRING_SIZE];
289 ec_state_string(fsm->requested_state, req_state, 0);
291 EC_SLAVE_ERR(slave, "Failed to check state %s: ", req_state);
293 return;
294 }
295
296 if (fsm->take_time) {
297 fsm->take_time = 0;
298 fsm->jiffies_start = datagram->jiffies_sent;
299 }
300
301 slave->current_state = EC_READ_U8(datagram->data);
302
303 if (slave->current_state == fsm->requested_state) {
304 // state has been set successfully
306 return;
307 }
308
309 if (slave->current_state != fsm->old_state) { // state changed
310 char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
311
312 ec_state_string(slave->current_state, cur_state, 0);
313
314 if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
315 // Slave spontaneously changed its state just before the new state
316 // was written. Accept current state as old state and wait for
317 // state change
318 fsm->spontaneous_change = 1;
319 fsm->old_state = slave->current_state;
320 EC_SLAVE_WARN(slave, "Changed to %s in the meantime.\n",
321 cur_state);
322 goto check_again;
323 }
324
325 // state change error
326
327 slave->error_flag = 1;
328 ec_state_string(fsm->requested_state, req_state, 0);
329
330 EC_SLAVE_ERR(slave, "Failed to set %s state, slave refused state"
331 " change (%s).\n", req_state, cur_state);
332
334 return;
335 }
336
337 // still old state
338
339 timeout_ms = ec_fsm_change_timeout_ms(fsm);
340 if (datagram->jiffies_received - fsm->jiffies_start >=
341 timeout_ms * HZ / 1000) {
342 // timeout while checking
343 char state_str[EC_STATE_STRING_SIZE];
344 ec_state_string(fsm->requested_state, state_str, 0);
346 EC_SLAVE_ERR(slave, "Timeout after %u ms while setting state %s.\n",
347 timeout_ms, state_str);
348 return;
349 }
350
351 check_again:
352 // no timeout yet. check again
353 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
354 ec_datagram_zero(datagram);
355 fsm->retries = EC_FSM_RETRIES;
356}
357
358/****************************************************************************/
359
363 ec_fsm_change_t *fsm
364 )
365{
366 ec_slave_t *slave = fsm->slave;
367 ec_datagram_t *datagram = fsm->datagram;
368
369 // fetch AL status error code
370 ec_datagram_fprd(datagram, slave->station_address, 0x0134, 2);
371 ec_datagram_zero(datagram);
372 fsm->retries = EC_FSM_RETRIES;
374}
375
376/****************************************************************************/
377
381
383 {0x0000, "No error"},
384 {0x0001, "Unspecified error"},
385 {0x0002, "No Memory"},
386 {0x0011, "Invalid requested state change"},
387 {0x0012, "Unknown requested state"},
388 {0x0013, "Bootstrap not supported"},
389 {0x0014, "No valid firmware"},
390 {0x0015, "Invalid mailbox configuration"},
391 {0x0016, "Invalid mailbox configuration"},
392 {0x0017, "Invalid sync manager configuration"},
393 {0x0018, "No valid inputs available"},
394 {0x0019, "No valid outputs"},
395 {0x001A, "Synchronization error"},
396 {0x001B, "Sync manager watchdog"},
397 {0x001C, "Invalid sync manager types"},
398 {0x001D, "Invalid output configuration"},
399 {0x001E, "Invalid input configuration"},
400 {0x001F, "Invalid watchdog configuration"},
401 {0x0020, "Slave needs cold start"},
402 {0x0021, "Slave needs INIT"},
403 {0x0022, "Slave needs PREOP"},
404 {0x0023, "Slave needs SAFEOP"},
405 {0x0024, "Invalid Input Mapping"},
406 {0x0025, "Invalid Output Mapping"},
407 {0x0026, "Inconsistent Settings"},
408 {0x0027, "Freerun not supported"},
409 {0x0028, "Synchronization not supported"},
410 {0x0029, "Freerun needs 3 Buffer Mode"},
411 {0x002A, "Background Watchdog"},
412 {0x002B, "No Valid Inputs and Outputs"},
413 {0x002C, "Fatal Sync Error"},
414 {0x002D, "No Sync Error"},
415 {0x0030, "Invalid DC SYNCH configuration"},
416 {0x0031, "Invalid DC latch configuration"},
417 {0x0032, "PLL error"},
418 {0x0033, "DC Sync IO Error"},
419 {0x0034, "DC Sync Timeout Error"},
420 {0x0035, "DC Invalid Sync Cycle Time"},
421 {0x0036, "DC Sync0 Cycle Time"},
422 {0x0037, "DC Sync1 Cycle Time"},
423 {0x0041, "MBX_AOE"},
424 {0x0042, "MBX_EOE"},
425 {0x0043, "MBX_COE"},
426 {0x0044, "MBX_FOE"},
427 {0x0045, "MBX_SOE"},
428 {0x004F, "MBX_VOE"},
429 {0x0050, "EEPROM No Access"},
430 {0x0051, "EEPROM Error"},
431 {0x0060, "Slave Restarted Locally"},
432 {0xffff}
433};
434
435
436/****************************************************************************/
437
441
444{
445 ec_datagram_t *datagram = fsm->datagram;
446 uint32_t code;
447 const ec_code_msg_t *al_msg;
448
449 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
450 return;
451
452 if (datagram->state != EC_DATAGRAM_RECEIVED) {
454 EC_SLAVE_ERR(fsm->slave, "Failed to receive"
455 " AL status code datagram: ");
456 ec_datagram_print_state(datagram);
457 return;
458 }
459
460 if (datagram->working_counter != 1) {
461 EC_SLAVE_WARN(fsm->slave, "Reception of AL status code"
462 " datagram failed: ");
464 } else {
465 code = EC_READ_U16(datagram->data);
466 for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
467 if (al_msg->code != code) {
468 continue;
469 }
470
471 EC_SLAVE_ERR(fsm->slave, "AL status message 0x%04X: \"%s\".\n",
472 al_msg->code, al_msg->message);
473 break;
474 }
475 if (al_msg->code == 0xffff) { /* not found in our list. */
476 EC_SLAVE_ERR(fsm->slave, "Unknown AL status code 0x%04X.\n",
477 code);
478 }
479 }
480
481 // acknowledge "old" slave state
482 ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0120, 2);
483 EC_WRITE_U16(datagram->data, fsm->slave->current_state);
484 fsm->retries = EC_FSM_RETRIES;
486}
487
488/****************************************************************************/
489
493
495{
496 ec_datagram_t *datagram = fsm->datagram;
497 ec_slave_t *slave = fsm->slave;
498
499 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
500 return;
501
502 if (datagram->state != EC_DATAGRAM_RECEIVED) {
504 EC_SLAVE_ERR(slave, "Failed to receive state ack datagram: ");
505 ec_datagram_print_state(datagram);
506 return;
507 }
508
509 if (datagram->working_counter != 1) {
511 EC_SLAVE_ERR(slave, "Reception of state ack datagram failed: ");
513 return;
514 }
515
516 fsm->take_time = 1;
517
518 // read new AL status
519 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
520 ec_datagram_zero(datagram);
521 fsm->retries = EC_FSM_RETRIES;
523}
524
525/****************************************************************************/
526
530
533{
534 ec_datagram_t *datagram = fsm->datagram;
535 ec_slave_t *slave = fsm->slave;
536 unsigned int timeout_ms;
537
538 if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
539 return;
540
541 if (datagram->state != EC_DATAGRAM_RECEIVED) {
543 EC_SLAVE_ERR(slave, "Failed to receive state ack check datagram: ");
544 ec_datagram_print_state(datagram);
545 return;
546 }
547
548 if (datagram->working_counter != 1) {
550 EC_SLAVE_ERR(slave, "Reception of state ack check datagram failed: ");
552 return;
553 }
554
555 if (fsm->take_time) {
556 fsm->take_time = 0;
557 fsm->jiffies_start = datagram->jiffies_sent;
558 }
559
560 slave->current_state = EC_READ_U8(datagram->data);
561
562 if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
563 char state_str[EC_STATE_STRING_SIZE];
564 ec_state_string(slave->current_state, state_str, 0);
565 if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
567 }
568 else { // EC_FSM_CHANGE_MODE_ACK_ONLY
570 }
571 EC_SLAVE_INFO(slave, "Acknowledged state %s.\n", state_str);
572 return;
573 }
574
575 timeout_ms = ec_fsm_change_timeout_ms(fsm);
576 if (datagram->jiffies_received - fsm->jiffies_start >=
577 timeout_ms * HZ / 1000) {
578 // timeout while checking
579 char state_str[EC_STATE_STRING_SIZE];
580 ec_state_string(slave->current_state, state_str, 0);
582 EC_SLAVE_ERR(slave, "Timeout after %u ms while acknowledging"
583 " state %s.\n", timeout_ms, state_str);
584 return;
585 }
586
587 // reread new AL status
588 ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
589 ec_datagram_zero(datagram);
590 fsm->retries = EC_FSM_RETRIES;
591}
592
593/****************************************************************************/
594
598
603
604/****************************************************************************/
605
609
614
615/****************************************************************************/
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_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition datagram.c:170
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition datagram.c:557
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:290
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:265
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition fsm_change.c:172
void ec_fsm_change_state_ack(ec_fsm_change_t *)
Change state: ACK.
Definition fsm_change.c:494
void ec_fsm_change_state_start(ec_fsm_change_t *)
Change state: START.
Definition fsm_change.c:185
void ec_fsm_change_init(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition fsm_change.c:54
void ec_fsm_change_state_check(ec_fsm_change_t *)
Change state: CHECK.
Definition fsm_change.c:207
void ec_fsm_change_state_code(ec_fsm_change_t *)
Change state: CODE.
Definition fsm_change.c:442
void ec_fsm_change_state_check_ack(ec_fsm_change_t *)
Change state: CHECK ACK.
Definition fsm_change.c:531
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:140
const ec_code_msg_t al_status_messages[]
Application layer status messages.
Definition fsm_change.c:382
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:123
void ec_fsm_change_clear(ec_fsm_change_t *fsm)
Destructor.
Definition fsm_change.c:69
void ec_fsm_change_state_error(ec_fsm_change_t *)
State: ERROR.
Definition fsm_change.c:599
void ec_fsm_change_state_status(ec_fsm_change_t *)
Change state: STATUS.
Definition fsm_change.c:270
void ec_fsm_change_state_start_code(ec_fsm_change_t *)
Enter reading AL status code.
Definition fsm_change.c:362
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition fsm_change.c:157
void ec_fsm_change_state_end(ec_fsm_change_t *)
State: END.
Definition fsm_change.c:610
unsigned int ec_fsm_change_timeout_ms(const ec_fsm_change_t *)
Get timeout in ms.
Definition fsm_change.c:79
EtherCAT state change FSM.
struct ec_fsm_change ec_fsm_change_t
Definition fsm_change.h:50
@ EC_FSM_CHANGE_MODE_FULL
full state change
Definition fsm_change.h:43
@ EC_FSM_CHANGE_MODE_ACK_ONLY
only state acknowledgement
Definition fsm_change.h:44
Global definitions and macros.
ec_slave_state_t
State of an EtherCAT slave.
Definition globals.h:121
@ EC_SLAVE_STATE_BOOT
Bootstrap state (mailbox communication, firmware update).
Definition globals.h:128
@ EC_SLAVE_STATE_PREOP
PREOP state (mailbox communication, no IO).
Definition globals.h:126
@ EC_SLAVE_STATE_OP
OP (mailbox communication and input/output update).
Definition globals.h:132
@ EC_SLAVE_STATE_SAFEOP
SAFEOP (mailbox communication and input update).
Definition globals.h:130
@ EC_SLAVE_STATE_UNKNOWN
unknown state
Definition globals.h:122
@ EC_SLAVE_STATE_INIT
INIT state (no mailbox communication, no IO).
Definition globals.h:124
@ EC_SLAVE_STATE_ACK_ERR
Acknowledge/Error bit (no actual state).
Definition globals.h:134
#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:401
struct ec_slave ec_slave_t
Definition globals.h:310
#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
EtherCAT master structure.
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition slave.h:68
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition slave.h:82
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition slave.h:54
unsigned int ec_slave_config_al_timeout(const ec_slave_config_t *sc, ec_slave_state_t from, ec_slave_state_t to)
Return an AL state timeout.
EtherCAT slave configuration structure.
Code/Message pair.
Definition globals.h:275
uint32_t code
Code.
Definition globals.h:276
const char * message
Message belonging to code.
Definition globals.h:277
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
uint8_t * data
Datagram payload.
Definition datagram.h:88
unsigned int retries
retries upon datagram timeout
Definition fsm_change.h:60
ec_slave_state_t old_state
prior slave state
Definition fsm_change.h:65
ec_fsm_change_mode_t mode
full state change, or ack only.
Definition fsm_change.h:63
ec_slave_state_t requested_state
input: state
Definition fsm_change.h:64
uint8_t spontaneous_change
spontaneous state change detected
Definition fsm_change.h:68
uint8_t take_time
take sending timestamp
Definition fsm_change.h:67
unsigned long jiffies_start
change timer
Definition fsm_change.h:66
ec_datagram_t * datagram
datagram used in the state machine
Definition fsm_change.h:59
void(* state)(ec_fsm_change_t *)
slave state change state function
Definition fsm_change.h:62
ec_slave_t * slave
slave the FSM runs on
Definition fsm_change.h:58
ec_slave_config_t * config
Current configuration.
Definition slave.h:182
ec_slave_state_t current_state
Current application state.
Definition slave.h:184
uint16_t station_address
Configured station address.
Definition slave.h:176
unsigned int error_flag
Stop processing after an error.
Definition slave.h:185