IgH EtherCAT Master  1.6.1
fsm_sii.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 "mailbox.h"
31 #include "master.h"
32 #include "fsm_sii.h"
33 
41 #define SII_TIMEOUT 20
42 
45 #define SII_INHIBIT 5
46 
47 //#define SII_DEBUG
48 
49 /****************************************************************************/
50 
59 
60 /****************************************************************************/
61 
67  ec_datagram_t *datagram
68  )
69 {
70  fsm->state = NULL;
71  fsm->datagram = datagram;
72 }
73 
74 /****************************************************************************/
75 
81 {
82 }
83 
84 /****************************************************************************/
85 
91  ec_slave_t *slave,
92  uint16_t word_offset,
94  )
95 {
97  fsm->slave = slave;
98  fsm->word_offset = word_offset;
99  fsm->mode = mode;
100 }
101 
102 /****************************************************************************/
103 
109  ec_slave_t *slave,
110  uint16_t word_offset,
111  const uint16_t *value,
113  )
114 {
116  fsm->slave = slave;
117  fsm->word_offset = word_offset;
118  fsm->mode = mode;
119  memcpy(fsm->value, value, 2);
120 }
121 
122 /****************************************************************************/
123 
130 {
131  fsm->state(fsm);
132 
133  return fsm->state != ec_fsm_sii_state_end
134  && fsm->state != ec_fsm_sii_state_error;
135 }
136 
137 /****************************************************************************/
138 
145 {
146  return fsm->state == ec_fsm_sii_state_end;
147 }
148 
149 /*****************************************************************************
150  * state functions
151  ****************************************************************************/
152 
159  ec_fsm_sii_t *fsm
160  )
161 {
162  ec_datagram_t *datagram = fsm->datagram;
163 
164  // initiate read operation
165  switch (fsm->mode) {
167  ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
168  break;
170  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 4);
171  break;
172  }
173 
174  EC_WRITE_U8 (datagram->data, 0x80); // two address octets
175  EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
176  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
177 
178 #ifdef SII_DEBUG
179  EC_SLAVE_DBG(fsm->slave, 0, "reading SII data, word %u:\n",
180  fsm->word_offset);
181  ec_print_data(datagram->data, 4);
182 #endif
183 
184  fsm->retries = EC_FSM_RETRIES;
186 }
187 
188 /****************************************************************************/
189 
196  ec_fsm_sii_t *fsm
197  )
198 {
199  ec_datagram_t *datagram = fsm->datagram;
200 
201  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
202  return;
203 
204  if (datagram->state != EC_DATAGRAM_RECEIVED) {
206  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII read datagram: ");
207  ec_datagram_print_state(datagram);
208  return;
209  }
210 
211  if (datagram->working_counter != 1) {
213  EC_SLAVE_ERR(fsm->slave, "Reception of SII read datagram failed: ");
214  ec_datagram_print_wc_error(datagram);
215  return;
216  }
217 
218  fsm->jiffies_start = datagram->jiffies_sent;
219  fsm->check_once_more = 1;
220 
221  // issue check/fetch datagram
222  switch (fsm->mode) {
224  ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
225  break;
227  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 10);
228  break;
229  }
230 
231  ec_datagram_zero(datagram);
232  fsm->retries = EC_FSM_RETRIES;
234 }
235 
236 /****************************************************************************/
237 
243  ec_fsm_sii_t *fsm
244  )
245 {
246  ec_datagram_t *datagram = fsm->datagram;
247 
248  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
249  return;
250 
251  if (datagram->state != EC_DATAGRAM_RECEIVED) {
253  EC_SLAVE_ERR(fsm->slave,
254  "Failed to receive SII check/fetch datagram: ");
255  ec_datagram_print_state(datagram);
256  return;
257  }
258 
259  if (datagram->working_counter != 1) {
261  EC_SLAVE_ERR(fsm->slave,
262  "Reception of SII check/fetch datagram failed: ");
263  ec_datagram_print_wc_error(datagram);
264  return;
265  }
266 
267 #ifdef SII_DEBUG
268  EC_SLAVE_DBG(fsm->slave, 0, "checking SII read state:\n");
269  ec_print_data(datagram->data, 10);
270 #endif
271 
272  if (EC_READ_U8(datagram->data + 1) & 0x20) {
273  EC_SLAVE_ERR(fsm->slave, "Error on last command while"
274  " reading from SII word 0x%04x.\n", fsm->word_offset);
276  return;
277  }
278 
279  // check "busy bit"
280  if (EC_READ_U8(datagram->data + 1) & 0x81) { /* busy bit or
281  read operation busy */
282  // still busy... timeout?
283  unsigned long diff_ms =
284  (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
285  if (diff_ms >= SII_TIMEOUT) {
286  if (fsm->check_once_more) {
287  fsm->check_once_more = 0;
288  } else {
289  EC_SLAVE_ERR(fsm->slave, "SII: Read timeout.\n");
291  return;
292  }
293  }
294 
295  // issue check/fetch datagram again
296  fsm->retries = EC_FSM_RETRIES;
297  return;
298  }
299 
300  // SII value received.
301  memcpy(fsm->value, datagram->data + 6, 4);
303 }
304 
305 /****************************************************************************/
306 
313  ec_fsm_sii_t *fsm
314  )
315 {
316  ec_datagram_t *datagram = fsm->datagram;
317 
318  // initiate write operation
319  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 8);
320  EC_WRITE_U8 (datagram->data, 0x81); /* two address octets
321  + enable write access */
322  EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
323  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
324  memset(datagram->data + 4, 0x00, 2);
325  memcpy(datagram->data + 6, fsm->value, 2);
326 
327 #ifdef SII_DEBUG
328  EC_SLAVE_DBG(fsm->slave, 0, "writing SII data:\n");
329  ec_print_data(datagram->data, 8);
330 #endif
331 
332  fsm->retries = EC_FSM_RETRIES;
334 }
335 
336 /****************************************************************************/
337 
343  ec_fsm_sii_t *fsm
344  )
345 {
346  ec_datagram_t *datagram = fsm->datagram;
347 
348  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
349  return;
350 
351  if (datagram->state != EC_DATAGRAM_RECEIVED) {
353  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII write datagram: ");
354  ec_datagram_print_state(datagram);
355  return;
356  }
357 
358  if (datagram->working_counter != 1) {
360  EC_SLAVE_ERR(fsm->slave, "Reception of SII write datagram failed: ");
361  ec_datagram_print_wc_error(datagram);
362  return;
363  }
364 
365  fsm->jiffies_start = datagram->jiffies_sent;
366  fsm->check_once_more = 1;
367 
368  // issue check datagram
369  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 2);
370  ec_datagram_zero(datagram);
371  fsm->retries = EC_FSM_RETRIES;
373 }
374 
375 /****************************************************************************/
376 
382  ec_fsm_sii_t *fsm
383  )
384 {
385  ec_datagram_t *datagram = fsm->datagram;
386  unsigned long diff_ms;
387 
388  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
389  return;
390 
391  if (datagram->state != EC_DATAGRAM_RECEIVED) {
393  EC_SLAVE_ERR(fsm->slave,
394  "Failed to receive SII write check datagram: ");
395  ec_datagram_print_state(datagram);
396  return;
397  }
398 
399  if (datagram->working_counter != 1) {
401  EC_SLAVE_ERR(fsm->slave,
402  "Reception of SII write check datagram failed: ");
403  ec_datagram_print_wc_error(datagram);
404  return;
405  }
406 
407 #ifdef SII_DEBUG
408  EC_SLAVE_DBG(fsm->slave, 0, "checking SII write state:\n");
409  ec_print_data(datagram->data, 2);
410 #endif
411 
412  if (EC_READ_U8(datagram->data + 1) & 0x20) {
413  EC_SLAVE_ERR(fsm->slave, "SII: Error on last SII command!\n");
415  return;
416  }
417 
418  /* FIXME: some slaves never answer with the busy flag set...
419  * wait a few ms for the write operation to complete. */
420  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
421  if (diff_ms < SII_INHIBIT) {
422 #ifdef SII_DEBUG
423  EC_SLAVE_DBG(fsm->slave, 0, "too early.\n");
424 #endif
425  // issue check datagram again
426  fsm->retries = EC_FSM_RETRIES;
427  return;
428  }
429 
430  if (EC_READ_U8(datagram->data + 1) & 0x82) { /* busy bit or
431  write operation busy bit */
432  // still busy... timeout?
433  if (diff_ms >= SII_TIMEOUT) {
434  if (fsm->check_once_more) {
435  fsm->check_once_more = 0;
436  } else {
437  EC_SLAVE_ERR(fsm->slave, "SII: Write timeout.\n");
439  return;
440  }
441  }
442 
443  // issue check datagram again
444  fsm->retries = EC_FSM_RETRIES;
445  return;
446  }
447 
448  if (EC_READ_U8(datagram->data + 1) & 0x40) {
449  EC_SLAVE_ERR(fsm->slave, "SII: Write operation failed!\n");
451  return;
452  }
453 
454  // success
456 }
457 
458 /****************************************************************************/
459 
465  ec_fsm_sii_t *fsm
466  )
467 {
468 }
469 
470 /****************************************************************************/
471 
477  ec_fsm_sii_t *fsm
478  )
479 {
480 }
481 
482 /****************************************************************************/
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
uint16_t ring_position
Ring position.
Definition: slave.h:175
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:98
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:98
void ec_fsm_sii_state_end(ec_fsm_sii_t *)
State: END.
Definition: fsm_sii.c:476
#define SII_TIMEOUT
Read/write timeout [ms].
Definition: fsm_sii.c:41
void ec_fsm_sii_state_error(ec_fsm_sii_t *)
State: ERROR.
Definition: fsm_sii.c:464
void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *)
SII state: START READING.
Definition: fsm_sii.c:158
unsigned long jiffies_start
Start timestamp.
Definition: fsm_sii.h:63
Slave information interface FSM.
Definition: fsm_sii.h:53
ec_fsm_sii_addressing_t
SII access addressing mode.
Definition: fsm_sii.h:40
uint16_t word_offset
input: word offset in SII
Definition: fsm_sii.h:60
EtherCAT datagram.
Definition: datagram.h:79
void ec_fsm_sii_write(ec_fsm_sii_t *fsm, ec_slave_t *slave, uint16_t word_offset, const uint16_t *value, ec_fsm_sii_addressing_t mode)
Initializes the SII write state machine.
Definition: fsm_sii.c:108
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3137
#define SII_INHIBIT
Time before evaluating answer at writing [ms].
Definition: fsm_sii.c:45
uint16_t working_counter
Working counter.
Definition: datagram.h:93
void ec_fsm_sii_init(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_sii.c:66
uint16_t station_address
Configured station address.
Definition: slave.h:176
int ec_datagram_aprd(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APRD datagram.
Definition: datagram.c:181
Global definitions and macros.
EtherCAT master structure.
unsigned int retries
retries upon datagram timeout
Definition: fsm_sii.h:57
EtherCAT slave.
Definition: slave.h:168
int ec_datagram_apwr(ec_datagram_t *datagram, uint16_t ring_position, uint16_t mem_address, size_t data_size)
Initializes an EtherCAT APWR datagram.
Definition: datagram.c:202
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:170
void(* state)(ec_fsm_sii_t *)
SII state function.
Definition: fsm_sii.h:59
ec_datagram_state_t state
State.
Definition: datagram.h:94
Use configured addresses.
Definition: fsm_sii.h:42
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:68
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *)
SII state: WRITE CHECK.
Definition: fsm_sii.c:342
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:594
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3154
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
uint8_t check_once_more
one more try after timeout
Definition: fsm_sii.h:64
void ec_fsm_sii_read(ec_fsm_sii_t *fsm, ec_slave_t *slave, uint16_t word_offset, ec_fsm_sii_addressing_t mode)
Initializes the SII read state machine.
Definition: fsm_sii.c:90
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:344
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:80
EtherCAT slave information interface FSM structure.
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition: fsm_sii.c:129
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:144
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:557
Mailbox functionality.
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_sii.h:55
Timed out (dequeued).
Definition: datagram.h:71
uint8_t * data
Datagram payload.
Definition: datagram.h:88
void ec_fsm_sii_state_start_writing(ec_fsm_sii_t *)
SII state: START WRITING.
Definition: fsm_sii.c:312
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3029
ec_fsm_sii_addressing_t mode
reading via APRD or NPRD
Definition: fsm_sii.h:61
Received (dequeued).
Definition: datagram.h:70
void ec_fsm_sii_state_read_fetch(ec_fsm_sii_t *)
SII state: READ FETCH.
Definition: fsm_sii.c:242
void ec_fsm_sii_state_read_check(ec_fsm_sii_t *)
SII state: READ CHECK.
Definition: fsm_sii.c:195
void ec_fsm_sii_state_write_check2(ec_fsm_sii_t *)
SII state: WRITE CHECK 2.
Definition: fsm_sii.c:381
Use auto-increment addressing.
Definition: fsm_sii.h:41
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_sii.h:56
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:102
uint8_t value[4]
raw SII value (32bit)
Definition: fsm_sii.h:62