IgH EtherCAT Master  1.6.9
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
26
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
65
67 ec_datagram_t *datagram
68 )
69{
70 fsm->state = NULL;
71 fsm->datagram = datagram;
72}
73
74/****************************************************************************/
75
79
81{
82}
83
84/****************************************************************************/
85
89
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
107
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
128
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
143
145{
146 return fsm->state == ec_fsm_sii_state_end;
147}
148
149/*****************************************************************************
150 * state functions
151 ****************************************************************************/
152
157
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
194
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: ");
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: ");
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
311
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
341
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: ");
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
380
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: ");
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
463
465 ec_fsm_sii_t *fsm
466 )
467{
468}
469
470/****************************************************************************/
471
475
477 ec_fsm_sii_t *fsm
478 )
479{
480}
481
482/****************************************************************************/
void ec_datagram_print_wc_error(const ec_datagram_t *datagram)
Evaluates the working counter of a single-cast datagram.
Definition datagram.c:594
void ec_datagram_zero(ec_datagram_t *datagram)
Fills the datagram payload memory with zeros.
Definition datagram.c:170
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_print_state(const ec_datagram_t *datagram)
Prints the state of a datagram.
Definition datagram.c:557
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
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
@ EC_DATAGRAM_RECEIVED
Received (dequeued).
Definition datagram.h:70
@ EC_DATAGRAM_TIMED_OUT
Timed out (dequeued).
Definition datagram.h:71
#define SII_TIMEOUT
Read/write timeout [ms].
Definition fsm_sii.c:41
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_fsm_sii_state_write_check2(ec_fsm_sii_t *)
SII state: WRITE CHECK 2.
Definition fsm_sii.c:381
void ec_fsm_sii_state_end(ec_fsm_sii_t *)
State: END.
Definition fsm_sii.c:476
void ec_fsm_sii_clear(ec_fsm_sii_t *fsm)
Destructor.
Definition fsm_sii.c:80
void ec_fsm_sii_state_read_check(ec_fsm_sii_t *)
SII state: READ CHECK.
Definition fsm_sii.c:195
int ec_fsm_sii_exec(ec_fsm_sii_t *fsm)
Executes the SII state machine.
Definition fsm_sii.c:129
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_fsm_sii_state_start_reading(ec_fsm_sii_t *)
SII state: START READING.
Definition fsm_sii.c:158
void ec_fsm_sii_state_write_check(ec_fsm_sii_t *)
SII state: WRITE CHECK.
Definition fsm_sii.c:342
#define SII_INHIBIT
Time before evaluating answer at writing [ms].
Definition fsm_sii.c:45
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_start_writing(ec_fsm_sii_t *)
SII state: START WRITING.
Definition fsm_sii.c:312
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
void ec_fsm_sii_init(ec_fsm_sii_t *fsm, ec_datagram_t *datagram)
Constructor.
Definition fsm_sii.c:66
void ec_fsm_sii_state_error(ec_fsm_sii_t *)
State: ERROR.
Definition fsm_sii.c:464
EtherCAT slave information interface FSM structure.
struct ec_fsm_sii ec_fsm_sii_t
Definition fsm_sii.h:47
ec_fsm_sii_addressing_t
SII access addressing mode.
Definition fsm_sii.h:40
@ EC_FSM_SII_USE_CONFIGURED_ADDRESS
Use configured addresses.
Definition fsm_sii.h:42
@ EC_FSM_SII_USE_INCREMENT_ADDRESS
Use auto-increment addressing.
Definition fsm_sii.h:41
Global definitions and macros.
#define EC_FSM_RETRIES
Number of state machine retries on datagram timeout.
Definition globals.h:47
struct ec_slave ec_slave_t
Definition globals.h:310
void ec_print_data(const uint8_t *, size_t)
Outputs frame contents for debugging purposes.
Definition module.c:344
#define EC_WRITE_U8(DATA, VAL)
Write an 8-bit unsigned value to EtherCAT data.
Definition ecrt.h:3040
#define EC_READ_U8(DATA)
Read an 8-bit unsigned value from EtherCAT data.
Definition ecrt.h:2932
#define EC_WRITE_U16(DATA, VAL)
Write a 16-bit unsigned value to EtherCAT data.
Definition ecrt.h:3057
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:98
#define EC_SLAVE_ERR(slave, fmt, args...)
Convenience macro for printing slave-specific errors to syslog.
Definition slave.h:68
EtherCAT datagram.
Definition datagram.h:79
uint16_t working_counter
Working counter.
Definition datagram.h:93
unsigned long jiffies_received
Jiffies, when the datagram was received.
Definition datagram.h:102
unsigned long jiffies_sent
Jiffies, when the datagram was sent.
Definition datagram.h:98
ec_datagram_state_t state
State.
Definition datagram.h:94
uint8_t * data
Datagram payload.
Definition datagram.h:88
ec_datagram_t * datagram
datagram used in the state machine
Definition fsm_sii.h:56
unsigned int retries
retries upon datagram timeout
Definition fsm_sii.h:57
void(* state)(ec_fsm_sii_t *)
SII state function.
Definition fsm_sii.h:59
ec_slave_t * slave
slave the FSM runs on
Definition fsm_sii.h:55
uint8_t check_once_more
one more try after timeout
Definition fsm_sii.h:64
unsigned long jiffies_start
Start timestamp.
Definition fsm_sii.h:63
ec_fsm_sii_addressing_t mode
reading via APRD or NPRD
Definition fsm_sii.h:61
uint8_t value[4]
raw SII value (32bit)
Definition fsm_sii.h:62
uint16_t word_offset
input: word offset in SII
Definition fsm_sii.h:60
uint16_t ring_position
Ring position.
Definition slave.h:175
uint16_t station_address
Configured station address.
Definition slave.h:176