IgH EtherCAT Master  1.6.0
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 
27 /****************************************************************************/
28 
29 #include "globals.h"
30 #include "master.h"
31 #include "fsm_change.h"
32 
33 /****************************************************************************/
34 
40 #define EC_AL_STATE_CHANGE_TIMEOUT 10
41 
42 /****************************************************************************/
43 
53 
54 /****************************************************************************/
55 
61  ec_datagram_t *datagram
62  )
63 {
64  fsm->state = NULL;
65  fsm->datagram = datagram;
66  fsm->spontaneous_change = 0;
67 }
68 
69 /****************************************************************************/
70 
76 {
77 }
78 
79 /****************************************************************************/
80 
86  ec_slave_t *slave,
87  ec_slave_state_t state
88  )
89 {
91  fsm->slave = slave;
92  fsm->requested_state = state;
94 }
95 
96 /****************************************************************************/
97 
103  ec_slave_t *slave
104  )
105 {
107  fsm->slave = slave;
110 }
111 
112 /****************************************************************************/
113 
120 {
121  fsm->state(fsm);
122 
123  return fsm->state != ec_fsm_change_state_end
124  && fsm->state != ec_fsm_change_state_error;
125 }
126 
127 /****************************************************************************/
128 
135 {
136  return fsm->state == ec_fsm_change_state_end;
137 }
138 
139 /*****************************************************************************
140  * state change state machine
141  ****************************************************************************/
142 
149 {
150  ec_datagram_t *datagram = fsm->datagram;
151  ec_slave_t *slave = fsm->slave;
152 
153  fsm->take_time = 1;
154  fsm->old_state = fsm->slave->current_state;
155 
156  // write new state to slave
157  ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
158  EC_WRITE_U16(datagram->data, fsm->requested_state);
159  fsm->retries = EC_FSM_RETRIES;
161 }
162 
163 /****************************************************************************/
164 
171 {
172  ec_datagram_t *datagram = fsm->datagram;
173  ec_slave_t *slave = fsm->slave;
174 
175  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
176  return;
177 
178  if (datagram->state != EC_DATAGRAM_RECEIVED) {
180  EC_SLAVE_ERR(slave, "Failed to receive state datagram: ");
181  ec_datagram_print_state(datagram);
182  return;
183  }
184 
185  if (fsm->take_time) {
186  fsm->take_time = 0;
187  fsm->jiffies_start = datagram->jiffies_sent;
188  }
189 
190  if (datagram->working_counter == 0) {
191  if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
192  char state_str[EC_STATE_STRING_SIZE];
193  ec_state_string(fsm->requested_state, state_str, 0);
195  EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
196  ec_datagram_print_wc_error(datagram);
197  return;
198  }
199 
200  // repeat writing new state to slave
201  ec_datagram_fpwr(datagram, slave->station_address, 0x0120, 2);
202  EC_WRITE_U16(datagram->data, fsm->requested_state);
203  fsm->retries = EC_FSM_RETRIES;
204  return;
205  }
206 
207  if (unlikely(datagram->working_counter > 1)) {
208  char state_str[EC_STATE_STRING_SIZE];
209  ec_state_string(fsm->requested_state, state_str, 0);
211  EC_SLAVE_ERR(slave, "Failed to set state %s: ", state_str);
212  ec_datagram_print_wc_error(datagram);
213  return;
214  }
215 
216  fsm->take_time = 1;
217 
218  // read AL status from slave
219  ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
220  ec_datagram_zero(datagram);
221  fsm->retries = EC_FSM_RETRIES;
222  fsm->spontaneous_change = 0;
224 }
225 
226 /****************************************************************************/
227 
234 {
235  ec_datagram_t *datagram = fsm->datagram;
236  ec_slave_t *slave = fsm->slave;
237 
238  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
239  return;
240 
241  if (datagram->state != EC_DATAGRAM_RECEIVED) {
243  EC_SLAVE_ERR(slave, "Failed to receive state checking datagram: ");
244  ec_datagram_print_state(datagram);
245  return;
246  }
247 
248  if (datagram->working_counter != 1) {
249  char req_state[EC_STATE_STRING_SIZE];
250  ec_state_string(fsm->requested_state, req_state, 0);
252  EC_SLAVE_ERR(slave, "Failed to check state %s: ", req_state);
253  ec_datagram_print_wc_error(datagram);
254  return;
255  }
256 
257  if (fsm->take_time) {
258  fsm->take_time = 0;
259  fsm->jiffies_start = datagram->jiffies_sent;
260  }
261 
262  slave->current_state = EC_READ_U8(datagram->data);
263 
264  if (slave->current_state == fsm->requested_state) {
265  // state has been set successfully
267  return;
268  }
269 
270  if (slave->current_state != fsm->old_state) { // state changed
271  char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
272 
273  ec_state_string(slave->current_state, cur_state, 0);
274 
275  if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
276  // Slave spontaneously changed its state just before the new state
277  // was written. Accept current state as old state and wait for
278  // state change
279  fsm->spontaneous_change = 1;
280  fsm->old_state = slave->current_state;
281  EC_SLAVE_WARN(slave, "Changed to %s in the meantime.\n",
282  cur_state);
283  goto check_again;
284  }
285 
286  // state change error
287 
288  slave->error_flag = 1;
289  ec_state_string(fsm->requested_state, req_state, 0);
290 
291  EC_SLAVE_ERR(slave, "Failed to set %s state, slave refused state"
292  " change (%s).\n", req_state, cur_state);
293 
295  return;
296  }
297 
298  // still old state
299 
300  if (datagram->jiffies_received - fsm->jiffies_start >=
302  // timeout while checking
303  char state_str[EC_STATE_STRING_SIZE];
304  ec_state_string(fsm->requested_state, state_str, 0);
306  EC_SLAVE_ERR(slave, "Timeout while setting state %s.\n", state_str);
307  return;
308  }
309 
310  check_again:
311  // no timeout yet. check again
312  ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
313  ec_datagram_zero(datagram);
314  fsm->retries = EC_FSM_RETRIES;
315 }
316 
317 /****************************************************************************/
318 
322  ec_fsm_change_t *fsm
323  )
324 {
325  ec_slave_t *slave = fsm->slave;
326  ec_datagram_t *datagram = fsm->datagram;
327 
328  // fetch AL status error code
329  ec_datagram_fprd(datagram, slave->station_address, 0x0134, 2);
330  ec_datagram_zero(datagram);
331  fsm->retries = EC_FSM_RETRIES;
333 }
334 
335 /****************************************************************************/
336 
342  {0x0000, "No error"},
343  {0x0001, "Unspecified error"},
344  {0x0002, "No Memory"},
345  {0x0011, "Invalid requested state change"},
346  {0x0012, "Unknown requested state"},
347  {0x0013, "Bootstrap not supported"},
348  {0x0014, "No valid firmware"},
349  {0x0015, "Invalid mailbox configuration"},
350  {0x0016, "Invalid mailbox configuration"},
351  {0x0017, "Invalid sync manager configuration"},
352  {0x0018, "No valid inputs available"},
353  {0x0019, "No valid outputs"},
354  {0x001A, "Synchronization error"},
355  {0x001B, "Sync manager watchdog"},
356  {0x001C, "Invalid sync manager types"},
357  {0x001D, "Invalid output configuration"},
358  {0x001E, "Invalid input configuration"},
359  {0x001F, "Invalid watchdog configuration"},
360  {0x0020, "Slave needs cold start"},
361  {0x0021, "Slave needs INIT"},
362  {0x0022, "Slave needs PREOP"},
363  {0x0023, "Slave needs SAFEOP"},
364  {0x0024, "Invalid Input Mapping"},
365  {0x0025, "Invalid Output Mapping"},
366  {0x0026, "Inconsistent Settings"},
367  {0x0027, "Freerun not supported"},
368  {0x0028, "Synchronization not supported"},
369  {0x0029, "Freerun needs 3 Buffer Mode"},
370  {0x002A, "Background Watchdog"},
371  {0x002B, "No Valid Inputs and Outputs"},
372  {0x002C, "Fatal Sync Error"},
373  {0x002D, "No Sync Error"},
374  {0x0030, "Invalid DC SYNCH configuration"},
375  {0x0031, "Invalid DC latch configuration"},
376  {0x0032, "PLL error"},
377  {0x0033, "DC Sync IO Error"},
378  {0x0034, "DC Sync Timeout Error"},
379  {0x0035, "DC Invalid Sync Cycle Time"},
380  {0x0036, "DC Sync0 Cycle Time"},
381  {0x0037, "DC Sync1 Cycle Time"},
382  {0x0041, "MBX_AOE"},
383  {0x0042, "MBX_EOE"},
384  {0x0043, "MBX_COE"},
385  {0x0044, "MBX_FOE"},
386  {0x0045, "MBX_SOE"},
387  {0x004F, "MBX_VOE"},
388  {0x0050, "EEPROM No Access"},
389  {0x0051, "EEPROM Error"},
390  {0x0060, "Slave Restarted Locally"},
391  {0xffff}
392 };
393 
394 
395 /****************************************************************************/
396 
403 {
404  ec_datagram_t *datagram = fsm->datagram;
405  uint32_t code;
406  const ec_code_msg_t *al_msg;
407 
408  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
409  return;
410 
411  if (datagram->state != EC_DATAGRAM_RECEIVED) {
413  EC_SLAVE_ERR(fsm->slave, "Failed to receive"
414  " AL status code datagram: ");
415  ec_datagram_print_state(datagram);
416  return;
417  }
418 
419  if (datagram->working_counter != 1) {
420  EC_SLAVE_WARN(fsm->slave, "Reception of AL status code"
421  " datagram failed: ");
422  ec_datagram_print_wc_error(datagram);
423  } else {
424  code = EC_READ_U16(datagram->data);
425  for (al_msg = al_status_messages; al_msg->code != 0xffff; al_msg++) {
426  if (al_msg->code != code) {
427  continue;
428  }
429 
430  EC_SLAVE_ERR(fsm->slave, "AL status message 0x%04X: \"%s\".\n",
431  al_msg->code, al_msg->message);
432  break;
433  }
434  if (al_msg->code == 0xffff) { /* not found in our list. */
435  EC_SLAVE_ERR(fsm->slave, "Unknown AL status code 0x%04X.\n",
436  code);
437  }
438  }
439 
440  // acknowledge "old" slave state
441  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0120, 2);
442  EC_WRITE_U16(datagram->data, fsm->slave->current_state);
443  fsm->retries = EC_FSM_RETRIES;
445 }
446 
447 /****************************************************************************/
448 
454 {
455  ec_datagram_t *datagram = fsm->datagram;
456  ec_slave_t *slave = fsm->slave;
457 
458  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
459  return;
460 
461  if (datagram->state != EC_DATAGRAM_RECEIVED) {
463  EC_SLAVE_ERR(slave, "Failed to receive state ack datagram: ");
464  ec_datagram_print_state(datagram);
465  return;
466  }
467 
468  if (datagram->working_counter != 1) {
470  EC_SLAVE_ERR(slave, "Reception of state ack datagram failed: ");
471  ec_datagram_print_wc_error(datagram);
472  return;
473  }
474 
475  fsm->take_time = 1;
476 
477  // read new AL status
478  ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
479  ec_datagram_zero(datagram);
480  fsm->retries = EC_FSM_RETRIES;
482 }
483 
484 /****************************************************************************/
485 
492 {
493  ec_datagram_t *datagram = fsm->datagram;
494  ec_slave_t *slave = fsm->slave;
495 
496  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
497  return;
498 
499  if (datagram->state != EC_DATAGRAM_RECEIVED) {
501  EC_SLAVE_ERR(slave, "Failed to receive state ack check datagram: ");
502  ec_datagram_print_state(datagram);
503  return;
504  }
505 
506  if (datagram->working_counter != 1) {
508  EC_SLAVE_ERR(slave, "Reception of state ack check datagram failed: ");
509  ec_datagram_print_wc_error(datagram);
510  return;
511  }
512 
513  if (fsm->take_time) {
514  fsm->take_time = 0;
515  fsm->jiffies_start = datagram->jiffies_sent;
516  }
517 
518  slave->current_state = EC_READ_U8(datagram->data);
519 
520  if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
521  char state_str[EC_STATE_STRING_SIZE];
522  ec_state_string(slave->current_state, state_str, 0);
523  if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
525  }
526  else { // EC_FSM_CHANGE_MODE_ACK_ONLY
528  }
529  EC_SLAVE_INFO(slave, "Acknowledged state %s.\n", state_str);
530  return;
531  }
532 
533  if (datagram->jiffies_received - fsm->jiffies_start >=
535  // timeout while checking
536  char state_str[EC_STATE_STRING_SIZE];
537  ec_state_string(slave->current_state, state_str, 0);
539  EC_SLAVE_ERR(slave, "Timeout while acknowledging state %s.\n",
540  state_str);
541  return;
542  }
543 
544  // reread new AL status
545  ec_datagram_fprd(datagram, slave->station_address, 0x0130, 2);
546  ec_datagram_zero(datagram);
547  fsm->retries = EC_FSM_RETRIES;
548 }
549 
550 /****************************************************************************/
551 
558 {
559 }
560 
561 /****************************************************************************/
562 
569 {
570 }
571 
572 /****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:96
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:68
#define EC_AL_STATE_CHANGE_TIMEOUT
Timeout while waiting for AL state change [s].
Definition: fsm_change.c:40
EtherCAT state change FSM.
size_t ec_state_string(uint8_t, char *, uint8_t)
Prints slave states in clear text.
Definition: module.c:399
uint8_t take_time
take sending timestamp
Definition: fsm_change.h:67
ec_slave_state_t current_state
Current application state.
Definition: slave.h:184
uint32_t code
Code.
Definition: globals.h:276
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:82
EtherCAT datagram.
Definition: datagram.h:79
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:85
uint16_t working_counter
Working counter.
Definition: datagram.h:91
void ec_fsm_change_state_end(ec_fsm_change_t *)
State: END.
Definition: fsm_change.c:567
Acknowledge/Error bit (no actual state)
Definition: globals.h:134
uint16_t station_address
Configured station address.
Definition: slave.h:176
const char * message
Message belonging to code.
Definition: globals.h:277
Global definitions and macros.
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_change.h:59
EtherCAT master structure.
void ec_fsm_change_state_error(ec_fsm_change_t *)
State: ERROR.
Definition: fsm_change.c:556
EtherCAT slave.
Definition: slave.h:168
only state acknowledgement
Definition: fsm_change.h:44
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:170
Code/Message pair.
Definition: globals.h:275
ec_datagram_state_t state
State.
Definition: datagram.h:92
unsigned long jiffies_start
change timer
Definition: fsm_change.h:66
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:68
void(* state)(ec_fsm_change_t *)
slave state change state function
Definition: fsm_change.h:62
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:594
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:119
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2716
void ec_fsm_change_state_start(ec_fsm_change_t *)
Change state: START.
Definition: fsm_change.c:147
void ec_fsm_change_clear(ec_fsm_change_t *fsm)
Destructor.
Definition: fsm_change.c:75
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
ec_fsm_change_mode_t mode
full state change, or ack only.
Definition: fsm_change.h:63
ec_slave_state_t
State of an EtherCAT slave.
Definition: globals.h:121
void ec_fsm_change_state_check_ack(ec_fsm_change_t *)
Change state: CHECK ACK.
Definition: fsm_change.c:490
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
full state change
Definition: fsm_change.h:43
void ec_fsm_change_state_status(ec_fsm_change_t *)
Change state: STATUS.
Definition: fsm_change.c:232
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:54
void ec_fsm_change_init(ec_fsm_change_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_change.c:60
void ec_fsm_change_state_ack(ec_fsm_change_t *)
Change state: ACK.
Definition: fsm_change.c:453
const ec_code_msg_t al_status_messages[]
Application layer status messages.
Definition: fsm_change.c:341
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2611
ec_slave_state_t requested_state
input: state
Definition: fsm_change.h:64
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:557
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_change.h:58
#define EC_STATE_STRING_SIZE
Minimum size of a buffer used with ec_state_string().
Definition: globals.h:54
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:102
Timed out (dequeued).
Definition: datagram.h:71
uint8_t * data
Datagram payload.
Definition: datagram.h:86
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2595
void ec_fsm_change_state_code(ec_fsm_change_t *)
Change state: CODE.
Definition: fsm_change.c:401
void ec_fsm_change_state_check(ec_fsm_change_t *)
Change state: CHECK.
Definition: fsm_change.c:169
void ec_fsm_change_state_start_code(ec_fsm_change_t *)
Enter reading AL status code.
Definition: fsm_change.c:321
Received (dequeued).
Definition: datagram.h:70
ec_slave_state_t old_state
prior slave state
Definition: fsm_change.h:65
unsigned int retries
retries upon datagram timeout
Definition: fsm_change.h:60
unsigned int error_flag
Stop processing after an error.
Definition: slave.h:185
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:100
unknown state
Definition: globals.h:122
EtherCAT state change FSM.
Definition: fsm_change.h:56
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:134