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_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: ");
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: ");
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: ");
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: ");
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/*****************************************************************************/
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition: datagram.c:602
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition: datagram.c:178
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_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition: datagram.c:565
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
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
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition: datagram.h:78
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition: datagram.h:79
#define SII_TIMEOUT
Read/write timeout [ms].
Definition: fsm_sii.c:49
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_fsm_sii_state_write_check2(ec_fsm_sii_t *)
SII state: WRITE CHECK 2.
Definition: fsm_sii.c:389
void ec_fsm_sii_state_end(ec_fsm_sii_t *)
State: END.
Definition: fsm_sii.c:484
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition: fsm_sii.c:88
void ec_fsm_sii_state_read_check(ec_fsm_sii_t *)
SII state: READ CHECK.
Definition: fsm_sii.c:203
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition: fsm_sii.c:137
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_fsm_sii_state_start_reading(ec_fsm_sii_t *)
SII state: START READING.
Definition: fsm_sii.c:166
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *)
SII state: WRITE CHECK.
Definition: fsm_sii.c:350
#define SII_INHIBIT
Time before evaluating answer at writing [ms].
Definition: fsm_sii.c:53
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_start_writing(ec_fsm_sii_t *)
SII state: START WRITING.
Definition: fsm_sii.c:320
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
void ec_fsm_sii_init(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition: fsm_sii.c:74
void ec_fsm_sii_state_error(ec_fsm_sii_t *)
State: ERROR.
Definition: fsm_sii.c:472
EtherCAT slave information interface FSM structure.
ec_fsm_sii_addressing_t
SII access addressing mode.
Definition: fsm_sii.h:48
@ EC_FSM_SII_USE_CONFIGURED_ADDRESS
Use configured addresses.
Definition: fsm_sii.h:50
@ EC_FSM_SII_USE_INCREMENT_ADDRESS
Use auto-increment addressing.
Definition: fsm_sii.h:49
Global definitions and macros.
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition: globals.h:47
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition: module.c:348
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2266
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition: ecrt.h:2162
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition: ecrt.h:2283
Mailbox functionality.
EtherCAT master structure.
#define EC_SLAVE_DBG(slave, level, fmt, args...)
Convenience macro for printing slave-specific debug messages to syslog.
Definition: slave.h:106
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition: slave.h:76
EtherCAT datagram.
Definition: datagram.h:87
uint16_t working_counter
Working counter.
Definition: datagram.h:99
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition: datagram.h:108
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition: datagram.h:104
ec_datagram_state_t state
State.
Definition: datagram.h:100
uint8_t * data
Datagram payload.
Definition: datagram.h:94
Slave information interface FSM.
Definition: fsm_sii.h:62
ec_datagram_t * datagram
datagram used in the state machine
Definition: fsm_sii.h:64
unsigned int retries
retries upon datagram timeout
Definition: fsm_sii.h:65
void(* state)(ec_fsm_sii_t *)
SII state function.
Definition: fsm_sii.h:67
ec_slave_t * slave
slave the FSM runs on
Definition: fsm_sii.h:63
uint8_t check_once_more
one more try after timeout
Definition: fsm_sii.h:72
unsigned long jiffies_start
Start timestamp.
Definition: fsm_sii.h:71
ec_fsm_sii_addressing_t mode
reading via APRD or NPRD
Definition: fsm_sii.h:69
uint8_t value[4]
raw SII value (32bit)
Definition: fsm_sii.h:70
uint16_t word_offset
input: word offset in SII
Definition: fsm_sii.h:68
EtherCAT slave.
Definition: slave.h:177
uint16_t ring_position
Ring position.
Definition: slave.h:183
uint16_t station_address
Configured station address.
Definition: slave.h:184