IgH EtherCAT Master  1.7.0
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  fsm->read_word_count = 0;
73 }
74 
75 /****************************************************************************/
76 
82 {
83 }
84 
85 /****************************************************************************/
86 
92  ec_slave_t *slave,
93  uint16_t word_offset,
95  )
96 {
98  fsm->slave = slave;
99  fsm->word_offset = word_offset;
100  fsm->mode = mode;
101  fsm->read_word_count = 0;
102 }
103 
104 /****************************************************************************/
105 
111  ec_slave_t *slave,
112  uint16_t word_offset,
113  const uint16_t *value,
115  )
116 {
118  fsm->slave = slave;
119  fsm->word_offset = word_offset;
120  fsm->mode = mode;
121  memcpy(fsm->value, value, 2);
122 }
123 
124 /****************************************************************************/
125 
132 {
133  fsm->state(fsm);
134 
135  return fsm->state != ec_fsm_sii_state_end
136  && fsm->state != ec_fsm_sii_state_error;
137 }
138 
139 /****************************************************************************/
140 
147 {
148  return fsm->state == ec_fsm_sii_state_end;
149 }
150 
151 /*****************************************************************************
152  * state functions
153  ****************************************************************************/
154 
161  ec_fsm_sii_t *fsm
162  )
163 {
164  ec_datagram_t *datagram = fsm->datagram;
165 
166  // initiate read operation
167  switch (fsm->mode) {
169  ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
170  break;
172  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x502, 4);
173  break;
174  }
175 
176  // 0x0502 (direction)
177  EC_WRITE_U8 (datagram->data, 0x80); // two address octets FIXME (RO)
178 
179  // 0x0503 (trigger operations)
180  EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
181 
182  // Address 0x0504:0x0507 DWORD 32-bit word address
183  // Only the lower 16 bit (0x0504:0x0505) will be used.
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,
233  0x502, 14);
234  break;
236  ec_datagram_fprd(datagram, fsm->slave->station_address,
237  0x502, 14);
238  break;
239  }
240 
241  ec_datagram_zero(datagram);
242  fsm->retries = EC_FSM_RETRIES;
244 }
245 
246 /****************************************************************************/
247 
253  ec_fsm_sii_t *fsm
254  )
255 {
256  ec_datagram_t *datagram = fsm->datagram;
257 
258  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
259  return;
260 
261  if (datagram->state != EC_DATAGRAM_RECEIVED) {
263  EC_SLAVE_ERR(fsm->slave,
264  "Failed to receive SII check/fetch datagram: ");
265  ec_datagram_print_state(datagram);
266  return;
267  }
268 
269  if (datagram->working_counter != 1) {
271  EC_SLAVE_ERR(fsm->slave,
272  "Reception of SII check/fetch datagram failed: ");
273  ec_datagram_print_wc_error(datagram);
274  return;
275  }
276 
277 #ifdef SII_DEBUG
278  EC_SLAVE_DBG(fsm->slave, 0, "checking SII read state:\n");
279  ec_print_data(datagram->data, 10);
280 #endif
281 
282  if (EC_READ_U8(datagram->data + 1) & 0x20) {
283  EC_SLAVE_ERR(fsm->slave, "Error on last command while"
284  " reading from SII word 0x%04x.\n", fsm->word_offset);
286  return;
287  }
288 
289  // check "busy bit" 0x0503.7
290  if (EC_READ_U8(datagram->data + 1) & 0x81) { /* busy bit or
291  read operation busy */
292  // still busy... timeout?
293  unsigned long diff_ms =
294  (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
295  if (diff_ms >= SII_TIMEOUT) {
296  if (fsm->check_once_more) {
297  fsm->check_once_more = 0;
298  } else {
299  EC_SLAVE_ERR(fsm->slave, "SII: Read timeout.\n");
301  return;
302  }
303  }
304 
305  // issue check/fetch datagram again
306  fsm->retries = EC_FSM_RETRIES;
307  return;
308  }
309 
310  // if 0x0502.6 is set, we have read 4 words (instead of 2)
311  fsm->read_word_count = EC_READ_U8(datagram->data) & 0x40 ? 4 : 2;
312  if (fsm->read_word_count > fsm->slave->sii_parallel_words) {
314  }
315 
316  // SII value received.
317  memcpy(fsm->value, datagram->data + 6, fsm->read_word_count * 2);
319 }
320 
321 /****************************************************************************/
322 
329  ec_fsm_sii_t *fsm
330  )
331 {
332  ec_datagram_t *datagram = fsm->datagram;
333 
334  // initiate write operation
335  ec_datagram_fpwr(datagram, fsm->slave->station_address, 0x0502, 8);
336  EC_WRITE_U8 (datagram->data, 0x81); /* two address octets
337  + enable write access */
338  EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
339 
340  // Address 0x0504:0x0507 DWORD 32-bit word address
341  // Only the lower 16 bit (0x0504:0x0505) will be used.
342  EC_WRITE_U32(datagram->data + 2, fsm->word_offset);
343 
344  // Data 0x0508:0x050b
345  // For the write operation only the lower 16 bit (0x0508:0x0509) will be
346  // used.
347  memcpy(datagram->data + 6, fsm->value, 2);
348 
349 #ifdef SII_DEBUG
350  EC_SLAVE_DBG(fsm->slave, 0, "writing SII data:\n");
351  ec_print_data(datagram->data, 8);
352 #endif
353 
354  fsm->retries = EC_FSM_RETRIES;
356 }
357 
358 /****************************************************************************/
359 
365  ec_fsm_sii_t *fsm
366  )
367 {
368  ec_datagram_t *datagram = fsm->datagram;
369 
370  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
371  return;
372 
373  if (datagram->state != EC_DATAGRAM_RECEIVED) {
375  EC_SLAVE_ERR(fsm->slave, "Failed to receive SII write datagram: ");
376  ec_datagram_print_state(datagram);
377  return;
378  }
379 
380  if (datagram->working_counter != 1) {
382  EC_SLAVE_ERR(fsm->slave, "Reception of SII write datagram failed: ");
383  ec_datagram_print_wc_error(datagram);
384  return;
385  }
386 
387  fsm->jiffies_start = datagram->jiffies_sent;
388  fsm->check_once_more = 1;
389 
390  // issue check datagram
391  ec_datagram_fprd(datagram, fsm->slave->station_address, 0x502, 2);
392  ec_datagram_zero(datagram);
393  fsm->retries = EC_FSM_RETRIES;
395 }
396 
397 /****************************************************************************/
398 
404  ec_fsm_sii_t *fsm
405  )
406 {
407  ec_datagram_t *datagram = fsm->datagram;
408  unsigned long diff_ms;
409 
410  if (datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--)
411  return;
412 
413  if (datagram->state != EC_DATAGRAM_RECEIVED) {
415  EC_SLAVE_ERR(fsm->slave,
416  "Failed to receive SII write check datagram: ");
417  ec_datagram_print_state(datagram);
418  return;
419  }
420 
421  if (datagram->working_counter != 1) {
423  EC_SLAVE_ERR(fsm->slave,
424  "Reception of SII write check datagram failed: ");
425  ec_datagram_print_wc_error(datagram);
426  return;
427  }
428 
429 #ifdef SII_DEBUG
430  EC_SLAVE_DBG(fsm->slave, 0, "checking SII write state:\n");
431  ec_print_data(datagram->data, 2);
432 #endif
433 
434  if (EC_READ_U8(datagram->data + 1) & 0x20) {
435  EC_SLAVE_ERR(fsm->slave, "SII: Error on last SII command!\n");
437  return;
438  }
439 
440  /* FIXME: some slaves never answer with the busy flag set...
441  * wait a few ms for the write operation to complete. */
442  diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
443  if (diff_ms < SII_INHIBIT) {
444 #ifdef SII_DEBUG
445  EC_SLAVE_DBG(fsm->slave, 0, "too early.\n");
446 #endif
447  // issue check datagram again
448  fsm->retries = EC_FSM_RETRIES;
449  return;
450  }
451 
452  if (EC_READ_U8(datagram->data + 1) & 0x82) { /* busy bit or write
453  operation busy bit */
454  // still busy... timeout?
455  if (diff_ms >= SII_TIMEOUT) {
456  if (fsm->check_once_more) {
457  fsm->check_once_more = 0;
458  } else {
459  EC_SLAVE_ERR(fsm->slave, "SII: Write timeout.\n");
461  return;
462  }
463  }
464 
465  // issue check datagram again
466  fsm->retries = EC_FSM_RETRIES;
467  return;
468  }
469 
470  if (EC_READ_U8(datagram->data + 1) & 0x40) {
471  EC_SLAVE_ERR(fsm->slave, "SII: Write operation failed!\n");
473  return;
474  }
475 
476  // success
478 }
479 
480 /****************************************************************************/
481 
487  ec_fsm_sii_t *fsm
488  )
489 {
490 }
491 
492 /****************************************************************************/
493 
499  ec_fsm_sii_t *fsm
500  )
501 {
502 }
503 
504 /****************************************************************************/
#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:176
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:99
void ec_fsm_sii_state_end(ec_fsm_sii_t *)
State: END.
Definition: fsm_sii.c:498
#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:486
void ec_fsm_sii_state_start_reading(ec_fsm_sii_t *)
SII state: START READING.
Definition: fsm_sii.c:160
unsigned long jiffies_start
Start timestamp.
Definition: fsm_sii.h:64
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:110
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3298
#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:177
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:57
EtherCAT slave.
Definition: slave.h:169
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
unsigned int read_word_count
Number of words that have been read.
Definition: fsm_sii.h:63
void(* state)(ec_fsm_sii_t *)
SII state function.
Definition: fsm_sii.h:59
ec_datagram_state_t state
State.
Definition: datagram.h:94
#define EC_WRITE_U32(DATA, VAL)
Write a 32-bit unsigned value to EtherCAT data.
Definition: ecrt.h:3332
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:69
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *)
SII state: WRITE CHECK.
Definition: fsm_sii.c:364
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:3315
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:65
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:91
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:81
EtherCAT slave information interface FSM structure.
uint8_t value[8]
raw SII value (32 bit / 64 bit)
Definition: fsm_sii.h:62
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition: fsm_sii.c:131
int ec_fsm_sii_success(ec_fsm_sii_t *fsm)
Returns, if the master startup state machine terminated with success.
Definition: fsm_sii.c:146
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: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:328
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:3190
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:252
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:403
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
unsigned int sii_parallel_words
How many SII words the slave can read at once.
Definition: slave.h:214