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 {
67  fsm->state = NULL;
68  fsm->datagram = NULL;
69  fsm->spontaneous_change = 0;
70 }
71 
72 /*****************************************************************************/
73 
79 {
80 }
81 
82 /*****************************************************************************/
83 
89  ec_slave_t *slave,
90  ec_slave_state_t state
91  )
92 {
94  fsm->slave = slave;
95  fsm->requested_state = state;
97 }
98 
99 /*****************************************************************************/
100 
106  ec_slave_t *slave
107  )
108 {
110  fsm->slave = slave;
113 }
114 
115 /*****************************************************************************/
116 
123  ec_fsm_change_t *fsm,
124  ec_datagram_t *datagram
125  )
126 {
128  return 0;
129 
130  fsm->state(fsm, datagram);
131 
133  fsm->datagram = NULL;
134  return 0;
135  }
136 
137  fsm->datagram = datagram;
138  return 1;
139 }
140 
141 /*****************************************************************************/
142 
149 {
150  return fsm->state == ec_fsm_change_state_end;
151 }
152 
153 /******************************************************************************
154  * datagram functions
155  *****************************************************************************/
156 
158  ec_fsm_change_t *fsm,
159  ec_datagram_t *datagram
160  )
161 {
162  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0120, 2);
163  EC_WRITE_U16(datagram->data, fsm->requested_state);
164 }
165 
166 /*****************************************************************************/
167 
169  ec_fsm_change_t *fsm,
170  ec_datagram_t *datagram
171  )
172 {
173  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0120, 2);
174  EC_WRITE_U16(datagram->data, fsm->slave->current_state);
175 }
176 
177 /*****************************************************************************/
178 
180  ec_fsm_change_t *fsm,
181  ec_datagram_t *datagram
182  )
183 {
184  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0130, 2);
185  ec_datagram_zero(datagram);
186 }
187 
188 /*****************************************************************************/
189 
191  ec_fsm_change_t *fsm,
192  ec_datagram_t *datagram
193  )
194 {
195  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x0134, 2);
196  ec_datagram_zero(datagram);
197 }
198 
199 /******************************************************************************
200  * state change state machine
201  *****************************************************************************/
202 
208  ec_fsm_change_t *fsm,
209  ec_datagram_t *datagram
210  )
211 {
212  fsm->take_time = 1;
213  fsm->old_state = fsm->slave->current_state;
214 
215  // write new state to slave
217  fsm->retries = EC_FSM_RETRIES;
219 }
220 
221 /*****************************************************************************/
222 
228  ec_fsm_change_t *fsm,
229  ec_datagram_t *datagram
230  )
231 {
232  ec_slave_t *slave = fsm->slave;
233 
234  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
236  return;
237  }
238 
239  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
241  EC_SLAVE_ERR(slave, "Failed to receive state datagram: ");
243  return;
244  }
245 
246  if (fsm->take_time) {
247  fsm->take_time = 0;
248  fsm->jiffies_start = fsm->datagram->jiffies_sent;
249  }
250 
251  if (fsm->datagram->working_counter == 0) {
252  if (fsm->datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
253  char state_str[EC_STATE_STRING_SIZE];
254  ec_state_string(fsm->requested_state, state_str, 0);
256  EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
258  return;
259  }
260 
261  // repeat writing new state to slave
263  fsm->retries = EC_FSM_RETRIES;
264  return;
265  }
266 
267  if (unlikely(fsm->datagram->working_counter > 1)) {
268  char state_str[EC_STATE_STRING_SIZE];
269  ec_state_string(fsm->requested_state, state_str, 0);
271  EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
273  return;
274  }
275 
276  fsm->take_time = 1;
277 
278  // read AL status from slave
279  ec_fsm_change_prepare_read_state(fsm, datagram);
280  fsm->retries = EC_FSM_RETRIES;
281  fsm->spontaneous_change = 0;
283 }
284 
285 /*****************************************************************************/
286 
292  ec_fsm_change_t *fsm,
293  ec_datagram_t *datagram
294  )
295 {
296  ec_slave_t *slave = fsm->slave;
297 
298  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
299  ec_fsm_change_prepare_read_state(fsm, datagram);
300  return;
301  }
302 
303  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
305  EC_SLAVE_ERR(slave, "Failed to receive state checking datagram: ");
307  return;
308  }
309 
310  if (fsm->datagram->working_counter != 1) {
311  char req_state[EC_STATE_STRING_SIZE];
312  ec_state_string(fsm->requested_state, req_state, 0);
314  EC_SLAVE_ERR(slave, "Failed to check state %s: ", req_state);
316  return;
317  }
318 
319  if (fsm->take_time) {
320  fsm->take_time = 0;
321  fsm->jiffies_start = fsm->datagram->jiffies_sent;
322  }
323 
324  slave->current_state = EC_READ_U8(fsm->datagram->data);
325 
326  if (slave->current_state == fsm->requested_state) {
327  // state has been set successfully
329  return;
330  }
331 
332  if (slave->current_state != fsm->old_state) { // state changed
333  char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
334 
335  ec_state_string(slave->current_state, cur_state, 0);
336 
337  if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
338  // Slave spontaneously changed its state just before the new state
339  // was written. Accept current state as old state and wait for
340  // state change
341  fsm->spontaneous_change = 1;
342  fsm->old_state = slave->current_state;
343  EC_SLAVE_WARN(slave, "Changed to %s in the meantime.\n",
344  cur_state);
345  goto check_again;
346  }
347 
348  // state change error
349 
350  slave->error_flag = 1;
351  ec_state_string(fsm->requested_state, req_state, 0);
352 
353  EC_SLAVE_ERR(slave, "Failed to set %s state, slave refused state"
354  " change (%s).\n", req_state, cur_state);
355 
356  ec_fsm_change_state_start_code(fsm, datagram);
357  return;
358  }
359 
360  // still old state
361 
362  if (fsm->datagram->jiffies_received - fsm->jiffies_start >=
364  // timeout while checking
365  char state_str[EC_STATE_STRING_SIZE];
366  ec_state_string(fsm->requested_state, state_str, 0);
368  EC_SLAVE_ERR(slave, "Timeout while setting state %s.\n", state_str);
369  return;
370  }
371 
372  check_again:
373  // no timeout yet. check again
374  ec_fsm_change_prepare_read_state(fsm, datagram);
375  fsm->retries = EC_FSM_RETRIES;
376 }
377 
378 /*****************************************************************************/
379 
383  ec_fsm_change_t *fsm,
384  ec_datagram_t *datagram
385  )
386 {
387  // fetch AL status error code
388  ec_fsm_change_prepare_read_code(fsm, datagram);
389  fsm->retries = EC_FSM_RETRIES;
391 }
392 
393 /*****************************************************************************/
394 
400  {0x0000, "No error"},
401  {0x0001, "Unspecified error"},
402  {0x0002, "No Memory"},
403  {0x0011, "Invalid requested state change"},
404  {0x0012, "Unknown requested state"},
405  {0x0013, "Bootstrap not supported"},
406  {0x0014, "No valid firmware"},
407  {0x0015, "Invalid mailbox configuration"},
408  {0x0016, "Invalid mailbox configuration"},
409  {0x0017, "Invalid sync manager configuration"},
410  {0x0018, "No valid inputs available"},
411  {0x0019, "No valid outputs"},
412  {0x001A, "Synchronization error"},
413  {0x001B, "Sync manager watchdog"},
414  {0x001C, "Invalid sync manager types"},
415  {0x001D, "Invalid output configuration"},
416  {0x001E, "Invalid input configuration"},
417  {0x001F, "Invalid watchdog configuration"},
418  {0x0020, "Slave needs cold start"},
419  {0x0021, "Slave needs INIT"},
420  {0x0022, "Slave needs PREOP"},
421  {0x0023, "Slave needs SAFEOP"},
422  {0x0024, "Invalid Input Mapping"},
423  {0x0025, "Invalid Output Mapping"},
424  {0x0026, "Inconsistent Settings"},
425  {0x0027, "Freerun not supported"},
426  {0x0028, "Synchronization not supported"},
427  {0x0029, "Freerun needs 3 Buffer Mode"},
428  {0x002A, "Background Watchdog"},
429  {0x002B, "No Valid Inputs and Outputs"},
430  {0x002C, "Fatal Sync Error"},
431  {0x002D, "No Sync Error"},
432  {0x0030, "Invalid DC SYNCH configuration"},
433  {0x0031, "Invalid DC latch configuration"},
434  {0x0032, "PLL error"},
435  {0x0033, "DC Sync IO Error"},
436  {0x0034, "DC Sync Timeout Error"},
437  {0x0035, "DC Invalid Sync Cycle Time"},
438  {0x0036, "DC Sync0 Cycle Time"},
439  {0x0037, "DC Sync1 Cycle Time"},
440  {0x0041, "MBX_AOE"},
441  {0x0042, "MBX_EOE"},
442  {0x0043, "MBX_COE"},
443  {0x0044, "MBX_FOE"},
444  {0x0045, "MBX_SOE"},
445  {0x004F, "MBX_VOE"},
446  {0x0050, "EEPROM No Access"},
447  {0x0051, "EEPROM Error"},
448  {0x0060, "Slave Restarted Locally"},
449  {0xffff}
450 };
451 
452 
453 /*****************************************************************************/
454 
460  ec_fsm_change_t *fsm,
461  ec_datagram_t *datagram
462  )
463 {
464  uint32_t code;
465  const ec_code_msg_t *al_msg;
466 
467  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
468  ec_fsm_change_prepare_read_code(fsm, datagram);
469  return;
470  }
471 
472  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
474  EC_SLAVE_ERR(fsm->slave, "Failed to receive"
475  " AL status code datagram: ");
477  return;
478  }
479 
480  if (fsm->datagram->working_counter != 1) {
481  EC_SLAVE_WARN(fsm->slave, "Reception of AL status code"
482  " datagram failed: ");
484  fsm->slave->last_al_error = 0;
485  } else {
486  code = EC_READ_U16(fsm->datagram->data);
487  fsm->slave->last_al_error = code;
488  for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
489  if (al_msg->code != code) {
490  continue;
491  }
492 
493  EC_SLAVE_ERR(fsm->slave, "AL status message 0x%04X: \"%s\".\n",
494  al_msg->code, al_msg->message);
495  break;
496  }
497  if (al_msg->code == 0xffff) { /* not found in our list. */
498  EC_SLAVE_ERR(fsm->slave, "Unknown AL status code 0x%04X.\n",
499  code);
500  }
501  }
502 
503  // acknowledge "old" slave state
505  fsm->retries = EC_FSM_RETRIES;
507 }
508 
509 /*****************************************************************************/
510 
516  ec_fsm_change_t *fsm,
517  ec_datagram_t *datagram
518  )
519 {
520  ec_slave_t *slave = fsm->slave;
521 
522  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
524  return;
525  }
526 
527  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
529  EC_SLAVE_ERR(slave, "Failed to receive state ack datagram: ");
531  return;
532  }
533 
534  if (fsm->datagram->working_counter != 1) {
536  EC_SLAVE_ERR(slave, "Reception of state ack datagram failed: ");
538  return;
539  }
540 
541  fsm->take_time = 1;
542 
543  // read new AL status
544  ec_fsm_change_prepare_read_state(fsm, datagram);
545  fsm->retries = EC_FSM_RETRIES;
547 }
548 
549 /*****************************************************************************/
550 
556  ec_fsm_change_t *fsm,
557  ec_datagram_t *datagram
558  )
559 {
560  ec_slave_t *slave = fsm->slave;
561 
562  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
563  ec_fsm_change_prepare_read_state(fsm, datagram);
564  return;
565  }
566 
567  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
569  EC_SLAVE_ERR(slave, "Failed to receive state ack check datagram: ");
571  return;
572  }
573 
574  if (fsm->datagram->working_counter != 1) {
576  EC_SLAVE_ERR(slave, "Reception of state ack check datagram failed: ");
578  return;
579  }
580 
581  if (fsm->take_time) {
582  fsm->take_time = 0;
583  fsm->jiffies_start = fsm->datagram->jiffies_sent;
584  }
585 
586  slave->current_state = EC_READ_U8(fsm->datagram->data);
587 
588  if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
589  char state_str[EC_STATE_STRING_SIZE];
590  ec_state_string(slave->current_state, state_str, 0);
591  if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
593  }
594  else { // EC_FSM_CHANGE_MODE_ACK_ONLY
596  }
597  EC_SLAVE_INFO(slave, "Acknowledged state %s.\n", state_str);
598  return;
599  }
600 
601  if (fsm->datagram->jiffies_received - fsm->jiffies_start >=
603  // timeout while checking
604  char state_str[EC_STATE_STRING_SIZE];
605  ec_state_string(slave->current_state, state_str, 0);
607  EC_SLAVE_ERR(slave, "Timeout while acknowledging state %s.\n",
608  state_str);
609  return;
610  }
611 
612  // reread new AL status
613  ec_fsm_change_prepare_read_state(fsm, datagram);
614  fsm->retries = EC_FSM_RETRIES;
615 }
616 
617 /*****************************************************************************/
618 
624  ec_fsm_change_t *fsm,
625  ec_datagram_t *datagram
626  )
627 {
628 }
629 
630 /*****************************************************************************/
631 
637  ec_fsm_change_t *fsm,
638  ec_datagram_t *datagram
639  )
640 {
641 }
642 
643 /*****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:59
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
void ec_fsm_change_state_error(ec_fsm_change_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_change.c:623
#define EC_AL_STATE_CHANGE_TIMEOUT
Timeout while waiting for AL state change [s].
Definition: fsm_change.c:45
EtherCAT state change FSM.
size_t ec_state_string(uint8_t, char *, uint8_t)
Prints slave states in clear text.
Definition: module.c:408
uint8_t take_time
take sending timestamp
Definition: fsm_change.h:75
ec_slave_state_t current_state
Current application state.
Definition: slave.h:237
uint32_t code
Code.
Definition: globals.h:314
void ec_fsm_change_init(ec_fsm_change_t *fsm)
Constructor.
Definition: fsm_change.c:65
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:91
EtherCAT datagram.
Definition: datagram.h:88
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:88
uint16_t working_counter
Working counter.
Definition: datagram.h:100
static void ec_fsm_change_prepare_write_requested(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Definition: fsm_change.c:157
Acknowledge/Error bit (no actual state)
Definition: globals.h:172
uint16_t station_address
Configured station address.
Definition: slave.h:222
const char * message
Message belonging to code.
Definition: globals.h:315
Global definitions and macros.
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_change.h:67
EtherCAT master structure.
void ec_fsm_change_state_code(ec_fsm_change_t *, ec_datagram_t *)
Change state: CODE.
Definition: fsm_change.c:459
void ec_fsm_change_state_check_ack(ec_fsm_change_t *, ec_datagram_t *)
Change state: CHECK ACK.
Definition: fsm_change.c:555
EtherCAT slave.
Definition: slave.h:214
only state acknowledgement
Definition: fsm_change.h:52
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:179
void(* state)(ec_fsm_change_t *, ec_datagram_t *)
slave state change state function
Definition: fsm_change.h:70
Code/Message pair.
Definition: globals.h:313
void ec_fsm_change_state_ack(ec_fsm_change_t *, ec_datagram_t *)
Change state: ACK.
Definition: fsm_change.c:515
ec_datagram_state_t state
State.
Definition: datagram.h:101
static void ec_fsm_change_prepare_write_current(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Definition: fsm_change.c:168
unsigned long jiffies_start
change timer
Definition: fsm_change.h:74
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:77
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:627
void ec_fsm_change_state_status(ec_fsm_change_t *, ec_datagram_t *)
Change state: STATUS.
Definition: fsm_change.c:291
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2659
void ec_fsm_change_state_start_code(ec_fsm_change_t *, ec_datagram_t *)
Enter reading AL status code.
Definition: fsm_change.c:382
void ec_fsm_change_clear(ec_fsm_change_t *fsm)
Destructor.
Definition: fsm_change.c:78
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:320
ec_fsm_change_mode_t mode
full state change, or ack only.
Definition: fsm_change.h:71
ec_slave_state_t
State of an EtherCAT slave.
Definition: globals.h:159
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:295
full state change
Definition: fsm_change.h:51
static void ec_fsm_change_prepare_read_code(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Definition: fsm_change.c:190
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:63
const ec_code_msg_t al_status_messages[]
Application layer status messages.
Definition: fsm_change.c:399
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2554
ec_slave_state_t requested_state
input: state
Definition: fsm_change.h:72
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:587
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_change.h:66
#define EC_STATE_STRING_SIZE
Minimum size of a buffer used with ec_state_string().
Definition: globals.h:65
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:105
int ec_fsm_change_exec(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Executes the current state of the state machine.
Definition: fsm_change.c:122
Timed out (dequeued).
Definition: datagram.h:79
void ec_fsm_change_state_check(ec_fsm_change_t *, ec_datagram_t *)
Change state: CHECK.
Definition: fsm_change.c:227
uint8_t * data
Datagram payload.
Definition: datagram.h:95
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2538
void ec_fsm_change_state_end(ec_fsm_change_t *, ec_datagram_t *)
State: END.
Definition: fsm_change.c:636
Received (dequeued).
Definition: datagram.h:78
void ec_fsm_change_state_start(ec_fsm_change_t *, ec_datagram_t *)
Change state: START.
Definition: fsm_change.c:207
ec_slave_state_t old_state
prior slave state
Definition: fsm_change.h:73
unsigned int retries
retries upon datagram timeout
Definition: fsm_change.h:68
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:239
uint16_t last_al_error
Last AL state error code.
Definition: slave.h:238
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:110
unknown state
Definition: globals.h:160
EtherCAT state change FSM.
Definition: fsm_change.h:64
static void ec_fsm_change_prepare_read_state(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Definition: fsm_change.c:179
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:148