IgH EtherCAT Master  1.5.3
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
129  && fsm->state != ec_fsm_change_state_error;
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);
201  ec_datagram_print_wc_error(datagram);
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);
217  ec_datagram_print_wc_error(datagram);
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);
258  ec_datagram_print_wc_error(datagram);
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: ");
427  ec_datagram_print_wc_error(datagram);
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: ");
476  ec_datagram_print_wc_error(datagram);
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: ");
514  ec_datagram_print_wc_error(datagram);
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 /*****************************************************************************/
#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:104
uint8_t spontaneous_change
spontaneous state change detected
Definition: fsm_change.h:76
#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:405
uint8_t take_time
take sending timestamp
Definition: fsm_change.h:75
ec_slave_state_t current_state
Current application state.
Definition: slave.h:192
uint32_t code
Code.
Definition: globals.h:267
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:90
EtherCAT datagram.
Definition: datagram.h:87
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
uint16_t working_counter
Working counter.
Definition: datagram.h:99
void ec_fsm_change_state_end(ec_fsm_change_t *)
State: END.
Definition: fsm_change.c:572
Acknowledge/Error bit (no actual state)
Definition: globals.h:128
uint16_t station_address
Configured station address.
Definition: slave.h:184
const char * message
Message belonging to code.
Definition: globals.h:268
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_error(ec_fsm_change_t *)
State: ERROR.
Definition: fsm_change.c:561
EtherCAT slave.
Definition: slave.h:176
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:178
Code/Message pair.
Definition: globals.h:266
ec_datagram_state_t state
State.
Definition: datagram.h:100
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:76
void(* state)(ec_fsm_change_t *)
slave state change state function
Definition: fsm_change.h:70
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
int ec_fsm_change_exec(ec_fsm_change_t *fsm)
Executes the current state of the state machine.
Definition: fsm_change.c:124
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2418
void ec_fsm_change_state_start(ec_fsm_change_t *)
Change state: START.
Definition: fsm_change.c:152
void ec_fsm_change_clear(ec_fsm_change_t *fsm)
Destructor.
Definition: fsm_change.c:80
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
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:115
void ec_fsm_change_state_check_ack(ec_fsm_change_t *)
Change state: CHECK ACK.
Definition: fsm_change.c:495
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
full state change
Definition: fsm_change.h:51
void ec_fsm_change_state_status(ec_fsm_change_t *)
Change state: STATUS.
Definition: fsm_change.c:237
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:62
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_ack(ec_fsm_change_t *)
Change state: ACK.
Definition: fsm_change.c:458
const ec_code_msg_t al_status_messages[]
Application layer status messages.
Definition: fsm_change.c:346
#define EC_READ_U16(DATA)
Read a 16-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2313
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:565
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: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:107
Timed out (dequeued).
Definition: datagram.h:79
uint8_t * data
Datagram payload.
Definition: datagram.h:94
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2297
void ec_fsm_change_state_code(ec_fsm_change_t *)
Change state: CODE.
Definition: fsm_change.c:406
void ec_fsm_change_state_check(ec_fsm_change_t *)
Change state: CHECK.
Definition: fsm_change.c:174
void ec_fsm_change_state_start_code(ec_fsm_change_t *)
Enter reading AL status code.
Definition: fsm_change.c:326
Received (dequeued).
Definition: datagram.h:78
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:193
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
unknown state
Definition: globals.h:116
EtherCAT state change FSM.
Definition: fsm_change.h:64
int ec_fsm_change_success(ec_fsm_change_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_change.c:139