IgH EtherCAT Master  1.5.3
fsm_sii.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 "mailbox.h"
39 #include "master.h"
40 #include "fsm_sii.h"
41 
49 #define SII_TIMEOUT 20
50 
53 #define SII_INHIBIT 5
54 
55 //#define SII_DEBUG
56 
57 /*****************************************************************************/
58 
67 
68 /*****************************************************************************/
69 
75  ec_datagram_t *datagram
76  )
77 {
78  fsm->state = NULL;
79  fsm->datagram = datagram;
80 }
81 
82 /*****************************************************************************/
83 
89 {
90 }
91 
92 /*****************************************************************************/
93 
99  ec_slave_t *slave,
100  uint16_t word_offset,
102  )
103 {
105  fsm->slave = slave;
106  fsm->word_offset = word_offset;
107  fsm->mode = mode;
108 }
109 
110 /*****************************************************************************/
111 
117  ec_slave_t *slave,
118  uint16_t word_offset,
119  const uint16_t *value,
121  )
122 {
124  fsm->slave = slave;
125  fsm->word_offset = word_offset;
126  fsm->mode = mode;
127  memcpy(fsm->value, value, 2);
128 }
129 
130 /*****************************************************************************/
131 
138 {
139  fsm->state(fsm);
140 
141  return fsm->state != ec_fsm_sii_state_end
142  && fsm->state != ec_fsm_sii_state_error;
143 }
144 
145 /*****************************************************************************/
146 
153 {
154  return fsm->state == ec_fsm_sii_state_end;
155 }
156 
157 /******************************************************************************
158  * state functions
159  *****************************************************************************/
160 
167  ec_fsm_sii_t *fsm
168  )
169 {
170  ec_datagram_t *datagram = fsm->datagram;
171 
172  // initiate read operation
173  switch (fsm->mode) {
175  ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
176  break;
178  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 4);
179  break;
180  }
181 
182  EC_WRITE_U8 (datagram->data, 0x80); // two address octets
183  EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
184  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
185 
186 #ifdef SII_DEBUG
187  EC_SLAVE_DBG(fsm->slave, 0, "reading SII data, word %u:\n",
188  fsm->word_offset);
189  ec_print_data(datagram->data, 4);
190 #endif
191 
192  fsm->retries = EC_FSM_RETRIES;
194 }
195 
196 /*****************************************************************************/
197 
204  ec_fsm_sii_t *fsm
205  )
206 {
207  ec_datagram_t *datagram = fsm->datagram;
208 
209  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
210  return;
211 
212  if (datagram->state != EC_DATAGRAM_RECEIVED) {
214  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII read datagram: ");
215  ec_datagram_print_state(datagram);
216  return;
217  }
218 
219  if (datagram->working_counter != 1) {
221  EC_SLAVE_ERR(fsm->slave, "Reception of SII read datagram failed: ");
222  ec_datagram_print_wc_error(datagram);
223  return;
224  }
225 
226  fsm->jiffies_start = datagram->jiffies_sent;
227  fsm->check_once_more = 1;
228 
229  // issue check/fetch datagram
230  switch (fsm->mode) {
232  ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
233  break;
235  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 10);
236  break;
237  }
238 
239  ec_datagram_zero(datagram);
240  fsm->retries = EC_FSM_RETRIES;
242 }
243 
244 /*****************************************************************************/
245 
251  ec_fsm_sii_t *fsm
252  )
253 {
254  ec_datagram_t *datagram = fsm->datagram;
255 
256  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
257  return;
258 
259  if (datagram->state != EC_DATAGRAM_RECEIVED) {
261  EC_SLAVE_ERR(fsm->slave,
262  "Failed to receive SII check/fetch datagram: ");
263  ec_datagram_print_state(datagram);
264  return;
265  }
266 
267  if (datagram->working_counter != 1) {
269  EC_SLAVE_ERR(fsm->slave,
270  "Reception of SII check/fetch datagram failed: ");
271  ec_datagram_print_wc_error(datagram);
272  return;
273  }
274 
275 #ifdef SII_DEBUG
276  EC_SLAVE_DBG(fsm->slave, 0, "checking SII read state:\n");
277  ec_print_data(datagram->data, 10);
278 #endif
279 
280  if (EC_READ_U8(datagram->data + 1) & 0x20) {
281  EC_SLAVE_ERR(fsm->slave, "Error on last command while"
282  " reading from SII word 0x%04x.\n", fsm->word_offset);
284  return;
285  }
286 
287  // check "busy bit"
288  if (EC_READ_U8(datagram->data + 1) & 0x81) { /* busy bit or
289  read operation busy */
290  // still busy... timeout?
291  unsigned long diff_ms =
292  (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
293  if (diff_ms >= SII_TIMEOUT) {
294  if (fsm->check_once_more) {
295  fsm->check_once_more = 0;
296  } else {
297  EC_SLAVE_ERR(fsm->slave, "SII: Read timeout.\n");
299  return;
300  }
301  }
302 
303  // issue check/fetch datagram again
304  fsm->retries = EC_FSM_RETRIES;
305  return;
306  }
307 
308  // SII value received.
309  memcpy(fsm->value, datagram->data + 6, 4);
311 }
312 
313 /*****************************************************************************/
314 
321  ec_fsm_sii_t *fsm
322  )
323 {
324  ec_datagram_t *datagram = fsm->datagram;
325 
326  // initiate write operation
327  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 8);
328  EC_WRITE_U8 (datagram->data, 0x81); /* two address octets
329  + enable write access */
330  EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
331  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
332  memset(datagram->data + 4, 0x00, 2);
333  memcpy(datagram->data + 6, fsm->value, 2);
334 
335 #ifdef SII_DEBUG
336  EC_SLAVE_DBG(fsm->slave, 0, "writing SII data:\n");
337  ec_print_data(datagram->data, 8);
338 #endif
339 
340  fsm->retries = EC_FSM_RETRIES;
342 }
343 
344 /*****************************************************************************/
345 
351  ec_fsm_sii_t *fsm
352  )
353 {
354  ec_datagram_t *datagram = fsm->datagram;
355 
356  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
357  return;
358 
359  if (datagram->state != EC_DATAGRAM_RECEIVED) {
361  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII write datagram: ");
362  ec_datagram_print_state(datagram);
363  return;
364  }
365 
366  if (datagram->working_counter != 1) {
368  EC_SLAVE_ERR(fsm->slave, "Reception of SII write datagram failed: ");
369  ec_datagram_print_wc_error(datagram);
370  return;
371  }
372 
373  fsm->jiffies_start = datagram->jiffies_sent;
374  fsm->check_once_more = 1;
375 
376  // issue check datagram
377  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 2);
378  ec_datagram_zero(datagram);
379  fsm->retries = EC_FSM_RETRIES;
381 }
382 
383 /*****************************************************************************/
384 
390  ec_fsm_sii_t *fsm
391  )
392 {
393  ec_datagram_t *datagram = fsm->datagram;
394  unsigned long diff_ms;
395 
396  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
397  return;
398 
399  if (datagram->state != EC_DATAGRAM_RECEIVED) {
401  EC_SLAVE_ERR(fsm->slave,
402  "Failed to receive SII write check datagram: ");
403  ec_datagram_print_state(datagram);
404  return;
405  }
406 
407  if (datagram->working_counter != 1) {
409  EC_SLAVE_ERR(fsm->slave,
410  "Reception of SII write check datagram failed: ");
411  ec_datagram_print_wc_error(datagram);
412  return;
413  }
414 
415 #ifdef SII_DEBUG
416  EC_SLAVE_DBG(fsm->slave, 0, "checking SII write state:\n");
417  ec_print_data(datagram->data, 2);
418 #endif
419 
420  if (EC_READ_U8(datagram->data + 1) & 0x20) {
421  EC_SLAVE_ERR(fsm->slave, "SII: Error on last SII command!\n");
423  return;
424  }
425 
426  /* FIXME: some slaves never answer with the busy flag set...
427  * wait a few ms for the write operation to complete. */
428  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
429  if (diff_ms < SII_INHIBIT) {
430 #ifdef SII_DEBUG
431  EC_SLAVE_DBG(fsm->slave, 0, "too early.\n");
432 #endif
433  // issue check datagram again
434  fsm->retries = EC_FSM_RETRIES;
435  return;
436  }
437 
438  if (EC_READ_U8(datagram->data + 1) & 0x82) { /* busy bit or
439  write operation busy bit */
440  // still busy... timeout?
441  if (diff_ms >= SII_TIMEOUT) {
442  if (fsm->check_once_more) {
443  fsm->check_once_more = 0;
444  } else {
445  EC_SLAVE_ERR(fsm->slave, "SII: Write timeout.\n");
447  return;
448  }
449  }
450 
451  // issue check datagram again
452  fsm->retries = EC_FSM_RETRIES;
453  return;
454  }
455 
456  if (EC_READ_U8(datagram->data + 1) & 0x40) {
457  EC_SLAVE_ERR(fsm->slave, "SII: Write operation failed!\n");
459  return;
460  }
461 
462  // success
464 }
465 
466 /*****************************************************************************/
467 
473  ec_fsm_sii_t *fsm
474  )
475 {
476 }
477 
478 /*****************************************************************************/
479 
485  ec_fsm_sii_t *fsm
486  )
487 {
488 }
489 
490 /*****************************************************************************/
#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:183
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:106
void ec_fsm_sii_state_end(ec_fsm_sii_t *)
State: END.
Definition: fsm_sii.c:484
#define SII_TIMEOUT
Read/write timeout [ms].
Definition: fsm_sii.c:49
void ec_fsm_sii_state_error(ec_fsm_sii_t *)
State: ERROR.
Definition: fsm_sii.c:472
void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *)
SII state: START READING.
Definition: fsm_sii.c:166
unsigned long jiffies_start
Start timestamp.
Definition: fsm_sii.h:71
Slave information interface FSM.
Definition: fsm_sii.h:61
ec_fsm_sii_addressing_t
SII access addressing mode.
Definition: fsm_sii.h:48
uint16_t word_offset
input: word offset in SII
Definition: fsm_sii.h:68
EtherCAT datagram.
Definition: datagram.h:87
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:116
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2401
#define SII_INHIBIT
Time before evaluating answer at writing [ms].
Definition: fsm_sii.c:53
uint16_t working_counter
Working counter.
Definition: datagram.h:99
void ec_fsm_sii_init(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_sii.c:74
uint16_t station_address
Configured station address.
Definition: slave.h:184
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:189
Global definitions and macros.
EtherCAT master structure.
unsigned int retries
retries upon datagram timeout
Definition: fsm_sii.h:65
EtherCAT slave.
Definition: slave.h:176
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:210
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
void(* state)(ec_fsm_sii_t *)
SII state function.
Definition: fsm_sii.h:67
ec_datagram_state_t state
State.
Definition: datagram.h:100
Use configured addresses.
Definition: fsm_sii.h:50
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *)
SII state: WRITE CHECK.
Definition: fsm_sii.c:350
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2418
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
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
uint8_t check_once_more
one more try after timeout
Definition: fsm_sii.h:72
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:98
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:348
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:88
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:137
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:152
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
Mailbox functionality.
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_sii.h:63
Timed out (dequeued).
Definition: datagram.h:79
uint8_t * data
Datagram payload.
Definition: datagram.h:94
void ec_fsm_sii_state_start_writing(ec_fsm_sii_t *)
SII state: START WRITING.
Definition: fsm_sii.c:320
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2297
ec_fsm_sii_addressing_t mode
reading via APRD or NPRD
Definition: fsm_sii.h:69
Received (dequeued).
Definition: datagram.h:78
void ec_fsm_sii_state_read_fetch(ec_fsm_sii_t *)
SII state: READ FETCH.
Definition: fsm_sii.c:250
void ec_fsm_sii_state_read_check(ec_fsm_sii_t *)
SII state: READ CHECK.
Definition: fsm_sii.c:203
void ec_fsm_sii_state_write_check2(ec_fsm_sii_t *)
SII state: WRITE CHECK 2.
Definition: fsm_sii.c:389
Use auto-increment addressing.
Definition: fsm_sii.h:49
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_sii.h:64
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
uint8_t value[4]
raw SII value (32bit)
Definition: fsm_sii.h:70