Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/******************************************************************************
*
* $Id: fsm_coe.c 920 2007-09-12 10:07:55Z fp $
*
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
* The IgH EtherCAT Master is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The IgH EtherCAT Master is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the IgH EtherCAT Master; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* The right to use EtherCAT Technology is granted and comes free of
* charge under condition of compatibility of product made by
* Licensee. People intending to distribute/sell products based on the
* code, have to sign an agreement to guarantee that products using
* software based on IgH EtherCAT master stay compatible with the actual
* EtherCAT specification (which are released themselves as an open
* standard) as the (only) precondition to have the right to use EtherCAT
* Technology, IP and trade marks.
*
*****************************************************************************/
/**
\file
EtherCAT CoE mapping state machines.
*/
/*****************************************************************************/
#include "globals.h"
#include "master.h"
#include "mailbox.h"
#include "canopen.h"
#include "fsm_coe_map.h"
/*****************************************************************************/
void ec_fsm_coe_map_state_start(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_pdo_count(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_pdo(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_pdo_entry_count(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_pdo_entry(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_end(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_state_error(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_action_next_sync(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_action_next_pdo(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_action_next_pdo_entry(ec_fsm_coe_map_t *);
void ec_fsm_coe_map_clear_pdos(ec_fsm_coe_map_t *);
/*****************************************************************************/
/**
Constructor.
*/
void ec_fsm_coe_map_init(
ec_fsm_coe_map_t *fsm, /**< finite state machine */
ec_fsm_coe_t *fsm_coe /**< CoE state machine to use */
)
{
fsm->state = NULL;
fsm->fsm_coe = fsm_coe;
INIT_LIST_HEAD(&fsm->pdos);
}
/*****************************************************************************/
/**
Destructor.
*/
void ec_fsm_coe_map_clear(ec_fsm_coe_map_t *fsm /**< finite state machine */)
{
ec_fsm_coe_map_clear_pdos(fsm);
}
/*****************************************************************************/
/**
*/
void ec_fsm_coe_map_clear_pdos(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
ec_pdo_t *pdo, *next;
// free all PDOs
list_for_each_entry_safe(pdo, next, &fsm->pdos, list) {
list_del(&pdo->list);
ec_pdo_clear(pdo);
kfree(pdo);
}
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
}
/*****************************************************************************/
/**
Starts to upload an SDO from a slave.
*/
void ec_fsm_coe_map_start(
ec_fsm_coe_map_t *fsm, /**< finite state machine */
ec_slave_t *slave /**< EtherCAT slave */
)
{
fsm->slave = slave;
fsm->state = ec_fsm_coe_map_state_start;
}
/*****************************************************************************/
/**
Executes the current state of the state machine.
\return false, if state machine has terminated
*/
int ec_fsm_coe_map_exec(ec_fsm_coe_map_t *fsm /**< finite state machine */)
{
fsm->state(fsm);
return fsm->state != ec_fsm_coe_map_state_end
&& fsm->state != ec_fsm_coe_map_state_error;
}
/*****************************************************************************/
/**
Returns, if the state machine terminated with success.
\return non-zero if successful.
*/
int ec_fsm_coe_map_success(ec_fsm_coe_map_t *fsm /**< Finite state machine */)
{
return fsm->state == ec_fsm_coe_map_state_end;
}
/******************************************************************************
*****************************************************************************/
/**
void ec_fsm_coe_map_state_start(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
// read mapping of first sync manager
fsm->sync_index = 0;
ec_fsm_coe_map_action_next_sync(fsm);
}
/*****************************************************************************/
/**
*/
void ec_fsm_coe_map_action_next_sync(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
ec_slave_t *slave = fsm->slave;
ec_sdo_entry_t *entry;
for (; fsm->sync_index < slave->sii_sync_count; fsm->sync_index++) {
if (!(fsm->sync_sdo = ec_slave_get_sdo(slave, 0x1C10 + fsm->sync_index)))
continue;
if (slave->master->debug_level)
EC_DBG("Reading PDO mapping of sync manager %u of slave %u.\n",
fsm->sync_index, slave->ring_position);
ec_fsm_coe_map_clear_pdos(fsm);
if (!(entry = ec_sdo_get_entry(fsm->sync_sdo, 0))) {
EC_ERR("SDO 0x%04X has no subindex 0 on slave %u.\n",
fsm->sync_sdo->index,
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
ec_sdo_request_init_read(&fsm->request, entry);
fsm->state = ec_fsm_coe_map_state_pdo_count;
ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
return;
}
fsm->state = ec_fsm_coe_map_state_end;
}
/*****************************************************************************/
/**
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
*/
void ec_fsm_coe_map_state_pdo_count(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
if (ec_fsm_coe_exec(fsm->fsm_coe)) return;
if (!ec_fsm_coe_success(fsm->fsm_coe)) {
EC_ERR("Failed to read number of mapped PDOs from slave %u.\n",
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
fsm->sync_subindices = EC_READ_U8(fsm->request.data);
if (fsm->slave->master->debug_level)
EC_DBG(" %u PDOs mapped.\n", fsm->sync_subindices);
// read first PDO
fsm->sync_subindex = 1;
ec_fsm_coe_map_action_next_pdo(fsm);
}
/*****************************************************************************/
/**
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
*/
void ec_fsm_coe_map_action_next_pdo(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
ec_sdo_entry_t *entry;
if (fsm->sync_subindex <= fsm->sync_subindices) {
if (!(entry = ec_sdo_get_entry(fsm->sync_sdo,
fsm->sync_subindex))) {
EC_ERR("SDO 0x%04X has no subindex %u on slave %u.\n",
fsm->sync_sdo->index,
fsm->sync_subindex,
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
ec_sdo_request_init_read(&fsm->request, entry);
fsm->state = ec_fsm_coe_map_state_pdo;
ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
return;
}
{
ec_sync_t *sync = fsm->slave->sii_syncs + fsm->sync_index;
ec_pdo_t *pdo;
// exchange sync manager PDO mapping
ec_sync_clear_pdos(sync);
list_for_each_entry(pdo, &fsm->pdos, list) {
ec_sync_add_pdo(sync, pdo);
}
sync->mapping_source = EC_SYNC_MAPPING_COE;
ec_fsm_coe_map_clear_pdos(fsm);
// next sync manager
fsm->sync_index++;
ec_fsm_coe_map_action_next_sync(fsm);
}
}
/*****************************************************************************/
/**
*/
void ec_fsm_coe_map_state_pdo(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
if (ec_fsm_coe_exec(fsm->fsm_coe)) return;
if (!ec_fsm_coe_success(fsm->fsm_coe)) {
EC_ERR("Failed to read mapped PDO index from slave %u.\n",
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
{
ec_sdo_entry_t *entry;
if (!(fsm->pdo = (ec_pdo_t *)
kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO.\n");
fsm->state = ec_fsm_coe_map_state_error;
return;
}
ec_pdo_init(fsm->pdo);
fsm->pdo->index = EC_READ_U16(fsm->request.data);
fsm->pdo->type =
ec_sync_get_pdo_type(fsm->slave->sii_syncs + fsm->sync_index);
if (fsm->slave->master->debug_level)
EC_DBG(" PDO 0x%04X.\n", fsm->pdo->index);
if (!(fsm->pdo_sdo = ec_slave_get_sdo(fsm->slave, fsm->pdo->index))) {
EC_ERR("Slave %u has no SDO 0x%04X.\n",
fsm->slave->ring_position, fsm->pdo->index);
ec_pdo_clear(fsm->pdo);
kfree(fsm->pdo);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
if (fsm->pdo_sdo->name && strlen(fsm->pdo_sdo->name)) {
if (!(fsm->pdo->name = (char *)
kmalloc(strlen(fsm->pdo_sdo->name) + 1, GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO name.\n");
ec_pdo_clear(fsm->pdo);
kfree(fsm->pdo);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
memcpy(fsm->pdo->name, fsm->pdo_sdo->name,
strlen(fsm->pdo_sdo->name) + 1);
} else {
fsm->pdo->name = NULL;
}
if (!(entry = ec_sdo_get_entry(fsm->pdo_sdo, 0))) {
EC_ERR("SDO 0x%04X has no subindex 0 on slave %u.\n",
fsm->pdo_sdo->index,
fsm->slave->ring_position);
ec_pdo_clear(fsm->pdo);
kfree(fsm->pdo);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
list_add_tail(&fsm->pdo->list, &fsm->pdos);
ec_sdo_request_init_read(&fsm->request, entry);
fsm->state = ec_fsm_coe_map_state_pdo_entry_count;
ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
return;
}
}
/*****************************************************************************/
/**
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
*/
void ec_fsm_coe_map_state_pdo_entry_count(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
if (ec_fsm_coe_exec(fsm->fsm_coe)) return;
if (!ec_fsm_coe_success(fsm->fsm_coe)) {
EC_ERR("Failed to read number of mapped PDO entries from slave %u.\n",
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
fsm->pdo_subindices = EC_READ_U8(fsm->request.data);
if (fsm->slave->master->debug_level)
EC_DBG(" %u PDO entries mapped.\n", fsm->pdo_subindices);
// read first PDO entry
fsm->pdo_subindex = 1;
ec_fsm_coe_map_action_next_pdo_entry(fsm);
}
/*****************************************************************************/
/**
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
*/
void ec_fsm_coe_map_action_next_pdo_entry(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
ec_sdo_entry_t *entry;
if (fsm->pdo_subindex <= fsm->pdo_subindices) {
if (!(entry = ec_sdo_get_entry(fsm->pdo_sdo,
fsm->pdo_subindex))) {
EC_ERR("SDO 0x%04X has no subindex %u on slave %u.\n",
fsm->pdo_sdo->index, fsm->pdo_subindex,
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
ec_sdo_request_init_read(&fsm->request, entry);
fsm->state = ec_fsm_coe_map_state_pdo_entry;
ec_fsm_coe_upload(fsm->fsm_coe, fsm->slave, &fsm->request);
ec_fsm_coe_exec(fsm->fsm_coe); // execute immediately
return;
}
// next PDO
fsm->sync_subindex++;
ec_fsm_coe_map_action_next_pdo(fsm);
}
/*****************************************************************************/
/**
*/
void ec_fsm_coe_map_state_pdo_entry(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
if (ec_fsm_coe_exec(fsm->fsm_coe)) return;
if (!ec_fsm_coe_success(fsm->fsm_coe)) {
EC_ERR("Failed to read index of mapped PDO entry from slave %u.\n",
fsm->slave->ring_position);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
{
uint32_t pdo_entry_info;
ec_sdo_t *sdo;
ec_sdo_entry_t *entry;
ec_pdo_entry_t *pdo_entry;
pdo_entry_info = EC_READ_U32(fsm->request.data);
if (!(pdo_entry = (ec_pdo_entry_t *)
kmalloc(sizeof(ec_pdo_entry_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO entry.\n");
fsm->state = ec_fsm_coe_map_state_error;
return;
}
pdo_entry->index = pdo_entry_info >> 16;
pdo_entry->subindex = (pdo_entry_info >> 8) & 0xFF;
pdo_entry->bit_length = pdo_entry_info & 0xFF;
if (!(sdo = ec_slave_get_sdo(fsm->slave, pdo_entry->index))) {
EC_ERR("Slave %u has no SDO 0x%04X.\n",
fsm->slave->ring_position, pdo_entry->index);
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
if (!(entry = ec_sdo_get_entry(sdo, pdo_entry->subindex))) {
EC_ERR("Slave %u has no SDO entry 0x%04X:%u.\n",
fsm->slave->ring_position, pdo_entry->index,
pdo_entry->subindex);
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
if (entry->description && strlen(entry->description)) {
if (!(pdo_entry->name = (char *)
kmalloc(strlen(entry->description) + 1, GFP_KERNEL))) {
EC_ERR("Failed to allocate PDO entry name.\n");
kfree(pdo_entry);
fsm->state = ec_fsm_coe_map_state_error;
return;
}
memcpy(pdo_entry->name, entry->description, strlen(entry->description) + 1);
} else {
pdo_entry->name = NULL;
}
if (fsm->slave->master->debug_level) {
EC_DBG(" PDO entry 0x%04X \"%s\" (%u bit).\n",
pdo_entry->index, pdo_entry->name ? pdo_entry->name : "???",
pdo_entry->bit_length);
list_add_tail(&pdo_entry->list, &fsm->pdo->entries);
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
// next PDO entry
fsm->pdo_subindex++;
ec_fsm_coe_map_action_next_pdo_entry(fsm);
}
}
/*****************************************************************************/
/**
State: ERROR.
*/
void ec_fsm_coe_map_state_error(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
}
/*****************************************************************************/
/**
State: END.
*/
void ec_fsm_coe_map_state_end(
ec_fsm_coe_map_t *fsm /**< finite state machine */
)
{
}
/*****************************************************************************/