|
1 /****************************************************************************** |
|
2 * |
|
3 * $Id$ |
|
4 * |
|
5 * Copyright (C) 2006 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 |
|
10 * and/or modify it under the terms of the GNU General Public License |
|
11 * as published by the Free Software Foundation; either version 2 of the |
|
12 * License, or (at your option) any later version. |
|
13 * |
|
14 * The IgH EtherCAT Master is distributed in the hope that it will be |
|
15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 * GNU General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU General Public License |
|
20 * along with the IgH EtherCAT Master; if not, write to the Free Software |
|
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
22 * |
|
23 * The right to use EtherCAT Technology is granted and comes free of |
|
24 * charge under condition of compatibility of product made by |
|
25 * Licensee. People intending to distribute/sell products based on the |
|
26 * code, have to sign an agreement to guarantee that products using |
|
27 * software based on IgH EtherCAT master stay compatible with the actual |
|
28 * EtherCAT specification (which are released themselves as an open |
|
29 * standard) as the (only) precondition to have the right to use EtherCAT |
|
30 * Technology, IP and trade marks. |
|
31 * |
|
32 *****************************************************************************/ |
|
33 |
|
34 /** |
|
35 \file |
|
36 EtherCAT finite state machines. |
|
37 */ |
|
38 |
|
39 /*****************************************************************************/ |
|
40 |
|
41 #include "globals.h" |
|
42 #include "fsm.h" |
|
43 #include "master.h" |
|
44 |
|
45 /*****************************************************************************/ |
|
46 |
|
47 /** |
|
48 Size of memory to allocate while reading categories. |
|
49 */ |
|
50 |
|
51 #define EC_CAT_MEM 0x100 |
|
52 |
|
53 /*****************************************************************************/ |
|
54 |
|
55 const ec_code_msg_t al_status_messages[]; |
|
56 |
|
57 /*****************************************************************************/ |
|
58 |
|
59 void ec_fsm_master_start(ec_fsm_t *); |
|
60 void ec_fsm_master_broadcast(ec_fsm_t *); |
|
61 void ec_fsm_master_proc_states(ec_fsm_t *); |
|
62 void ec_fsm_master_scan(ec_fsm_t *); |
|
63 void ec_fsm_master_states(ec_fsm_t *); |
|
64 void ec_fsm_master_validate_vendor(ec_fsm_t *); |
|
65 void ec_fsm_master_validate_product(ec_fsm_t *); |
|
66 void ec_fsm_master_reconfigure(ec_fsm_t *); |
|
67 void ec_fsm_master_address(ec_fsm_t *); |
|
68 void ec_fsm_master_conf(ec_fsm_t *); |
|
69 |
|
70 void ec_fsm_slave_start_reading(ec_fsm_t *); |
|
71 void ec_fsm_slave_read_status(ec_fsm_t *); |
|
72 void ec_fsm_slave_read_base(ec_fsm_t *); |
|
73 void ec_fsm_slave_read_dl(ec_fsm_t *); |
|
74 void ec_fsm_slave_prepare_sii(ec_fsm_t *); |
|
75 void ec_fsm_slave_read_sii(ec_fsm_t *); |
|
76 void ec_fsm_slave_category_header(ec_fsm_t *); |
|
77 void ec_fsm_slave_category_data(ec_fsm_t *); |
|
78 void ec_fsm_slave_end(ec_fsm_t *); |
|
79 |
|
80 void ec_fsm_slave_conf(ec_fsm_t *); |
|
81 void ec_fsm_slave_sync(ec_fsm_t *); |
|
82 void ec_fsm_slave_preop(ec_fsm_t *); |
|
83 void ec_fsm_slave_fmmu(ec_fsm_t *); |
|
84 void ec_fsm_slave_saveop(ec_fsm_t *); |
|
85 void ec_fsm_slave_op(ec_fsm_t *); |
|
86 void ec_fsm_slave_op2(ec_fsm_t *); |
|
87 |
|
88 void ec_fsm_sii_start_reading(ec_fsm_t *); |
|
89 void ec_fsm_sii_check(ec_fsm_t *); |
|
90 void ec_fsm_sii_fetch(ec_fsm_t *); |
|
91 void ec_fsm_sii_end(ec_fsm_t *); |
|
92 void ec_fsm_sii_error(ec_fsm_t *); |
|
93 |
|
94 void ec_fsm_change_start(ec_fsm_t *); |
|
95 void ec_fsm_change_check(ec_fsm_t *); |
|
96 void ec_fsm_change_status(ec_fsm_t *); |
|
97 void ec_fsm_change_code(ec_fsm_t *); |
|
98 void ec_fsm_change_ack(ec_fsm_t *); |
|
99 void ec_fsm_change_ack2(ec_fsm_t *); |
|
100 void ec_fsm_change_end(ec_fsm_t *); |
|
101 void ec_fsm_change_error(ec_fsm_t *); |
|
102 |
|
103 /*****************************************************************************/ |
|
104 |
|
105 /** |
|
106 Constructor. |
|
107 */ |
|
108 |
|
109 int ec_fsm_init(ec_fsm_t *fsm, /**< finite state machine */ |
|
110 ec_master_t *master /**< EtherCAT master */ |
|
111 ) |
|
112 { |
|
113 fsm->master = master; |
|
114 fsm->master_state = ec_fsm_master_start; |
|
115 fsm->master_slaves_responding = 0; |
|
116 fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN; |
|
117 fsm->master_validation = 0; |
|
118 fsm->slave_cat_data = NULL; |
|
119 |
|
120 ec_command_init(&fsm->command); |
|
121 if (ec_command_prealloc(&fsm->command, EC_MAX_DATA_SIZE)) { |
|
122 EC_ERR("FSM failed to allocate FSM command.\n"); |
|
123 return -1; |
|
124 } |
|
125 |
|
126 return 0; |
|
127 } |
|
128 |
|
129 /*****************************************************************************/ |
|
130 |
|
131 /** |
|
132 Destructor. |
|
133 */ |
|
134 |
|
135 void ec_fsm_clear(ec_fsm_t *fsm /**< finite state machine */) |
|
136 { |
|
137 if (fsm->slave_cat_data) kfree(fsm->slave_cat_data); |
|
138 ec_command_clear(&fsm->command); |
|
139 } |
|
140 |
|
141 /*****************************************************************************/ |
|
142 |
|
143 /** |
|
144 Resets the state machine. |
|
145 */ |
|
146 |
|
147 void ec_fsm_reset(ec_fsm_t *fsm /**< finite state machine */) |
|
148 { |
|
149 fsm->master_state = ec_fsm_master_start; |
|
150 fsm->master_slaves_responding = 0; |
|
151 fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN; |
|
152 |
|
153 if (fsm->slave_cat_data) { |
|
154 kfree(fsm->slave_cat_data); |
|
155 fsm->slave_cat_data = NULL; |
|
156 } |
|
157 } |
|
158 |
|
159 /*****************************************************************************/ |
|
160 |
|
161 /** |
|
162 Executes the current state of the state machine. |
|
163 */ |
|
164 |
|
165 void ec_fsm_execute(ec_fsm_t *fsm /**< finite state machine */) |
|
166 { |
|
167 fsm->master_state(fsm); |
|
168 } |
|
169 |
|
170 /****************************************************************************** |
|
171 * master state machine |
|
172 *****************************************************************************/ |
|
173 |
|
174 /** |
|
175 Master state: START. |
|
176 Starts with getting slave count and slave states. |
|
177 */ |
|
178 |
|
179 void ec_fsm_master_start(ec_fsm_t *fsm) |
|
180 { |
|
181 ec_command_brd(&fsm->command, 0x0130, 2); |
|
182 ec_master_queue_command(fsm->master, &fsm->command); |
|
183 fsm->master_state = ec_fsm_master_broadcast; |
|
184 } |
|
185 |
|
186 /*****************************************************************************/ |
|
187 |
|
188 /** |
|
189 Master state: BROADCAST. |
|
190 Processes the broadcast read slave count and slaves states. |
|
191 */ |
|
192 |
|
193 void ec_fsm_master_broadcast(ec_fsm_t *fsm /**< finite state machine */) |
|
194 { |
|
195 ec_command_t *command = &fsm->command; |
|
196 unsigned int topology_change, states_change, i; |
|
197 ec_slave_t *slave; |
|
198 ec_master_t *master = fsm->master; |
|
199 |
|
200 if (command->state != EC_CMD_RECEIVED) { |
|
201 if (!master->device->link_state) { |
|
202 fsm->master_slaves_responding = 0; |
|
203 list_for_each_entry(slave, &master->slaves, list) { |
|
204 slave->online = 0; |
|
205 } |
|
206 } |
|
207 fsm->master_state = ec_fsm_master_start; |
|
208 fsm->master_state(fsm); // execute immediately |
|
209 return; |
|
210 } |
|
211 |
|
212 topology_change = (command->working_counter != |
|
213 fsm->master_slaves_responding); |
|
214 states_change = (EC_READ_U8(command->data) != fsm->master_slave_states); |
|
215 |
|
216 fsm->master_slave_states = EC_READ_U8(command->data); |
|
217 fsm->master_slaves_responding = command->working_counter; |
|
218 |
|
219 if (topology_change) { |
|
220 EC_INFO("%i slave%s responding.\n", |
|
221 fsm->master_slaves_responding, |
|
222 fsm->master_slaves_responding == 1 ? "" : "s"); |
|
223 |
|
224 if (master->mode == EC_MASTER_MODE_RUNNING) { |
|
225 if (fsm->master_slaves_responding == master->slave_count) { |
|
226 fsm->master_validation = 1; // start validation later |
|
227 } |
|
228 else { |
|
229 EC_WARN("Invalid slave count. Bus in tainted state.\n"); |
|
230 } |
|
231 } |
|
232 } |
|
233 |
|
234 if (states_change) { |
|
235 EC_INFO("Slave states: "); |
|
236 ec_print_states(fsm->master_slave_states); |
|
237 printk(".\n"); |
|
238 } |
|
239 |
|
240 // topology change in free-run mode: clear all slaves and scan the bus |
|
241 if (topology_change && master->mode == EC_MASTER_MODE_FREERUN) { |
|
242 EC_INFO("Scanning bus.\n"); |
|
243 |
|
244 ec_master_eoe_stop(master); |
|
245 ec_master_clear_slaves(master); |
|
246 |
|
247 if (!fsm->master_slaves_responding) { |
|
248 // no slaves present -> finish state machine. |
|
249 fsm->master_state = ec_fsm_master_start; |
|
250 fsm->master_state(fsm); // execute immediately |
|
251 return; |
|
252 } |
|
253 |
|
254 // init slaves |
|
255 for (i = 0; i < fsm->master_slaves_responding; i++) { |
|
256 if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t), |
|
257 GFP_ATOMIC))) { |
|
258 EC_ERR("Failed to allocate slave %i!\n", i); |
|
259 fsm->master_state = ec_fsm_master_start; |
|
260 fsm->master_state(fsm); // execute immediately |
|
261 return; |
|
262 } |
|
263 |
|
264 if (ec_slave_init(slave, master, i, i + 1)) { |
|
265 fsm->master_state = ec_fsm_master_start; |
|
266 fsm->master_state(fsm); // execute immediately |
|
267 return; |
|
268 } |
|
269 |
|
270 if (kobject_add(&slave->kobj)) { |
|
271 EC_ERR("Failed to add kobject.\n"); |
|
272 kobject_put(&slave->kobj); // free |
|
273 fsm->master_state = ec_fsm_master_start; |
|
274 fsm->master_state(fsm); // execute immediately |
|
275 return; |
|
276 } |
|
277 |
|
278 list_add_tail(&slave->list, &master->slaves); |
|
279 } |
|
280 |
|
281 // begin scanning of slaves |
|
282 fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); |
|
283 fsm->slave_state = ec_fsm_slave_start_reading; |
|
284 fsm->master_state = ec_fsm_master_scan; |
|
285 fsm->master_state(fsm); // execute immediately |
|
286 return; |
|
287 } |
|
288 |
|
289 // fetch state from each slave |
|
290 fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); |
|
291 ec_command_nprd(&fsm->command, fsm->slave->station_address, 0x0130, 2); |
|
292 ec_master_queue_command(master, &fsm->command); |
|
293 fsm->master_state = ec_fsm_master_states; |
|
294 } |
|
295 |
|
296 /*****************************************************************************/ |
|
297 |
|
298 /** |
|
299 Master action: Get state of next slave. |
|
300 */ |
|
301 |
|
302 void ec_fsm_master_action_next_slave_state(ec_fsm_t *fsm |
|
303 /**< finite state machine */) |
|
304 { |
|
305 ec_master_t *master = fsm->master; |
|
306 ec_slave_t *slave = fsm->slave; |
|
307 |
|
308 // have all states been read? |
|
309 if (slave->list.next == &master->slaves) { |
|
310 |
|
311 // check, if a bus validation has to be done |
|
312 if (fsm->master_validation) { |
|
313 fsm->master_validation = 0; |
|
314 list_for_each_entry(slave, &master->slaves, list) { |
|
315 if (slave->online) continue; |
|
316 |
|
317 // At least one slave is offline. validate! |
|
318 EC_INFO("Validating bus.\n"); |
|
319 fsm->slave = list_entry(master->slaves.next, ec_slave_t, list); |
|
320 fsm->master_state = ec_fsm_master_validate_vendor; |
|
321 fsm->sii_offset = 0x0008; // vendor ID |
|
322 fsm->sii_mode = 0; |
|
323 fsm->sii_state = ec_fsm_sii_start_reading; |
|
324 fsm->sii_state(fsm); // execute immediately |
|
325 return; |
|
326 } |
|
327 } |
|
328 |
|
329 fsm->master_state = ec_fsm_master_proc_states; |
|
330 fsm->master_state(fsm); // execute immediately |
|
331 return; |
|
332 } |
|
333 |
|
334 // process next slave |
|
335 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
|
336 ec_command_nprd(&fsm->command, fsm->slave->station_address, 0x0130, 2); |
|
337 ec_master_queue_command(master, &fsm->command); |
|
338 fsm->master_state = ec_fsm_master_states; |
|
339 } |
|
340 |
|
341 /*****************************************************************************/ |
|
342 |
|
343 /** |
|
344 Master state: STATES. |
|
345 Fetches the AL- and online state of a slave. |
|
346 */ |
|
347 |
|
348 void ec_fsm_master_states(ec_fsm_t *fsm /**< finite state machine */) |
|
349 { |
|
350 ec_slave_t *slave = fsm->slave; |
|
351 ec_command_t *command = &fsm->command; |
|
352 uint8_t new_state; |
|
353 |
|
354 if (command->state != EC_CMD_RECEIVED) { |
|
355 fsm->master_state = ec_fsm_master_start; |
|
356 fsm->master_state(fsm); // execute immediately |
|
357 return; |
|
358 } |
|
359 |
|
360 // did the slave not respond to its station address? |
|
361 if (command->working_counter != 1) { |
|
362 if (slave->online) { |
|
363 slave->online = 0; |
|
364 EC_INFO("Slave %i: offline.\n", slave->ring_position); |
|
365 } |
|
366 ec_fsm_master_action_next_slave_state(fsm); |
|
367 return; |
|
368 } |
|
369 |
|
370 // slave responded |
|
371 new_state = EC_READ_U8(command->data); |
|
372 if (!slave->online) { // slave was offline before |
|
373 slave->online = 1; |
|
374 slave->state_error = 0; |
|
375 slave->current_state = new_state; |
|
376 EC_INFO("Slave %i: online (", slave->ring_position); |
|
377 ec_print_states(new_state); |
|
378 printk(").\n"); |
|
379 } |
|
380 else if (new_state != slave->current_state) { |
|
381 EC_INFO("Slave %i: ", slave->ring_position); |
|
382 ec_print_states(slave->current_state); |
|
383 printk(" -> "); |
|
384 ec_print_states(new_state); |
|
385 printk(".\n"); |
|
386 slave->current_state = new_state; |
|
387 } |
|
388 |
|
389 ec_fsm_master_action_next_slave_state(fsm); |
|
390 } |
|
391 |
|
392 /*****************************************************************************/ |
|
393 |
|
394 /** |
|
395 Master state: PROC_STATES. |
|
396 Processes the slave states. |
|
397 */ |
|
398 |
|
399 void ec_fsm_master_proc_states(ec_fsm_t *fsm /**< finite state machine */) |
|
400 { |
|
401 ec_master_t *master = fsm->master; |
|
402 ec_slave_t *slave; |
|
403 |
|
404 // check if any slaves are not in the state, they're supposed to be |
|
405 list_for_each_entry(slave, &master->slaves, list) { |
|
406 if (slave->state_error || !slave->online || |
|
407 slave->requested_state == EC_SLAVE_STATE_UNKNOWN || |
|
408 slave->current_state == slave->requested_state) continue; |
|
409 |
|
410 EC_INFO("Changing state of slave %i from ", slave->ring_position); |
|
411 ec_print_states(slave->current_state); |
|
412 printk(" to "); |
|
413 ec_print_states(slave->requested_state); |
|
414 printk(".\n"); |
|
415 |
|
416 fsm->slave = slave; |
|
417 fsm->slave_state = ec_fsm_slave_conf; |
|
418 fsm->change_new = EC_SLAVE_STATE_INIT; |
|
419 fsm->change_state = ec_fsm_change_start; |
|
420 fsm->master_state = ec_fsm_master_conf; |
|
421 fsm->master_state(fsm); // execute immediately |
|
422 return; |
|
423 } |
|
424 |
|
425 // nothing to configure. restart master state machine. |
|
426 fsm->master_state = ec_fsm_master_start; |
|
427 fsm->master_state(fsm); // execute immediately |
|
428 } |
|
429 |
|
430 /*****************************************************************************/ |
|
431 |
|
432 /** |
|
433 Master state: VALIDATE_VENDOR. |
|
434 Validates the vendor ID of a slave. |
|
435 */ |
|
436 |
|
437 void ec_fsm_master_validate_vendor(ec_fsm_t *fsm /**< finite state machine */) |
|
438 { |
|
439 ec_slave_t *slave = fsm->slave; |
|
440 |
|
441 fsm->sii_state(fsm); // execute SII state machine |
|
442 |
|
443 if (fsm->sii_state == ec_fsm_sii_error) { |
|
444 EC_ERR("Failed to validate vendor ID of slave %i.\n", |
|
445 slave->ring_position); |
|
446 fsm->master_state = ec_fsm_master_start; |
|
447 fsm->master_state(fsm); // execute immediately |
|
448 return; |
|
449 } |
|
450 |
|
451 if (fsm->sii_state != ec_fsm_sii_end) return; |
|
452 |
|
453 if (fsm->sii_result != slave->sii_vendor_id) { |
|
454 EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position); |
|
455 fsm->master_state = ec_fsm_master_start; |
|
456 fsm->master_state(fsm); // execute immediately |
|
457 return; |
|
458 } |
|
459 |
|
460 // vendor ID is ok. check product code. |
|
461 fsm->master_state = ec_fsm_master_validate_product; |
|
462 fsm->sii_offset = 0x000A; // product code |
|
463 fsm->sii_mode = 0; |
|
464 fsm->sii_state = ec_fsm_sii_start_reading; |
|
465 fsm->sii_state(fsm); // execute immediately |
|
466 } |
|
467 |
|
468 /*****************************************************************************/ |
|
469 |
|
470 /** |
|
471 Master state: VALIDATE_PRODUCT. |
|
472 Validates the product ID of a slave. |
|
473 */ |
|
474 |
|
475 void ec_fsm_master_validate_product(ec_fsm_t *fsm /**< finite state machine */) |
|
476 { |
|
477 ec_slave_t *slave = fsm->slave; |
|
478 |
|
479 fsm->sii_state(fsm); // execute SII state machine |
|
480 |
|
481 if (fsm->sii_state == ec_fsm_sii_error) { |
|
482 EC_ERR("Failed to validate product code of slave %i.\n", |
|
483 slave->ring_position); |
|
484 fsm->master_state = ec_fsm_master_start; |
|
485 fsm->master_state(fsm); // execute immediately |
|
486 return; |
|
487 } |
|
488 |
|
489 if (fsm->sii_state != ec_fsm_sii_end) return; |
|
490 |
|
491 if (fsm->sii_result != slave->sii_product_code) { |
|
492 EC_ERR("Slave %i: invalid product code!\n", slave->ring_position); |
|
493 EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code, |
|
494 fsm->sii_result); |
|
495 fsm->master_state = ec_fsm_master_start; |
|
496 fsm->master_state(fsm); // execute immediately |
|
497 return; |
|
498 } |
|
499 |
|
500 // have all states been validated? |
|
501 if (slave->list.next == &fsm->master->slaves) { |
|
502 fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list); |
|
503 fsm->master_state = ec_fsm_master_reconfigure; |
|
504 return; |
|
505 } |
|
506 |
|
507 // validate next slave |
|
508 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
|
509 fsm->master_state = ec_fsm_master_validate_vendor; |
|
510 fsm->sii_offset = 0x0008; // vendor ID |
|
511 fsm->sii_mode = 0; |
|
512 fsm->sii_state = ec_fsm_sii_start_reading; |
|
513 fsm->sii_state(fsm); // execute immediately |
|
514 } |
|
515 |
|
516 /*****************************************************************************/ |
|
517 |
|
518 /** |
|
519 Master state: RECONFIGURE. |
|
520 Looks for slave, that have lost their configuration and writes |
|
521 their station address, so that they can be reconfigured later. |
|
522 */ |
|
523 |
|
524 void ec_fsm_master_reconfigure(ec_fsm_t *fsm /**< finite state machine */) |
|
525 { |
|
526 ec_command_t *command = &fsm->command; |
|
527 |
|
528 while (fsm->slave->online) { |
|
529 if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? |
|
530 fsm->master_state = ec_fsm_master_start; |
|
531 fsm->master_state(fsm); // execute immediately |
|
532 return; |
|
533 } |
|
534 // check next slave |
|
535 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
|
536 } |
|
537 |
|
538 EC_INFO("Reinitializing slave %i.\n", fsm->slave->ring_position); |
|
539 |
|
540 // write station address |
|
541 ec_command_apwr(command, fsm->slave->ring_position, 0x0010, 2); |
|
542 EC_WRITE_U16(command->data, fsm->slave->station_address); |
|
543 ec_master_queue_command(fsm->master, command); |
|
544 fsm->master_state = ec_fsm_master_address; |
|
545 } |
|
546 |
|
547 /*****************************************************************************/ |
|
548 |
|
549 /** |
|
550 Master state: ADDRESS. |
|
551 Checks, if the new station address has been written to the slave. |
|
552 */ |
|
553 |
|
554 void ec_fsm_master_address(ec_fsm_t *fsm /**< finite state machine */) |
|
555 { |
|
556 ec_slave_t *slave = fsm->slave; |
|
557 ec_command_t *command = &fsm->command; |
|
558 |
|
559 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
560 EC_ERR("Failed to write station address on slave %i.\n", |
|
561 slave->ring_position); |
|
562 } |
|
563 |
|
564 if (fsm->slave->list.next == &fsm->master->slaves) { // last slave? |
|
565 fsm->master_state = ec_fsm_master_start; |
|
566 fsm->master_state(fsm); // execute immediately |
|
567 return; |
|
568 } |
|
569 |
|
570 // check next slave |
|
571 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
|
572 fsm->master_state = ec_fsm_master_reconfigure; |
|
573 fsm->master_state(fsm); // execute immediately |
|
574 } |
|
575 |
|
576 /*****************************************************************************/ |
|
577 |
|
578 /** |
|
579 Master state: SCAN. |
|
580 Executes the sub-statemachine for the scanning of a slave. |
|
581 */ |
|
582 |
|
583 void ec_fsm_master_scan(ec_fsm_t *fsm /**< finite state machine */) |
|
584 { |
|
585 ec_master_t *master = fsm->master; |
|
586 ec_slave_t *slave = fsm->slave; |
|
587 uint16_t coupler_index, coupler_subindex; |
|
588 uint16_t reverse_coupler_index, current_coupler_index; |
|
589 ec_slave_ident_t *ident; |
|
590 |
|
591 fsm->slave_state(fsm); // execute slave state machine |
|
592 |
|
593 if (fsm->slave_state != ec_fsm_slave_end) return; |
|
594 |
|
595 // have all slaves been fetched? |
|
596 if (slave->list.next == &master->slaves) { |
|
597 EC_INFO("Bus scanning completed.\n"); |
|
598 |
|
599 // identify all slaves and calculate coupler addressing |
|
600 |
|
601 coupler_index = 0; |
|
602 reverse_coupler_index = 0xFFFF; |
|
603 current_coupler_index = 0x3FFF; |
|
604 coupler_subindex = 0; |
|
605 |
|
606 list_for_each_entry(slave, &master->slaves, list) |
|
607 { |
|
608 // search for identification in "database" |
|
609 ident = slave_idents; |
|
610 while (ident->type) { |
|
611 if (ident->vendor_id == slave->sii_vendor_id |
|
612 && ident->product_code == slave->sii_product_code) { |
|
613 slave->type = ident->type; |
|
614 break; |
|
615 } |
|
616 ident++; |
|
617 } |
|
618 |
|
619 if (!slave->type) { |
|
620 EC_WARN("FSM: Unknown slave device (vendor 0x%08X," |
|
621 " code 0x%08X) at position %i.\n", |
|
622 slave->sii_vendor_id, slave->sii_product_code, |
|
623 slave->ring_position); |
|
624 } |
|
625 else { |
|
626 // if the slave is a bus coupler, change adressing base |
|
627 if (slave->type->special == EC_TYPE_BUS_COUPLER) { |
|
628 if (slave->sii_alias) |
|
629 current_coupler_index = reverse_coupler_index--; |
|
630 else |
|
631 current_coupler_index = coupler_index++; |
|
632 coupler_subindex = 0; |
|
633 } |
|
634 } |
|
635 |
|
636 // determine initial state. |
|
637 if ((slave->type && slave->type->special == EC_TYPE_BUS_COUPLER)) { |
|
638 slave->requested_state = EC_SLAVE_STATE_OP; |
|
639 } |
|
640 else { |
|
641 if (master->mode == EC_MASTER_MODE_RUNNING) |
|
642 slave->requested_state = EC_SLAVE_STATE_PREOP; |
|
643 else |
|
644 slave->requested_state = EC_SLAVE_STATE_INIT; |
|
645 } |
|
646 slave->state_error = 0; |
|
647 |
|
648 // calculate coupler-based slave address |
|
649 slave->coupler_index = current_coupler_index; |
|
650 slave->coupler_subindex = coupler_subindex; |
|
651 coupler_subindex++; |
|
652 } |
|
653 |
|
654 if (master->mode == EC_MASTER_MODE_FREERUN) { |
|
655 // start EoE processing |
|
656 ec_master_eoe_start(master); |
|
657 } |
|
658 |
|
659 fsm->master_state = ec_fsm_master_start; |
|
660 fsm->master_state(fsm); // execute immediately |
|
661 return; |
|
662 } |
|
663 |
|
664 // process next slave |
|
665 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
|
666 fsm->slave_state = ec_fsm_slave_start_reading; |
|
667 fsm->slave_state(fsm); // execute immediately |
|
668 } |
|
669 |
|
670 /*****************************************************************************/ |
|
671 |
|
672 /** |
|
673 Master state: CONF. |
|
674 Starts configuring a slave. |
|
675 */ |
|
676 |
|
677 void ec_fsm_master_conf(ec_fsm_t *fsm /**< finite state machine */) |
|
678 { |
|
679 fsm->slave_state(fsm); // execute slave's state machine |
|
680 if (fsm->slave_state != ec_fsm_slave_end) return; |
|
681 fsm->master_state = ec_fsm_master_proc_states; |
|
682 fsm->master_state(fsm); // execute immediately |
|
683 } |
|
684 |
|
685 /****************************************************************************** |
|
686 * slave state machine |
|
687 *****************************************************************************/ |
|
688 |
|
689 /** |
|
690 Slave state: START_READING. |
|
691 First state of the slave state machine. Writes the station address to the |
|
692 slave, according to its ring position. |
|
693 */ |
|
694 |
|
695 void ec_fsm_slave_start_reading(ec_fsm_t *fsm /**< finite state machine */) |
|
696 { |
|
697 ec_command_t *command = &fsm->command; |
|
698 |
|
699 // write station address |
|
700 ec_command_apwr(command, fsm->slave->ring_position, 0x0010, 2); |
|
701 EC_WRITE_U16(command->data, fsm->slave->station_address); |
|
702 ec_master_queue_command(fsm->master, command); |
|
703 fsm->slave_state = ec_fsm_slave_read_status; |
|
704 } |
|
705 |
|
706 /*****************************************************************************/ |
|
707 |
|
708 /** |
|
709 Slave state: READ_STATUS. |
|
710 */ |
|
711 |
|
712 void ec_fsm_slave_read_status(ec_fsm_t *fsm /**< finite state machine */) |
|
713 { |
|
714 ec_command_t *command = &fsm->command; |
|
715 |
|
716 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
717 EC_ERR("FSM failed to write station address of slave %i.\n", |
|
718 fsm->slave->ring_position); |
|
719 fsm->slave_state = ec_fsm_slave_end; |
|
720 return; |
|
721 } |
|
722 |
|
723 // read AL status |
|
724 ec_command_nprd(command, fsm->slave->station_address, 0x0130, 2); |
|
725 ec_master_queue_command(fsm->master, command); |
|
726 fsm->slave_state = ec_fsm_slave_read_base; |
|
727 } |
|
728 |
|
729 /*****************************************************************************/ |
|
730 |
|
731 /** |
|
732 Slave state: READ_BASE. |
|
733 */ |
|
734 |
|
735 void ec_fsm_slave_read_base(ec_fsm_t *fsm /**< finite state machine */) |
|
736 { |
|
737 ec_command_t *command = &fsm->command; |
|
738 ec_slave_t *slave = fsm->slave; |
|
739 |
|
740 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
741 EC_ERR("FSM failed to read AL status of slave %i.\n", |
|
742 fsm->slave->ring_position); |
|
743 fsm->slave_state = ec_fsm_slave_end; |
|
744 return; |
|
745 } |
|
746 |
|
747 slave->current_state = EC_READ_U8(command->data); |
|
748 if (slave->current_state & EC_ACK) { |
|
749 EC_WARN("Slave %i has status error bit set (0x%02X)!\n", |
|
750 slave->ring_position, slave->current_state); |
|
751 slave->current_state &= 0x0F; |
|
752 } |
|
753 |
|
754 // read base data |
|
755 ec_command_nprd(command, fsm->slave->station_address, 0x0000, 6); |
|
756 ec_master_queue_command(fsm->master, command); |
|
757 fsm->slave_state = ec_fsm_slave_read_dl; |
|
758 } |
|
759 |
|
760 /*****************************************************************************/ |
|
761 |
|
762 /** |
|
763 Slave state: READ_DL. |
|
764 */ |
|
765 |
|
766 void ec_fsm_slave_read_dl(ec_fsm_t *fsm /**< finite state machine */) |
|
767 { |
|
768 ec_command_t *command = &fsm->command; |
|
769 ec_slave_t *slave = fsm->slave; |
|
770 |
|
771 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
772 EC_ERR("FSM failed to read base data of slave %i.\n", |
|
773 slave->ring_position); |
|
774 fsm->slave_state = ec_fsm_slave_end; |
|
775 return; |
|
776 } |
|
777 |
|
778 slave->base_type = EC_READ_U8 (command->data); |
|
779 slave->base_revision = EC_READ_U8 (command->data + 1); |
|
780 slave->base_build = EC_READ_U16(command->data + 2); |
|
781 slave->base_fmmu_count = EC_READ_U8 (command->data + 4); |
|
782 slave->base_sync_count = EC_READ_U8 (command->data + 5); |
|
783 |
|
784 if (slave->base_fmmu_count > EC_MAX_FMMUS) |
|
785 slave->base_fmmu_count = EC_MAX_FMMUS; |
|
786 |
|
787 // read data link status |
|
788 ec_command_nprd(command, slave->station_address, 0x0110, 2); |
|
789 ec_master_queue_command(slave->master, command); |
|
790 fsm->slave_state = ec_fsm_slave_prepare_sii; |
|
791 } |
|
792 |
|
793 /*****************************************************************************/ |
|
794 |
|
795 /** |
|
796 Slave state: PREPARE_SII. |
|
797 */ |
|
798 |
|
799 void ec_fsm_slave_prepare_sii(ec_fsm_t *fsm /**< finite state machine */) |
|
800 { |
|
801 ec_command_t *command = &fsm->command; |
|
802 ec_slave_t *slave = fsm->slave; |
|
803 uint16_t dl_status; |
|
804 unsigned int i; |
|
805 |
|
806 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
807 EC_ERR("FSM failed to read DL status of slave %i.\n", |
|
808 slave->ring_position); |
|
809 fsm->slave_state = ec_fsm_slave_end; |
|
810 return; |
|
811 } |
|
812 |
|
813 dl_status = EC_READ_U16(command->data); |
|
814 |
|
815 for (i = 0; i < 4; i++) { |
|
816 slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0; |
|
817 slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0; |
|
818 slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0; |
|
819 } |
|
820 |
|
821 fsm->sii_offset = 0x0004; |
|
822 fsm->sii_mode = 1; |
|
823 fsm->sii_state = ec_fsm_sii_start_reading; |
|
824 fsm->slave_sii_num = 0; |
|
825 fsm->slave_state = ec_fsm_slave_read_sii; |
|
826 fsm->slave_state(fsm); // execute state immediately |
|
827 } |
|
828 |
|
829 /*****************************************************************************/ |
|
830 |
|
831 /** |
|
832 Slave state: READ_SII. |
|
833 */ |
|
834 |
|
835 void ec_fsm_slave_read_sii(ec_fsm_t *fsm /**< finite state machine */) |
|
836 { |
|
837 ec_slave_t *slave = fsm->slave; |
|
838 |
|
839 // execute SII state machine |
|
840 fsm->sii_state(fsm); |
|
841 |
|
842 if (fsm->sii_state == ec_fsm_sii_error) { |
|
843 fsm->slave_state = ec_fsm_slave_end; |
|
844 EC_ERR("FSM failed to read SII data at 0x%04X on slave %i.\n", |
|
845 fsm->sii_offset, slave->ring_position); |
|
846 return; |
|
847 } |
|
848 |
|
849 if (fsm->sii_state != ec_fsm_sii_end) return; |
|
850 |
|
851 switch (fsm->slave_sii_num) { |
|
852 case 0: |
|
853 slave->sii_alias = fsm->sii_result & 0xFFFF; |
|
854 fsm->sii_offset = 0x0008; |
|
855 break; |
|
856 case 1: |
|
857 slave->sii_vendor_id = fsm->sii_result; |
|
858 fsm->sii_offset = 0x000A; |
|
859 break; |
|
860 case 2: |
|
861 slave->sii_product_code = fsm->sii_result; |
|
862 fsm->sii_offset = 0x000C; |
|
863 break; |
|
864 case 3: |
|
865 slave->sii_revision_number = fsm->sii_result; |
|
866 fsm->sii_offset = 0x000E; |
|
867 break; |
|
868 case 4: |
|
869 slave->sii_serial_number = fsm->sii_result; |
|
870 fsm->sii_offset = 0x0018; |
|
871 break; |
|
872 case 5: |
|
873 slave->sii_rx_mailbox_offset = fsm->sii_result & 0xFFFF; |
|
874 slave->sii_rx_mailbox_size = fsm->sii_result >> 16; |
|
875 fsm->sii_offset = 0x001A; |
|
876 break; |
|
877 case 6: |
|
878 slave->sii_tx_mailbox_offset = fsm->sii_result & 0xFFFF; |
|
879 slave->sii_tx_mailbox_size = fsm->sii_result >> 16; |
|
880 fsm->sii_offset = 0x001C; |
|
881 break; |
|
882 case 7: |
|
883 slave->sii_mailbox_protocols = fsm->sii_result & 0xFFFF; |
|
884 |
|
885 fsm->slave_cat_offset = 0x0040; |
|
886 |
|
887 if (fsm->slave_cat_data) { |
|
888 EC_INFO("FSM freeing old category data on slave %i...\n", |
|
889 fsm->slave->ring_position); |
|
890 kfree(fsm->slave_cat_data); |
|
891 } |
|
892 |
|
893 if (!(fsm->slave_cat_data = |
|
894 (uint8_t *) kmalloc(EC_CAT_MEM, GFP_ATOMIC))) { |
|
895 EC_ERR("FSM Failed to allocate category data.\n"); |
|
896 fsm->slave_state = ec_fsm_slave_end; |
|
897 return; |
|
898 } |
|
899 |
|
900 // start reading first category header |
|
901 fsm->sii_offset = fsm->slave_cat_offset; |
|
902 fsm->sii_state = ec_fsm_sii_start_reading; |
|
903 |
|
904 fsm->slave_state = ec_fsm_slave_category_header; |
|
905 fsm->slave_state(fsm); // execute state immediately |
|
906 return; |
|
907 } |
|
908 |
|
909 fsm->slave_sii_num++; |
|
910 fsm->sii_state = ec_fsm_sii_start_reading; |
|
911 fsm->slave_state(fsm); // execute state immediately |
|
912 } |
|
913 |
|
914 /*****************************************************************************/ |
|
915 |
|
916 /** |
|
917 Slave state: CATEGORY_HEADER. |
|
918 Start reading categories. |
|
919 */ |
|
920 |
|
921 void ec_fsm_slave_category_header(ec_fsm_t *fsm /**< finite state machine */) |
|
922 { |
|
923 // execute SII state machine |
|
924 fsm->sii_state(fsm); |
|
925 |
|
926 if (fsm->sii_state == ec_fsm_sii_error) { |
|
927 kfree(fsm->slave_cat_data); |
|
928 fsm->slave_cat_data = NULL; |
|
929 fsm->slave_state = ec_fsm_slave_end; |
|
930 EC_ERR("FSM failed to read category header at 0x%04X on slave %i.\n", |
|
931 fsm->slave_cat_offset, fsm->slave->ring_position); |
|
932 return; |
|
933 } |
|
934 |
|
935 if (fsm->sii_state != ec_fsm_sii_end) return; |
|
936 |
|
937 // last category? |
|
938 if ((fsm->sii_result & 0xFFFF) == 0xFFFF) { |
|
939 kfree(fsm->slave_cat_data); |
|
940 fsm->slave_cat_data = NULL; |
|
941 fsm->slave_state = ec_fsm_slave_end; |
|
942 return; |
|
943 } |
|
944 |
|
945 fsm->slave_cat_type = fsm->sii_result & 0x7FFF; |
|
946 fsm->slave_cat_words = (fsm->sii_result >> 16) & 0xFFFF; |
|
947 |
|
948 if (fsm->slave_cat_words > EC_CAT_MEM * 2) { |
|
949 EC_ERR("FSM category memory too small! %i words needed.\n", |
|
950 fsm->slave_cat_words); |
|
951 fsm->slave_state = ec_fsm_slave_end; |
|
952 return; |
|
953 } |
|
954 |
|
955 // start reading category data |
|
956 fsm->slave_cat_data_offset = 0; |
|
957 fsm->sii_offset = (fsm->slave_cat_offset + 2 + |
|
958 fsm->slave_cat_data_offset); |
|
959 fsm->sii_mode = 1; |
|
960 fsm->sii_state = ec_fsm_sii_start_reading; |
|
961 fsm->slave_state = ec_fsm_slave_category_data; |
|
962 fsm->slave_state(fsm); // execute state immediately |
|
963 } |
|
964 |
|
965 /*****************************************************************************/ |
|
966 |
|
967 /** |
|
968 Slave state: CATEGORY_DATA. |
|
969 Reads category data. |
|
970 */ |
|
971 |
|
972 void ec_fsm_slave_category_data(ec_fsm_t *fsm /**< finite state machine */) |
|
973 { |
|
974 // execute SII state machine |
|
975 fsm->sii_state(fsm); |
|
976 |
|
977 if (fsm->sii_state == ec_fsm_sii_error) { |
|
978 kfree(fsm->slave_cat_data); |
|
979 fsm->slave_cat_data = NULL; |
|
980 fsm->slave_state = ec_fsm_slave_end; |
|
981 EC_ERR("FSM failed to read category 0x%02X data at 0x%04X" |
|
982 " on slave %i.\n", fsm->slave_cat_type, fsm->sii_offset, |
|
983 fsm->slave->ring_position); |
|
984 return; |
|
985 } |
|
986 |
|
987 if (fsm->sii_state != ec_fsm_sii_end) return; |
|
988 |
|
989 fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] = |
|
990 fsm->sii_result & 0xFF; |
|
991 fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] = |
|
992 (fsm->sii_result >> 8) & 0xFF; |
|
993 |
|
994 // read second word "on the fly" |
|
995 if (fsm->slave_cat_data_offset + 1 < fsm->slave_cat_words) { |
|
996 fsm->slave_cat_data_offset++; |
|
997 fsm->slave_cat_data[fsm->slave_cat_data_offset * 2] = |
|
998 (fsm->sii_result >> 16) & 0xFF; |
|
999 fsm->slave_cat_data[fsm->slave_cat_data_offset * 2 + 1] = |
|
1000 (fsm->sii_result >> 24) & 0xFF; |
|
1001 } |
|
1002 |
|
1003 fsm->slave_cat_data_offset++; |
|
1004 |
|
1005 if (fsm->slave_cat_data_offset < fsm->slave_cat_words) { |
|
1006 fsm->sii_offset = (fsm->slave_cat_offset + 2 + |
|
1007 fsm->slave_cat_data_offset); |
|
1008 fsm->sii_mode = 1; |
|
1009 fsm->sii_state = ec_fsm_sii_start_reading; |
|
1010 fsm->slave_state = ec_fsm_slave_category_data; |
|
1011 fsm->slave_state(fsm); // execute state immediately |
|
1012 return; |
|
1013 } |
|
1014 |
|
1015 // category data complete |
|
1016 switch (fsm->slave_cat_type) |
|
1017 { |
|
1018 case 0x000A: |
|
1019 if (ec_slave_fetch_strings(fsm->slave, fsm->slave_cat_data)) |
|
1020 goto out_free; |
|
1021 break; |
|
1022 case 0x001E: |
|
1023 if (ec_slave_fetch_general(fsm->slave, fsm->slave_cat_data)) |
|
1024 goto out_free; |
|
1025 break; |
|
1026 case 0x0028: |
|
1027 break; |
|
1028 case 0x0029: |
|
1029 if (ec_slave_fetch_sync(fsm->slave, fsm->slave_cat_data, |
|
1030 fsm->slave_cat_words)) |
|
1031 goto out_free; |
|
1032 break; |
|
1033 case 0x0032: |
|
1034 if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data, |
|
1035 fsm->slave_cat_words, |
|
1036 EC_TX_PDO)) |
|
1037 goto out_free; |
|
1038 break; |
|
1039 case 0x0033: |
|
1040 if (ec_slave_fetch_pdo(fsm->slave, fsm->slave_cat_data, |
|
1041 fsm->slave_cat_words, |
|
1042 EC_RX_PDO)) |
|
1043 goto out_free; |
|
1044 break; |
|
1045 default: |
|
1046 EC_WARN("FSM: Unknown category type 0x%04X in slave %i.\n", |
|
1047 fsm->slave_cat_type, fsm->slave->ring_position); |
|
1048 } |
|
1049 |
|
1050 // start reading next category header |
|
1051 fsm->slave_cat_offset += 2 + fsm->slave_cat_words; |
|
1052 fsm->sii_offset = fsm->slave_cat_offset; |
|
1053 fsm->sii_mode = 1; |
|
1054 fsm->sii_state = ec_fsm_sii_start_reading; |
|
1055 fsm->slave_state = ec_fsm_slave_category_header; |
|
1056 fsm->slave_state(fsm); // execute state immediately |
|
1057 return; |
|
1058 |
|
1059 out_free: |
|
1060 kfree(fsm->slave_cat_data); |
|
1061 fsm->slave_cat_data = NULL; |
|
1062 fsm->slave_state = ec_fsm_slave_end; |
|
1063 } |
|
1064 |
|
1065 /*****************************************************************************/ |
|
1066 |
|
1067 /** |
|
1068 Slave state: CONF. |
|
1069 */ |
|
1070 |
|
1071 void ec_fsm_slave_conf(ec_fsm_t *fsm /**< finite state machine */) |
|
1072 { |
|
1073 ec_slave_t *slave = fsm->slave; |
|
1074 ec_master_t *master = fsm->master; |
|
1075 ec_command_t *command = &fsm->command; |
|
1076 |
|
1077 fsm->change_state(fsm); // execute state change state machine |
|
1078 |
|
1079 if (fsm->change_state == ec_fsm_change_error) { |
|
1080 fsm->slave_state = ec_fsm_slave_end; |
|
1081 return; |
|
1082 } |
|
1083 |
|
1084 if (fsm->change_state != ec_fsm_change_end) return; |
|
1085 |
|
1086 // slave is now in INIT |
|
1087 if (slave->current_state == slave->requested_state) { |
|
1088 fsm->slave_state = ec_fsm_slave_end; |
|
1089 return; |
|
1090 } |
|
1091 |
|
1092 // check for slave registration |
|
1093 if (!slave->type) { |
|
1094 EC_WARN("Slave %i has unknown type!\n", slave->ring_position); |
|
1095 } |
|
1096 |
|
1097 // check and reset CRC fault counters |
|
1098 //ec_slave_check_crc(slave); |
|
1099 |
|
1100 if (!slave->base_fmmu_count) { // no fmmus |
|
1101 fsm->slave_state = ec_fsm_slave_sync; |
|
1102 fsm->slave_state(fsm); // execute immediately |
|
1103 return; |
|
1104 } |
|
1105 |
|
1106 // reset FMMUs |
|
1107 ec_command_npwr(command, slave->station_address, 0x0600, |
|
1108 EC_FMMU_SIZE * slave->base_fmmu_count); |
|
1109 memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
1110 ec_master_queue_command(master, command); |
|
1111 fsm->slave_state = ec_fsm_slave_sync; |
|
1112 } |
|
1113 |
|
1114 /*****************************************************************************/ |
|
1115 |
|
1116 /** |
|
1117 Slave state: SYNC. |
|
1118 Configure sync managers. |
|
1119 */ |
|
1120 |
|
1121 void ec_fsm_slave_sync(ec_fsm_t *fsm /**< finite state machine */) |
|
1122 { |
|
1123 ec_command_t *command = &fsm->command; |
|
1124 ec_slave_t *slave = fsm->slave; |
|
1125 unsigned int j; |
|
1126 const ec_sync_t *sync; |
|
1127 ec_eeprom_sync_t *eeprom_sync, mbox_sync; |
|
1128 |
|
1129 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1130 EC_ERR("Failed to reset FMMUs of slave %i.\n", |
|
1131 slave->ring_position); |
|
1132 slave->state_error = 1; |
|
1133 fsm->slave_state = ec_fsm_slave_end; |
|
1134 return; |
|
1135 } |
|
1136 |
|
1137 if (!slave->base_sync_count) { // no sync managers |
|
1138 fsm->slave_state = ec_fsm_slave_preop; |
|
1139 fsm->slave_state(fsm); // execute immediately |
|
1140 return; |
|
1141 } |
|
1142 |
|
1143 // configure sync managers |
|
1144 ec_command_npwr(command, slave->station_address, 0x0800, |
|
1145 EC_SYNC_SIZE * slave->base_sync_count); |
|
1146 memset(command->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); |
|
1147 |
|
1148 // known slave type, take type's SM information |
|
1149 if (slave->type) { |
|
1150 for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) { |
|
1151 sync = slave->type->sync_managers[j]; |
|
1152 ec_sync_config(sync, command->data + EC_SYNC_SIZE * j); |
|
1153 } |
|
1154 } |
|
1155 |
|
1156 // unknown type, but slave has mailbox |
|
1157 else if (slave->sii_mailbox_protocols) |
|
1158 { |
|
1159 // does it supply sync manager configurations in its EEPROM? |
|
1160 if (!list_empty(&slave->eeprom_syncs)) { |
|
1161 list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) { |
|
1162 if (eeprom_sync->index >= slave->base_sync_count) { |
|
1163 EC_ERR("Invalid sync manager configuration found!"); |
|
1164 fsm->slave_state = ec_fsm_slave_end; |
|
1165 return; |
|
1166 } |
|
1167 ec_eeprom_sync_config(eeprom_sync, |
|
1168 command->data + EC_SYNC_SIZE |
|
1169 * eeprom_sync->index); |
|
1170 } |
|
1171 } |
|
1172 |
|
1173 // no sync manager information; guess mailbox settings |
|
1174 else { |
|
1175 mbox_sync.physical_start_address = |
|
1176 slave->sii_rx_mailbox_offset; |
|
1177 mbox_sync.length = slave->sii_rx_mailbox_size; |
|
1178 mbox_sync.control_register = 0x26; |
|
1179 mbox_sync.enable = 1; |
|
1180 ec_eeprom_sync_config(&mbox_sync, command->data); |
|
1181 |
|
1182 mbox_sync.physical_start_address = |
|
1183 slave->sii_tx_mailbox_offset; |
|
1184 mbox_sync.length = slave->sii_tx_mailbox_size; |
|
1185 mbox_sync.control_register = 0x22; |
|
1186 mbox_sync.enable = 1; |
|
1187 ec_eeprom_sync_config(&mbox_sync, |
|
1188 command->data + EC_SYNC_SIZE); |
|
1189 } |
|
1190 |
|
1191 EC_INFO("Mailbox configured for unknown slave %i\n", |
|
1192 slave->ring_position); |
|
1193 } |
|
1194 |
|
1195 ec_master_queue_command(fsm->master, command); |
|
1196 fsm->slave_state = ec_fsm_slave_preop; |
|
1197 } |
|
1198 |
|
1199 /*****************************************************************************/ |
|
1200 |
|
1201 /** |
|
1202 Slave state: PREOP. |
|
1203 Change slave state to PREOP. |
|
1204 */ |
|
1205 |
|
1206 void ec_fsm_slave_preop(ec_fsm_t *fsm /**< finite state machine */) |
|
1207 { |
|
1208 ec_command_t *command = &fsm->command; |
|
1209 ec_slave_t *slave = fsm->slave; |
|
1210 |
|
1211 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1212 EC_ERR("Failed to set sync managers on slave %i.\n", |
|
1213 slave->ring_position); |
|
1214 slave->state_error = 1; |
|
1215 fsm->slave_state = ec_fsm_slave_end; |
|
1216 return; |
|
1217 } |
|
1218 |
|
1219 fsm->change_new = EC_SLAVE_STATE_PREOP; |
|
1220 fsm->change_state = ec_fsm_change_start; |
|
1221 fsm->slave_state = ec_fsm_slave_fmmu; |
|
1222 fsm->change_state(fsm); // execute immediately |
|
1223 } |
|
1224 |
|
1225 /*****************************************************************************/ |
|
1226 |
|
1227 /** |
|
1228 Slave state: FMMU. |
|
1229 Configure FMMUs. |
|
1230 */ |
|
1231 |
|
1232 void ec_fsm_slave_fmmu(ec_fsm_t *fsm /**< finite state machine */) |
|
1233 { |
|
1234 ec_slave_t *slave = fsm->slave; |
|
1235 ec_master_t *master = fsm->master; |
|
1236 ec_command_t *command = &fsm->command; |
|
1237 unsigned int j; |
|
1238 |
|
1239 fsm->change_state(fsm); // execute state change state machine |
|
1240 |
|
1241 if (fsm->change_state == ec_fsm_change_error) { |
|
1242 fsm->slave_state = ec_fsm_slave_end; |
|
1243 return; |
|
1244 } |
|
1245 |
|
1246 if (fsm->change_state != ec_fsm_change_end) return; |
|
1247 |
|
1248 // slave is now in PREOP |
|
1249 if (slave->current_state == slave->requested_state) { |
|
1250 fsm->slave_state = ec_fsm_slave_end; |
|
1251 return; |
|
1252 } |
|
1253 |
|
1254 // stop activation here for slaves without type |
|
1255 if (!slave->type) { |
|
1256 fsm->slave_state = ec_fsm_slave_end; |
|
1257 return; |
|
1258 } |
|
1259 |
|
1260 if (!slave->base_fmmu_count) { |
|
1261 fsm->slave_state = ec_fsm_slave_saveop; |
|
1262 fsm->slave_state(fsm); // execute immediately |
|
1263 return; |
|
1264 } |
|
1265 |
|
1266 // configure FMMUs |
|
1267 ec_command_npwr(command, slave->station_address, |
|
1268 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
1269 memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
1270 for (j = 0; j < slave->fmmu_count; j++) { |
|
1271 ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j); |
|
1272 } |
|
1273 |
|
1274 ec_master_queue_command(master, command); |
|
1275 fsm->slave_state = ec_fsm_slave_saveop; |
|
1276 } |
|
1277 |
|
1278 /*****************************************************************************/ |
|
1279 |
|
1280 /** |
|
1281 Slave state: SAVEOP. |
|
1282 Set slave state to SAVEOP. |
|
1283 */ |
|
1284 |
|
1285 void ec_fsm_slave_saveop(ec_fsm_t *fsm /**< finite state machine */) |
|
1286 { |
|
1287 ec_command_t *command = &fsm->command; |
|
1288 |
|
1289 if (fsm->slave->base_fmmu_count && (command->state != EC_CMD_RECEIVED || |
|
1290 command->working_counter != 1)) { |
|
1291 EC_ERR("FSM failed to set FMMUs on slave %i.\n", |
|
1292 fsm->slave->ring_position); |
|
1293 fsm->slave->state_error = 1; |
|
1294 fsm->slave_state = ec_fsm_slave_end; |
|
1295 return; |
|
1296 } |
|
1297 |
|
1298 // set state to SAVEOP |
|
1299 fsm->slave_state = ec_fsm_slave_op; |
|
1300 fsm->change_new = EC_SLAVE_STATE_SAVEOP; |
|
1301 fsm->change_state = ec_fsm_change_start; |
|
1302 fsm->change_state(fsm); // execute immediately |
|
1303 } |
|
1304 |
|
1305 /*****************************************************************************/ |
|
1306 |
|
1307 /** |
|
1308 Slave state: OP. |
|
1309 Set slave state to OP. |
|
1310 */ |
|
1311 |
|
1312 void ec_fsm_slave_op(ec_fsm_t *fsm /**< finite state machine */) |
|
1313 { |
|
1314 fsm->change_state(fsm); // execute state change state machine |
|
1315 |
|
1316 if (fsm->change_state == ec_fsm_change_error) { |
|
1317 fsm->slave_state = ec_fsm_slave_end; |
|
1318 return; |
|
1319 } |
|
1320 |
|
1321 if (fsm->change_state != ec_fsm_change_end) return; |
|
1322 |
|
1323 // slave is now in SAVEOP |
|
1324 if (fsm->slave->current_state == fsm->slave->requested_state) { |
|
1325 fsm->slave_state = ec_fsm_slave_end; |
|
1326 return; |
|
1327 } |
|
1328 |
|
1329 // set state to OP |
|
1330 fsm->slave_state = ec_fsm_slave_op2; |
|
1331 fsm->change_new = EC_SLAVE_STATE_OP; |
|
1332 fsm->change_state = ec_fsm_change_start; |
|
1333 fsm->change_state(fsm); // execute immediately |
|
1334 } |
|
1335 |
|
1336 /*****************************************************************************/ |
|
1337 |
|
1338 /** |
|
1339 Slave state: OP2 |
|
1340 Executes the change state machine, until the OP state is set. |
|
1341 */ |
|
1342 |
|
1343 void ec_fsm_slave_op2(ec_fsm_t *fsm /**< finite state machine */) |
|
1344 { |
|
1345 fsm->change_state(fsm); // execute state change state machine |
|
1346 |
|
1347 if (fsm->change_state == ec_fsm_change_error) { |
|
1348 fsm->slave_state = ec_fsm_slave_end; |
|
1349 return; |
|
1350 } |
|
1351 |
|
1352 if (fsm->change_state != ec_fsm_change_end) return; |
|
1353 |
|
1354 // slave is now in OP |
|
1355 fsm->slave_state = ec_fsm_slave_end; |
|
1356 } |
|
1357 |
|
1358 /*****************************************************************************/ |
|
1359 |
|
1360 /** |
|
1361 Slave state: END. |
|
1362 End state of the slave state machine. |
|
1363 */ |
|
1364 |
|
1365 void ec_fsm_slave_end(ec_fsm_t *fsm /**< finite state machine */) |
|
1366 { |
|
1367 } |
|
1368 |
|
1369 /****************************************************************************** |
|
1370 * SII state machine |
|
1371 *****************************************************************************/ |
|
1372 |
|
1373 /** |
|
1374 SII state: START_READING. |
|
1375 Starts reading the slave information interface. |
|
1376 */ |
|
1377 |
|
1378 void ec_fsm_sii_start_reading(ec_fsm_t *fsm /**< finite state machine */) |
|
1379 { |
|
1380 ec_command_t *command = &fsm->command; |
|
1381 |
|
1382 // initiate read operation |
|
1383 if (fsm->sii_mode) { |
|
1384 ec_command_npwr(command, fsm->slave->station_address, 0x502, 4); |
|
1385 } |
|
1386 else { |
|
1387 ec_command_apwr(command, fsm->slave->ring_position, 0x502, 4); |
|
1388 } |
|
1389 |
|
1390 EC_WRITE_U8 (command->data, 0x00); // read-only access |
|
1391 EC_WRITE_U8 (command->data + 1, 0x01); // request read operation |
|
1392 EC_WRITE_U16(command->data + 2, fsm->sii_offset); |
|
1393 ec_master_queue_command(fsm->master, command); |
|
1394 fsm->sii_state = ec_fsm_sii_check; |
|
1395 } |
|
1396 |
|
1397 /*****************************************************************************/ |
|
1398 |
|
1399 /** |
|
1400 SII state: CHECK. |
|
1401 Checks, if the SII-read-command has been sent and issues a fetch command. |
|
1402 */ |
|
1403 |
|
1404 void ec_fsm_sii_check(ec_fsm_t *fsm /**< finite state machine */) |
|
1405 { |
|
1406 ec_command_t *command = &fsm->command; |
|
1407 |
|
1408 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1409 EC_ERR("SII: Reception of read command failed.\n"); |
|
1410 fsm->sii_state = ec_fsm_sii_error; |
|
1411 return; |
|
1412 } |
|
1413 |
|
1414 fsm->sii_start = get_cycles(); |
|
1415 |
|
1416 // issue check/fetch command |
|
1417 if (fsm->sii_mode) { |
|
1418 ec_command_nprd(command, fsm->slave->station_address, 0x502, 10); |
|
1419 } |
|
1420 else { |
|
1421 ec_command_aprd(command, fsm->slave->ring_position, 0x502, 10); |
|
1422 } |
|
1423 |
|
1424 ec_master_queue_command(fsm->master, command); |
|
1425 fsm->sii_state = ec_fsm_sii_fetch; |
|
1426 } |
|
1427 |
|
1428 /*****************************************************************************/ |
|
1429 |
|
1430 /** |
|
1431 SII state: FETCH. |
|
1432 Fetches the result of an SII-read command. |
|
1433 */ |
|
1434 |
|
1435 void ec_fsm_sii_fetch(ec_fsm_t *fsm /**< finite state machine */) |
|
1436 { |
|
1437 ec_command_t *command = &fsm->command; |
|
1438 |
|
1439 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1440 EC_ERR("SII: Reception of check/fetch command failed.\n"); |
|
1441 fsm->sii_state = ec_fsm_sii_error; |
|
1442 return; |
|
1443 } |
|
1444 |
|
1445 // check "busy bit" |
|
1446 if (EC_READ_U8(command->data + 1) & 0x81) { |
|
1447 // still busy... timeout? |
|
1448 if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) { |
|
1449 EC_ERR("SII: Timeout.\n"); |
|
1450 fsm->sii_state = ec_fsm_sii_error; |
|
1451 #if 0 |
|
1452 EC_DBG("SII busy: %02X %02X %02X %02X\n", |
|
1453 EC_READ_U8(command->data + 0), |
|
1454 EC_READ_U8(command->data + 1), |
|
1455 EC_READ_U8(command->data + 2), |
|
1456 EC_READ_U8(command->data + 3)); |
|
1457 #endif |
|
1458 } |
|
1459 |
|
1460 // issue check/fetch command again |
|
1461 if (fsm->sii_mode) { |
|
1462 ec_command_nprd(command, fsm->slave->station_address, 0x502, 10); |
|
1463 } |
|
1464 else { |
|
1465 ec_command_aprd(command, fsm->slave->ring_position, 0x502, 10); |
|
1466 } |
|
1467 ec_master_queue_command(fsm->master, command); |
|
1468 return; |
|
1469 } |
|
1470 |
|
1471 #if 0 |
|
1472 EC_DBG("SII rec: %02X %02X %02X %02X - %02X %02X %02X %02X\n", |
|
1473 EC_READ_U8(command->data + 0), EC_READ_U8(command->data + 1), |
|
1474 EC_READ_U8(command->data + 2), EC_READ_U8(command->data + 3), |
|
1475 EC_READ_U8(command->data + 6), EC_READ_U8(command->data + 7), |
|
1476 EC_READ_U8(command->data + 8), EC_READ_U8(command->data + 9)); |
|
1477 #endif |
|
1478 |
|
1479 // SII value received. |
|
1480 fsm->sii_result = EC_READ_U32(command->data + 6); |
|
1481 fsm->sii_state = ec_fsm_sii_end; |
|
1482 } |
|
1483 |
|
1484 /*****************************************************************************/ |
|
1485 |
|
1486 /** |
|
1487 SII state: END. |
|
1488 End state of the slave SII state machine. |
|
1489 */ |
|
1490 |
|
1491 void ec_fsm_sii_end(ec_fsm_t *fsm /**< finite state machine */) |
|
1492 { |
|
1493 } |
|
1494 |
|
1495 /*****************************************************************************/ |
|
1496 |
|
1497 /** |
|
1498 SII state: ERROR. |
|
1499 End state of the slave SII state machine. |
|
1500 */ |
|
1501 |
|
1502 void ec_fsm_sii_error(ec_fsm_t *fsm /**< finite state machine */) |
|
1503 { |
|
1504 } |
|
1505 |
|
1506 /****************************************************************************** |
|
1507 * state change state machine |
|
1508 *****************************************************************************/ |
|
1509 |
|
1510 /** |
|
1511 Change state: START. |
|
1512 */ |
|
1513 |
|
1514 void ec_fsm_change_start(ec_fsm_t *fsm /**< finite state machine */) |
|
1515 { |
|
1516 ec_command_t *command = &fsm->command; |
|
1517 ec_slave_t *slave = fsm->slave; |
|
1518 |
|
1519 // write new state to slave |
|
1520 ec_command_npwr(command, slave->station_address, 0x0120, 2); |
|
1521 EC_WRITE_U16(command->data, fsm->change_new); |
|
1522 ec_master_queue_command(fsm->master, command); |
|
1523 fsm->change_state = ec_fsm_change_check; |
|
1524 } |
|
1525 |
|
1526 /*****************************************************************************/ |
|
1527 |
|
1528 /** |
|
1529 Change state: CHECK. |
|
1530 */ |
|
1531 |
|
1532 void ec_fsm_change_check(ec_fsm_t *fsm /**< finite state machine */) |
|
1533 { |
|
1534 ec_command_t *command = &fsm->command; |
|
1535 ec_slave_t *slave = fsm->slave; |
|
1536 |
|
1537 if (command->state != EC_CMD_RECEIVED) { |
|
1538 EC_ERR("Failed to send state command to slave %i!\n", |
|
1539 fsm->slave->ring_position); |
|
1540 slave->state_error = 1; |
|
1541 fsm->change_state = ec_fsm_change_error; |
|
1542 return; |
|
1543 } |
|
1544 |
|
1545 if (command->working_counter != 1) { |
|
1546 EC_ERR("Failed to set state 0x%02X on slave %i: Slave did not" |
|
1547 " respond.\n", fsm->change_new, fsm->slave->ring_position); |
|
1548 slave->state_error = 1; |
|
1549 fsm->change_state = ec_fsm_change_error; |
|
1550 return; |
|
1551 } |
|
1552 |
|
1553 fsm->change_start = get_cycles(); |
|
1554 |
|
1555 // read AL status from slave |
|
1556 ec_command_nprd(command, slave->station_address, 0x0130, 2); |
|
1557 ec_master_queue_command(fsm->master, command); |
|
1558 fsm->change_state = ec_fsm_change_status; |
|
1559 } |
|
1560 |
|
1561 /*****************************************************************************/ |
|
1562 |
|
1563 /** |
|
1564 Change state: STATUS. |
|
1565 */ |
|
1566 |
|
1567 void ec_fsm_change_status(ec_fsm_t *fsm /**< finite state machine */) |
|
1568 { |
|
1569 ec_command_t *command = &fsm->command; |
|
1570 ec_slave_t *slave = fsm->slave; |
|
1571 |
|
1572 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1573 EC_ERR("Failed to check state 0x%02X on slave %i.\n", |
|
1574 fsm->change_new, slave->ring_position); |
|
1575 slave->state_error = 1; |
|
1576 fsm->change_state = ec_fsm_change_error; |
|
1577 return; |
|
1578 } |
|
1579 |
|
1580 slave->current_state = EC_READ_U8(command->data); |
|
1581 |
|
1582 if (slave->current_state == fsm->change_new) { |
|
1583 // state has been set successfully |
|
1584 fsm->change_state = ec_fsm_change_end; |
|
1585 return; |
|
1586 } |
|
1587 |
|
1588 if (slave->current_state & 0x10) { |
|
1589 // state change error |
|
1590 fsm->change_new = slave->current_state & 0x0F; |
|
1591 EC_ERR("Failed to set state 0x%02X - Slave %i refused state change" |
|
1592 " (code 0x%02X)!\n", fsm->change_new, slave->ring_position, |
|
1593 slave->current_state); |
|
1594 // fetch AL status error code |
|
1595 ec_command_nprd(command, slave->station_address, 0x0134, 2); |
|
1596 ec_master_queue_command(fsm->master, command); |
|
1597 fsm->change_state = ec_fsm_change_code; |
|
1598 return; |
|
1599 } |
|
1600 |
|
1601 if (get_cycles() - fsm->change_start >= (cycles_t) 10 * cpu_khz) { |
|
1602 // timeout while checking |
|
1603 slave->state_error = 1; |
|
1604 fsm->change_state = ec_fsm_change_error; |
|
1605 EC_ERR("Timeout while setting state 0x%02X on slave %i.\n", |
|
1606 fsm->change_new, slave->ring_position); |
|
1607 return; |
|
1608 } |
|
1609 |
|
1610 // still old state: check again |
|
1611 ec_command_nprd(command, slave->station_address, 0x0130, 2); |
|
1612 ec_master_queue_command(fsm->master, command); |
|
1613 } |
|
1614 |
|
1615 /*****************************************************************************/ |
|
1616 |
|
1617 /** |
|
1618 Change state: CODE. |
|
1619 */ |
|
1620 |
|
1621 void ec_fsm_change_code(ec_fsm_t *fsm /**< finite state machine */) |
|
1622 { |
|
1623 ec_command_t *command = &fsm->command; |
|
1624 ec_slave_t *slave = fsm->slave; |
|
1625 uint32_t code; |
|
1626 const ec_code_msg_t *al_msg; |
|
1627 |
|
1628 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1629 EC_ERR("Reception of AL status code command failed.\n"); |
|
1630 slave->state_error = 1; |
|
1631 fsm->change_state = ec_fsm_change_error; |
|
1632 return; |
|
1633 } |
|
1634 |
|
1635 if ((code = EC_READ_U16(command->data))) { |
|
1636 for (al_msg = al_status_messages; al_msg->code; al_msg++) { |
|
1637 if (al_msg->code != code) continue; |
|
1638 EC_ERR("AL status message 0x%04X: \"%s\".\n", |
|
1639 al_msg->code, al_msg->message); |
|
1640 break; |
|
1641 } |
|
1642 if (!al_msg->code) |
|
1643 EC_ERR("Unknown AL status code 0x%04X.\n", code); |
|
1644 } |
|
1645 |
|
1646 // acknowledge "old" slave state |
|
1647 ec_command_npwr(command, slave->station_address, 0x0120, 2); |
|
1648 EC_WRITE_U16(command->data, slave->current_state); |
|
1649 ec_master_queue_command(fsm->master, command); |
|
1650 fsm->change_state = ec_fsm_change_ack; |
|
1651 } |
|
1652 |
|
1653 /*****************************************************************************/ |
|
1654 |
|
1655 /** |
|
1656 Change state: ACK. |
|
1657 */ |
|
1658 |
|
1659 void ec_fsm_change_ack(ec_fsm_t *fsm /**< finite state machine */) |
|
1660 { |
|
1661 ec_command_t *command = &fsm->command; |
|
1662 ec_slave_t *slave = fsm->slave; |
|
1663 |
|
1664 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1665 EC_ERR("Reception of state ack command failed.\n"); |
|
1666 slave->state_error = 1; |
|
1667 fsm->change_state = ec_fsm_change_error; |
|
1668 return; |
|
1669 } |
|
1670 |
|
1671 // read new AL status |
|
1672 ec_command_nprd(command, slave->station_address, 0x0130, 2); |
|
1673 ec_master_queue_command(fsm->master, command); |
|
1674 fsm->change_state = ec_fsm_change_ack2; |
|
1675 } |
|
1676 |
|
1677 /*****************************************************************************/ |
|
1678 |
|
1679 /** |
|
1680 Change state: ACK. |
|
1681 Acknowledge 2. |
|
1682 */ |
|
1683 |
|
1684 void ec_fsm_change_ack2(ec_fsm_t *fsm /**< finite state machine */) |
|
1685 { |
|
1686 ec_command_t *command = &fsm->command; |
|
1687 ec_slave_t *slave = fsm->slave; |
|
1688 |
|
1689 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1690 EC_ERR("Reception of state ack check command failed.\n"); |
|
1691 slave->state_error = 1; |
|
1692 fsm->change_state = ec_fsm_change_error; |
|
1693 return; |
|
1694 } |
|
1695 |
|
1696 slave->current_state = EC_READ_U8(command->data); |
|
1697 |
|
1698 if (slave->current_state == fsm->change_new) { |
|
1699 EC_INFO("Acknowleged state 0x%02X on slave %i.\n", |
|
1700 slave->current_state, slave->ring_position); |
|
1701 slave->state_error = 1; |
|
1702 fsm->change_state = ec_fsm_change_error; |
|
1703 return; |
|
1704 } |
|
1705 |
|
1706 EC_WARN("Failed to acknowledge state 0x%02X on slave %i" |
|
1707 " - Timeout!\n", fsm->change_new, slave->ring_position); |
|
1708 slave->state_error = 1; |
|
1709 fsm->change_state = ec_fsm_change_error; |
|
1710 } |
|
1711 |
|
1712 /*****************************************************************************/ |
|
1713 |
|
1714 /** |
|
1715 Change state: END. |
|
1716 */ |
|
1717 |
|
1718 void ec_fsm_change_end(ec_fsm_t *fsm /**< finite state machine */) |
|
1719 { |
|
1720 } |
|
1721 |
|
1722 /*****************************************************************************/ |
|
1723 |
|
1724 /** |
|
1725 Change state: ERROR. |
|
1726 */ |
|
1727 |
|
1728 void ec_fsm_change_error(ec_fsm_t *fsm /**< finite state machine */) |
|
1729 { |
|
1730 } |
|
1731 |
|
1732 /*****************************************************************************/ |
|
1733 |
|
1734 /** |
|
1735 Application layer status messages. |
|
1736 */ |
|
1737 |
|
1738 const ec_code_msg_t al_status_messages[] = { |
|
1739 {0x0001, "Unspecified error"}, |
|
1740 {0x0011, "Invalud requested state change"}, |
|
1741 {0x0012, "Unknown requested state"}, |
|
1742 {0x0013, "Bootstrap not supported"}, |
|
1743 {0x0014, "No valid firmware"}, |
|
1744 {0x0015, "Invalid mailbox configuration"}, |
|
1745 {0x0016, "Invalid mailbox configuration"}, |
|
1746 {0x0017, "Invalid sync manager configuration"}, |
|
1747 {0x0018, "No valid inputs available"}, |
|
1748 {0x0019, "No valid outputs"}, |
|
1749 {0x001A, "Synchronisation error"}, |
|
1750 {0x001B, "Sync manager watchdog"}, |
|
1751 {0x0020, "Slave needs cold start"}, |
|
1752 {0x0021, "Slave needs INIT"}, |
|
1753 {0x0022, "Slave needs PREOP"}, |
|
1754 {0x0023, "Slave needs SAVEOP"}, |
|
1755 {} |
|
1756 }; |
|
1757 |
|
1758 /*****************************************************************************/ |