IgH EtherCAT Master  1.5.2
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_LOAD_TIMEOUT 500
50 
58 #define SII_TIMEOUT 20
59 
62 #define SII_INHIBIT 5
63 
64 //#define SII_DEBUG
65 
66 /*****************************************************************************/
67 
76 
77 /*****************************************************************************/
78 
84  )
85 {
86  fsm->state = NULL;
87  fsm->datagram = NULL;
88 }
89 
90 /*****************************************************************************/
91 
97 {
98 }
99 
100 /*****************************************************************************/
101 
107  ec_slave_t *slave,
108  uint16_t word_offset,
110  )
111 {
113  fsm->slave = slave;
114  fsm->word_offset = word_offset;
115  fsm->mode = mode;
116 }
117 
118 /*****************************************************************************/
119 
125  ec_slave_t *slave,
126  uint16_t word_offset,
127  const uint16_t *value,
129  )
130 {
132  fsm->slave = slave;
133  fsm->word_offset = word_offset;
134  fsm->mode = mode;
135  memcpy(fsm->value, value, 2);
136 }
137 
138 /*****************************************************************************/
139 
146  ec_datagram_t *datagram
147  )
148 {
150  return 0;
151  if (fsm->datagram &&
152  (fsm->datagram->state == EC_DATAGRAM_INIT ||
153  fsm->datagram->state == EC_DATAGRAM_QUEUED ||
154  fsm->datagram->state == EC_DATAGRAM_SENT)) {
155  // datagram not received yet
156  if (datagram != fsm->datagram)
157  datagram->state = EC_DATAGRAM_INVALID;
158  return 1;
159  }
160 
161  fsm->state(fsm, datagram);
162 
163  if (fsm->state == ec_fsm_sii_state_end || fsm->state == ec_fsm_sii_state_error) {
164  fsm->datagram = NULL;
165  return 0;
166  }
167 
168  fsm->datagram = datagram;
169  return 1;
170 }
171 
172 /*****************************************************************************/
173 
180 {
181  return fsm->state == ec_fsm_sii_state_end;
182 }
183 
184 /******************************************************************************
185  * datagram functions
186  *****************************************************************************/
187 
189  ec_fsm_sii_t *fsm,
190  ec_datagram_t *datagram
191  )
192 {
193  // initiate read operation
194  switch (fsm->mode) {
196  ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
197  break;
199  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 4);
200  break;
201  }
202 
203  EC_WRITE_U8 (datagram->data, 0x80); // two address octets
204  EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
205  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
206 }
207 
208 /*****************************************************************************/
209 
211  ec_fsm_sii_t *fsm,
212  ec_datagram_t *datagram
213  )
214 {
215  // issue check/fetch datagram
216  switch (fsm->mode) {
218  ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
219  break;
221  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 10);
222  break;
223  }
224 
225  ec_datagram_zero(datagram);
226 }
227 
228 /*****************************************************************************/
229 
231  ec_fsm_sii_t *fsm,
232  ec_datagram_t *datagram
233  )
234 {
235  // initiate write operation
236  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 8);
237  EC_WRITE_U8 (datagram->data, 0x81); /* two address octets
238  + enable write access */
239  EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
240  EC_WRITE_U16(datagram->data + 2, fsm->word_offset);
241  memset(datagram->data + 4, 0x00, 2);
242  memcpy(datagram->data + 6, fsm->value, 2);
243 }
244 
245 /*****************************************************************************/
246 
248  ec_fsm_sii_t *fsm,
249  ec_datagram_t *datagram
250  )
251 {
252  // issue check datagram
253  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 2);
254  ec_datagram_zero(datagram);
255 }
256 
257 /******************************************************************************
258  * state functions
259  *****************************************************************************/
260 
267  ec_fsm_sii_t *fsm,
268  ec_datagram_t *datagram
269  )
270 {
271  ec_fsm_sii_prepare_read(fsm, datagram);
272 
273 #ifdef SII_DEBUG
274  EC_SLAVE_DBG(fsm->slave, 0, "reading SII data, word %u:\n",
275  fsm->word_offset);
276  ec_print_data(datagram->data, 4);
277 #endif
278 
279  fsm->retries = EC_FSM_RETRIES;
281 }
282 
283 /*****************************************************************************/
284 
291  ec_fsm_sii_t *fsm,
292  ec_datagram_t *datagram
293  )
294 {
295  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
296  ec_fsm_sii_prepare_read(fsm, datagram);
297  return;
298  }
299 
300  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
302  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII read datagram: ");
304  return;
305  }
306 
307  if (fsm->datagram->working_counter != 1) {
309  EC_SLAVE_ERR(fsm->slave, "Reception of SII read datagram failed: ");
311  return;
312  }
313 
314  fsm->jiffies_start = fsm->datagram->jiffies_sent;
315  fsm->check_once_more = 1;
316  fsm->eeprom_load_retry = 0;
317 
318  ec_fsm_sii_prepare_read_check(fsm, datagram);
319  fsm->retries = EC_FSM_RETRIES;
321 }
322 
323 /*****************************************************************************/
324 
330  ec_fsm_sii_t *fsm,
331  ec_datagram_t *datagram
332  )
333 {
334  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
335  ec_fsm_sii_prepare_read_check(fsm, datagram);
336  return;
337  }
338 
339  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
341  EC_SLAVE_ERR(fsm->slave,
342  "Failed to receive SII check/fetch datagram: ");
344  return;
345  }
346 
347  if (fsm->datagram->working_counter != 1) {
349  EC_SLAVE_ERR(fsm->slave,
350  "Reception of SII check/fetch datagram failed: ");
352  return;
353  }
354 
355 #ifdef SII_DEBUG
356  EC_SLAVE_DBG(fsm->slave, 0, "checking SII read state:\n");
357  ec_print_data(fsm->datagram->data, 10);
358 #endif
359 
360  if (EC_READ_U8(fsm->datagram->data + 1) & 0x20) {
361  EC_SLAVE_ERR(fsm->slave, "Error on last command while"
362  " reading from SII word 0x%04x.\n", fsm->word_offset);
364  return;
365  }
366 
367  // check "EEPROM Loading bit"
368  if (EC_READ_U8(fsm->datagram->data + 1) & 0x10) { /* EEPROM not loaded */
369  unsigned long diff_ms;
370 
371  if (fsm->eeprom_load_retry == 0) {
372  fsm->eeprom_load_retry = 1;
373  EC_SLAVE_WARN(fsm->slave,
374  "SII Read Error, EEPROM not loaded. Retrying...\n");
375  }
376 
377  // EEPROM still not loaded... timeout?
378  // May be due to an EEPROM load error
379  diff_ms =
380  (fsm->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
381  if (diff_ms >= SII_LOAD_TIMEOUT) {
382  if (fsm->check_once_more) {
383  fsm->check_once_more = 0;
384  } else {
385  EC_SLAVE_ERR(fsm->slave,
386  "SII Error: Timeout waiting for EEPROM to load.\n");
388  return;
389  }
390  }
391 
392  // issue check/fetch datagram again
393  ec_fsm_sii_prepare_read_check(fsm, datagram);
394  fsm->retries = EC_FSM_RETRIES;
395  return;
396  } else if (fsm->eeprom_load_retry) {
397  fsm->eeprom_load_retry = 0;
398  EC_SLAVE_INFO(fsm->slave, "SII EEPROM loaded. Continuing.\n");
399 
400  // start reading SII value again
402  return;
403  }
404 
405  // check "busy bit"
406  if (EC_READ_U8(fsm->datagram->data + 1) & 0x81) { /* busy bit or
407  read operation busy */
408  // still busy... timeout?
409  unsigned long diff_ms =
410  (fsm->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
411  if (diff_ms >= SII_TIMEOUT) {
412  if (fsm->check_once_more) {
413  fsm->check_once_more = 0;
414  } else {
415  EC_SLAVE_ERR(fsm->slave, "SII: Read timeout.\n");
417  return;
418  }
419  }
420 
421  // issue check/fetch datagram again
422  ec_fsm_sii_prepare_read_check(fsm, datagram);
423  fsm->retries = EC_FSM_RETRIES;
424  return;
425  }
426 
427  // SII value received.
428  memcpy(fsm->value, fsm->datagram->data + 6, 4);
430 }
431 
432 /*****************************************************************************/
433 
440  ec_fsm_sii_t *fsm,
441  ec_datagram_t *datagram
442  )
443 {
444  ec_fsm_sii_prepare_write(fsm, datagram);
445 
446 #ifdef SII_DEBUG
447  EC_SLAVE_DBG(fsm->slave, 0, "writing SII data:\n");
448  ec_print_data(datagram->data, 8);
449 #endif
450 
451  fsm->retries = EC_FSM_RETRIES;
453 }
454 
455 /*****************************************************************************/
456 
462  ec_fsm_sii_t *fsm,
463  ec_datagram_t *datagram
464  )
465 {
466  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
467  ec_fsm_sii_prepare_write(fsm, datagram);
468  return;
469  }
470 
471  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
473  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII write datagram: ");
475  return;
476  }
477 
478  if (fsm->datagram->working_counter != 1) {
480  EC_SLAVE_ERR(fsm->slave, "Reception of SII write datagram failed: ");
482  return;
483  }
484 
485  fsm->jiffies_start = fsm->datagram->jiffies_sent;
486  fsm->check_once_more = 1;
487 
488  ec_fsm_sii_prepare_write_check(fsm, datagram);
489  fsm->retries = EC_FSM_RETRIES;
491 }
492 
493 /*****************************************************************************/
494 
500  ec_fsm_sii_t *fsm,
501  ec_datagram_t *datagram
502  )
503 {
504  unsigned long diff_ms;
505 
506  if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
507  ec_fsm_sii_prepare_write_check(fsm, datagram);
508  return;
509  }
510 
511  if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
513  EC_SLAVE_ERR(fsm->slave,
514  "Failed to receive SII write check datagram: ");
516  return;
517  }
518 
519  if (fsm->datagram->working_counter != 1) {
521  EC_SLAVE_ERR(fsm->slave,
522  "Reception of SII write check datagram failed: ");
524  return;
525  }
526 
527 #ifdef SII_DEBUG
528  EC_SLAVE_DBG(fsm->slave, 0, "checking SII write state:\n");
529  ec_print_data(fsm->datagram->data, 2);
530 #endif
531 
532  if (EC_READ_U8(fsm->datagram->data + 1) & 0x20) {
533  EC_SLAVE_ERR(fsm->slave, "SII: Error on last SII command!\n");
535  return;
536  }
537 
538  /* FIXME: some slaves never answer with the busy flag set...
539  * wait a few ms for the write operation to complete. */
540  diff_ms = (fsm->datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
541  if (diff_ms < SII_INHIBIT) {
542 #ifdef SII_DEBUG
543  EC_SLAVE_DBG(fsm->slave, 0, "too early.\n");
544 #endif
545  // issue check datagram again
546  fsm->retries = EC_FSM_RETRIES;
547  return;
548  }
549 
550  if (EC_READ_U8(fsm->datagram->data + 1) & 0x82) { /* busy bit or
551  write operation busy bit */
552  // still busy... timeout?
553  if (diff_ms >= SII_TIMEOUT) {
554  if (fsm->check_once_more) {
555  fsm->check_once_more = 0;
556  } else {
557  EC_SLAVE_ERR(fsm->slave, "SII: Write timeout.\n");
559  return;
560  }
561  }
562 
563  // issue check datagram again
564  ec_fsm_sii_prepare_write_check(fsm, datagram);
565  fsm->retries = EC_FSM_RETRIES;
566  return;
567  }
568 
569  if (EC_READ_U8(fsm->datagram->data + 1) & 0x40) {
570  EC_SLAVE_ERR(fsm->slave, "SII: Write operation failed!\n");
572  return;
573  }
574 
575  // success
577 }
578 
579 /*****************************************************************************/
580 
586  ec_fsm_sii_t *fsm,
587  ec_datagram_t *datagram
588  )
589 {
590 }
591 
592 /*****************************************************************************/
593 
599  ec_fsm_sii_t *fsm,
600  ec_datagram_t *datagram
601  )
602 {
603 }
604 
605 /*****************************************************************************/
static void ec_fsm_sii_prepare_write(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Definition: fsm_sii.c:230
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:59
uint16_t ring_position
Ring position.
Definition: slave.h:221
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:105
void ec_fsm_sii_state_end(ec_fsm_sii_t *, ec_datagram_t *)
State: END.
Definition: fsm_sii.c:598
void ec_fsm_sii_state_error(ec_fsm_sii_t *, ec_datagram_t *)
State: ERROR.
Definition: fsm_sii.c:585
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:108
#define SII_TIMEOUT
Read/write timeout [ms].
Definition: fsm_sii.c:58
void ec_fsm_sii_state_start_writing(ec_fsm_sii_t *, ec_datagram_t *)
SII state: START WRITING.
Definition: fsm_sii.c:439
void(* state)(ec_fsm_sii_t *, ec_datagram_t *)
SII state function.
Definition: fsm_sii.h:67
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
static void ec_fsm_sii_prepare_read_check(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Definition: fsm_sii.c:210
#define EC_SLAVE_WARN(slave, fmt, args...)
Convenience macro for printing slave-specific warnings to syslog.
Definition: slave.h:91
uint16_t word_offset
input: word offset in SII
Definition: fsm_sii.h:68
EtherCAT datagram.
Definition: datagram.h:88
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:124
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2642
#define SII_INHIBIT
Time before evaluating answer at writing [ms].
Definition: fsm_sii.c:62
uint16_t working_counter
Working counter.
Definition: datagram.h:100
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Executes the SII state machine.
Definition: fsm_sii.c:145
Sent (still in the queue).
Definition: datagram.h:77
uint16_t station_address
Configured station address.
Definition: slave.h:222
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:211
void ec_fsm_sii_state_read_fetch(ec_fsm_sii_t *, ec_datagram_t *)
SII state: READ FETCH.
Definition: fsm_sii.c:329
Global definitions and macros.
EtherCAT master structure.
Initial state of a new datagram.
Definition: datagram.h:75
unsigned int retries
retries upon datagram timeout
Definition: fsm_sii.h:65
EtherCAT slave.
Definition: slave.h:214
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:232
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:179
ec_datagram_state_t state
State.
Definition: datagram.h:101
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:77
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:627
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2659
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_sii_state_start_reading(ec_fsm_sii_t *, ec_datagram_t *)
SII state: START READING.
Definition: fsm_sii.c:266
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:295
void ec_fsm_sii_state_write_check2(ec_fsm_sii_t *, ec_datagram_t *)
SII state: WRITE CHECK 2.
Definition: fsm_sii.c:499
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:106
#define EC_SLAVE_INFO(slave, fmt, args...)
Convenience macro for printing slave-specific information to syslog.
Definition: slave.h:63
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:355
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:96
EtherCAT slave information interface FSM structure.
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:179
void ec_datagram_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:587
Mailbox functionality.
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *, ec_datagram_t *)
SII state: WRITE CHECK.
Definition: fsm_sii.c:461
uint8_t eeprom_load_retry
waiting for eeprom to be loaded
Definition: fsm_sii.h:73
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_sii.h:63
void ec_fsm_sii_init(ec_fsm_sii_t *fsm)
Constructor.
Definition: fsm_sii.c:83
Queued for sending.
Definition: datagram.h:76
Timed out (dequeued).
Definition: datagram.h:79
static void ec_fsm_sii_prepare_read(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Definition: fsm_sii.c:188
uint8_t * data
Datagram payload.
Definition: datagram.h:95
static void ec_fsm_sii_prepare_write_check(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Definition: fsm_sii.c:247
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2538
Unused and should not be queued (dequeued).
Definition: datagram.h:81
ec_fsm_sii_addressing_t mode
reading via APRD or NPRD
Definition: fsm_sii.h:69
Received (dequeued).
Definition: datagram.h:78
Use auto-increment addressing.
Definition: fsm_sii.h:49
void ec_fsm_sii_state_read_check(ec_fsm_sii_t *, ec_datagram_t *)
SII state: READ CHECK.
Definition: fsm_sii.c:290
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:110
#define SII_LOAD_TIMEOUT
EEPROM load timeout [ms].
Definition: fsm_sii.c:49
uint8_t value[4]
raw SII value (32bit)
Definition: fsm_sii.h:70