IgH EtherCAT Master  1.5.2
fsm_reboot.c
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * $Id$
4  *
5  * Copyright (C) 2014 Gavin Lambert
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_reboot.h"
40 
41 /*****************************************************************************/
42 
43 #define EC_FSM_ERR(fsm, fmt, args...) \
44  do { \
45  if (fsm->slave) { \
46  EC_SLAVE_ERR(fsm->slave, fmt, ##args); \
47  } else { \
48  EC_MASTER_ERR(fsm->master, fmt, ##args); \
49  } \
50  } while (0)
51 
52 /*****************************************************************************/
53 
61 
62 /*****************************************************************************/
63 
69  ec_datagram_t *datagram
70  )
71 {
72  fsm->state = NULL;
73  fsm->datagram = datagram;
74 }
75 
76 /*****************************************************************************/
77 
83 {
84 }
85 
86 /*****************************************************************************/
87 
93  ec_slave_t *slave
94  )
95 {
96  fsm->master = slave->master;
97  fsm->slave = slave;
99 }
100 
101 /*****************************************************************************/
102 
108  ec_master_t *master
109  )
110 {
111  fsm->master = master;
112  fsm->slave = NULL;
114 }
115 
116 /*****************************************************************************/
117 
124 {
125  fsm->state(fsm);
126 
127  return fsm->state != ec_fsm_reboot_state_end
128  && fsm->state != ec_fsm_reboot_state_error;
129 }
130 
131 /*****************************************************************************/
132 
139 {
140  return fsm->state == ec_fsm_reboot_state_end;
141 }
142 
143 /******************************************************************************
144  * slave reboot state machine
145  *****************************************************************************/
146 
153 {
154  ec_datagram_t *datagram = fsm->datagram;
155  ec_slave_t *slave = fsm->slave;
156 
157  if (slave) {
158  EC_SLAVE_INFO(slave, "Requesting slave reboot\n");
159  ec_datagram_fpwr(datagram, slave->station_address, 0x0040, 1);
160  } else {
161  EC_MASTER_INFO(fsm->master, "Requesting global reboot\n");
162  ec_datagram_bwr(datagram, 0x0040, 1);
163  }
164  EC_WRITE_U8(datagram->data, 'R');
165  fsm->retries = EC_FSM_RETRIES;
167 }
168 
169 /*****************************************************************************/
170 
177 {
178  ec_datagram_t *datagram = fsm->datagram;
179  ec_slave_t *slave = fsm->slave;
180 
181  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
182  return;
183 
184  if (datagram->state != EC_DATAGRAM_RECEIVED) {
186  EC_FSM_ERR(fsm, "Failed to receive reboot 1 datagram: ");
187  ec_datagram_print_state(datagram);
188  return;
189  }
190 
191  if (datagram->working_counter == 0) {
192  if (slave && fsm->retries--) {
193  ec_datagram_fpwr(datagram, slave->station_address, 0x0040, 1);
194  EC_WRITE_U8(datagram->data, 'R');
195  return;
196  }
197 
199  EC_FSM_ERR(fsm, "Failed to reboot 1\n");
200  ec_datagram_print_wc_error(datagram);
201  return;
202  }
203 
204  if (slave) {
205  ec_datagram_fpwr(datagram, slave->station_address, 0x0040, 1);
206  } else {
207  ec_datagram_bwr(datagram, 0x0040, 1);
208  }
209  EC_WRITE_U8(datagram->data, 'E');
210  fsm->retries = EC_FSM_RETRIES;
212 }
213 
214 /*****************************************************************************/
215 
222 {
223  ec_datagram_t *datagram = fsm->datagram;
224  ec_slave_t *slave = fsm->slave;
225 
226  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
227  return;
228 
229  if (datagram->state != EC_DATAGRAM_RECEIVED) {
231  EC_FSM_ERR(fsm, "Failed to receive reboot 2 datagram: ");
232  ec_datagram_print_state(datagram);
233  return;
234  }
235 
236  if (datagram->working_counter == 0) {
238  EC_FSM_ERR(fsm, "Failed to reboot 2\n");
239  ec_datagram_print_wc_error(datagram);
240  return;
241  }
242 
243  if (slave) {
244  ec_datagram_fpwr(datagram, slave->station_address, 0x0040, 1);
245  } else {
246  ec_datagram_bwr(datagram, 0x0040, 1);
247  }
248  EC_WRITE_U8(datagram->data, 'S');
249  fsm->retries = EC_FSM_RETRIES;
251 }
252 
253 /*****************************************************************************/
254 
261 {
262  ec_datagram_t *datagram = fsm->datagram;
263 
264  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
265  return;
266 
267  if (datagram->state != EC_DATAGRAM_RECEIVED) {
269  EC_FSM_ERR(fsm, "Failed to receive reboot 3 datagram: ");
270  ec_datagram_print_state(datagram);
271  return;
272  }
273 
274  if (datagram->working_counter == 0) {
276  EC_FSM_ERR(fsm, "Failed to reboot 3\n");
277  ec_datagram_print_wc_error(datagram);
278  return;
279  }
280 
281  // we must delay for a minimum of 1ms before allowing *any* datagram to be
282  // sent on the network, or the slaves may not actually reboot (due to a
283  // hardware bug). we must wait at least 2 cycles to guarantee no undershoot.
284  fsm->jiffies_timeout = datagram->jiffies_received + max(2, HZ/1000);
285  datagram->state = EC_DATAGRAM_INVALID; // do not send a new datagram
287 }
288 
289 /*****************************************************************************/
290 
297 {
298  ec_datagram_t *datagram = fsm->datagram;
299 
300  if (time_after(jiffies, fsm->jiffies_timeout)) {
301  // slave should have rebooted by now, if it supports this. if it
302  // does, the master FSM will detect a topology change (unless it
303  // finished reset already).
305  return;
306  }
307 
308  // we cannot allow any datagrams to be sent while we're waiting, or the
309  // slaves might fail to reboot. this will not absolutely block datagrams
310  // without a bit wider cooperation but it should work in most cases.
311  datagram->state = EC_DATAGRAM_INVALID;
312 }
313 
314 /*****************************************************************************/
315 
322 {
323 }
324 
325 /*****************************************************************************/
326 
333 {
334 }
335 
336 /*****************************************************************************/
ec_slave_t * slave
slave the FSM runs on, if "single"
Definition: fsm_reboot.h:56
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:59
void ec_fsm_reboot_all(ec_fsm_reboot_t *fsm, ec_master_t *master)
Starts the reboot state machine for all slaves on a master.
Definition: fsm_reboot.c:107
EtherCAT slave reboot FSM.
void ec_fsm_reboot_state_two(ec_fsm_reboot_t *)
Reboot state: TWO.
Definition: fsm_reboot.c:220
void(* state)(ec_fsm_reboot_t *)
slave reboot state function
Definition: fsm_reboot.h:61
int ec_fsm_reboot_success(ec_fsm_reboot_t *fsm)
Returns, if the state machine terminated with success.
Definition: fsm_reboot.c:138
ec_master_t * master
master the FSM runs on, if "all"
Definition: fsm_reboot.h:55
EtherCAT datagram.
Definition: datagram.h:88
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2642
uint16_t working_counter
Working counter.
Definition: datagram.h:100
uint16_t station_address
Configured station address.
Definition: slave.h:222
void ec_fsm_reboot_state_start(ec_fsm_reboot_t *)
Reboot state: START.
Definition: fsm_reboot.c:151
Global definitions and macros.
EtherCAT master structure.
EtherCAT slave.
Definition: slave.h:214
EtherCAT slave reboot FSM.
Definition: fsm_reboot.h:53
ec_datagram_state_t state
State.
Definition: datagram.h:101
void ec_fsm_reboot_state_end(ec_fsm_reboot_t *)
State: END.
Definition: fsm_reboot.c:331
unsigned int retries
retries upon datagram timeout
Definition: fsm_reboot.h:58
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:627
int ec_fsm_reboot_exec(ec_fsm_reboot_t *fsm)
Executes the current state of the state machine.
Definition: fsm_reboot.c:123
ec_master_t * master
Master owning the slave.
Definition: slave.h:216
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
void ec_fsm_reboot_init(ec_fsm_reboot_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_reboot.c:68
void ec_fsm_reboot_single(ec_fsm_reboot_t *fsm, ec_slave_t *slave)
Starts the reboot state machine for a single slave.
Definition: fsm_reboot.c:92
void ec_fsm_reboot_state_three(ec_fsm_reboot_t *)
Reboot state: THREE.
Definition: fsm_reboot.c:259
unsigned long jiffies_timeout
pause timer
Definition: fsm_reboot.h:59
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:63
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:587
void ec_fsm_reboot_state_one(ec_fsm_reboot_t *)
Reboot state: ONE.
Definition: fsm_reboot.c:175
void ec_fsm_reboot_state_error(ec_fsm_reboot_t *)
State: ERROR.
Definition: fsm_reboot.c:320
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_reboot.h:57
Timed out (dequeued).
Definition: datagram.h:79
void ec_fsm_reboot_state_wait(ec_fsm_reboot_t *)
Reboot state: WAIT.
Definition: fsm_reboot.c:295
uint8_t * data
Datagram payload.
Definition: datagram.h:95
Unused and should not be queued (dequeued).
Definition: datagram.h:81
Received (dequeued).
Definition: datagram.h:78
#define EC_MASTER_INFO(master, fmt, args...)
Convenience macro for printing master-specific information to syslog.
Definition: master.h:68
EtherCAT master.
Definition: master.h:202
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:110
void ec_fsm_reboot_clear(ec_fsm_reboot_t *fsm)
Destructor.
Definition: fsm_reboot.c:82
int ec_datagram_bwr(ec_datagram_t *datagram, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT BWR datagram.
Definition: datagram.c:415