46 |
46 |
47 #define EC_CAT_MEM 0x100 |
47 #define EC_CAT_MEM 0x100 |
48 |
48 |
49 /*****************************************************************************/ |
49 /*****************************************************************************/ |
50 |
50 |
|
51 const ec_code_msg_t al_status_messages[]; |
|
52 |
|
53 /*****************************************************************************/ |
|
54 |
51 void ec_fsm_master_start(ec_fsm_t *); |
55 void ec_fsm_master_start(ec_fsm_t *); |
52 void ec_fsm_master_wait(ec_fsm_t *); |
56 void ec_fsm_master_wait(ec_fsm_t *); |
53 void ec_fsm_master_slave(ec_fsm_t *); |
57 void ec_fsm_master_scan(ec_fsm_t *); |
54 void ec_fsm_master_calc(ec_fsm_t *); |
58 void ec_fsm_master_conf(ec_fsm_t *); |
55 void ec_fsm_master_finished(ec_fsm_t *); |
59 |
56 |
60 void ec_fsm_slave_start_reading(ec_fsm_t *); |
57 void ec_fsm_slave_start(ec_fsm_t *); |
|
58 void ec_fsm_slave_read_base(ec_fsm_t *); |
61 void ec_fsm_slave_read_base(ec_fsm_t *); |
59 void ec_fsm_slave_read_dl(ec_fsm_t *); |
62 void ec_fsm_slave_read_dl(ec_fsm_t *); |
60 void ec_fsm_slave_prepare_sii(ec_fsm_t *); |
63 void ec_fsm_slave_prepare_sii(ec_fsm_t *); |
61 void ec_fsm_slave_read_sii(ec_fsm_t *); |
64 void ec_fsm_slave_read_sii(ec_fsm_t *); |
62 void ec_fsm_slave_categories(ec_fsm_t *); |
|
63 void ec_fsm_slave_category_header(ec_fsm_t *); |
65 void ec_fsm_slave_category_header(ec_fsm_t *); |
64 void ec_fsm_slave_category_data(ec_fsm_t *); |
66 void ec_fsm_slave_category_data(ec_fsm_t *); |
65 void ec_fsm_slave_finished(ec_fsm_t *); |
67 void ec_fsm_slave_conf(ec_fsm_t *); |
|
68 void ec_fsm_slave_end(ec_fsm_t *); |
|
69 |
|
70 void ec_fsm_slave_conf(ec_fsm_t *); |
|
71 void ec_fsm_slave_sync(ec_fsm_t *); |
|
72 void ec_fsm_slave_preop(ec_fsm_t *); |
|
73 void ec_fsm_slave_fmmu(ec_fsm_t *); |
|
74 void ec_fsm_slave_saveop(ec_fsm_t *); |
|
75 void ec_fsm_slave_op(ec_fsm_t *); |
|
76 void ec_fsm_slave_op2(ec_fsm_t *); |
66 |
77 |
67 void ec_fsm_sii_start_reading(ec_fsm_t *); |
78 void ec_fsm_sii_start_reading(ec_fsm_t *); |
68 void ec_fsm_sii_check(ec_fsm_t *); |
79 void ec_fsm_sii_check(ec_fsm_t *); |
69 void ec_fsm_sii_fetch(ec_fsm_t *); |
80 void ec_fsm_sii_fetch(ec_fsm_t *); |
70 void ec_fsm_sii_finished(ec_fsm_t *); |
81 void ec_fsm_sii_finished(ec_fsm_t *); |
71 void ec_fsm_sii_error(ec_fsm_t *); |
82 void ec_fsm_sii_error(ec_fsm_t *); |
72 |
83 |
|
84 void ec_fsm_change_start(ec_fsm_t *); |
|
85 void ec_fsm_change_check(ec_fsm_t *); |
|
86 void ec_fsm_change_status(ec_fsm_t *); |
|
87 void ec_fsm_change_code(ec_fsm_t *); |
|
88 void ec_fsm_change_ack(ec_fsm_t *); |
|
89 void ec_fsm_change_ack2(ec_fsm_t *); |
|
90 void ec_fsm_change_end(ec_fsm_t *); |
|
91 void ec_fsm_change_error(ec_fsm_t *); |
|
92 |
73 /*****************************************************************************/ |
93 /*****************************************************************************/ |
74 |
94 |
75 int ec_fsm_init(ec_fsm_t *fsm, ec_master_t *master) |
95 int ec_fsm_init(ec_fsm_t *fsm, ec_master_t *master) |
76 { |
96 { |
77 fsm->master = master; |
97 fsm->master = master; |
147 /*****************************************************************************/ |
158 /*****************************************************************************/ |
148 |
159 |
149 void ec_fsm_master_wait(ec_fsm_t *fsm) |
160 void ec_fsm_master_wait(ec_fsm_t *fsm) |
150 { |
161 { |
151 ec_command_t *command = &fsm->command; |
162 ec_command_t *command = &fsm->command; |
152 unsigned int first, topology_change, i; |
163 unsigned int topology_change, i, eoe_slaves_active; |
153 ec_slave_t *slave; |
164 ec_slave_t *slave; |
154 |
165 |
155 if (command->state != EC_CMD_RECEIVED) { |
166 if (command->state != EC_CMD_RECEIVED) { |
156 fsm->master_state = ec_fsm_master_start; |
167 fsm->master_state = ec_fsm_master_start; |
157 fsm->master_state(fsm); // execute immediately |
168 fsm->master_state(fsm); // execute immediately |
158 return; |
169 return; |
159 } |
170 } |
160 |
171 |
161 if (command->working_counter == fsm->master_slaves_responding && |
172 if (command->working_counter == fsm->master_slaves_responding && |
162 command->data[0] == fsm->master_slave_states) { |
173 command->data[0] == fsm->master_slave_states) |
|
174 { |
|
175 // check if any slaves are not in the state, they're supposed to be |
|
176 list_for_each_entry(slave, &fsm->master->slaves, list) { |
|
177 if (slave->state_error || |
|
178 slave->requested_state == EC_SLAVE_STATE_UNKNOWN || |
|
179 slave->current_state == slave->requested_state) continue; |
|
180 |
|
181 EC_INFO("Changing state of slave %i from ", slave->ring_position); |
|
182 ec_print_states(slave->current_state); |
|
183 printk(" to "); |
|
184 ec_print_states(slave->requested_state); |
|
185 printk(".\n"); |
|
186 |
|
187 fsm->slave = slave; |
|
188 fsm->slave_state = ec_fsm_slave_conf; |
|
189 |
|
190 fsm->change_new = EC_SLAVE_STATE_INIT; |
|
191 fsm->change_state = ec_fsm_change_start; |
|
192 |
|
193 fsm->master_state = ec_fsm_master_conf; |
|
194 fsm->master_state(fsm); // execute immediately |
|
195 return; |
|
196 } |
|
197 |
|
198 // nothing to configure... |
|
199 eoe_slaves_active = 0; |
|
200 list_for_each_entry(slave, &fsm->master->slaves, list) { |
|
201 if (slave->sii_mailbox_protocols & EC_MBOX_EOE) { |
|
202 eoe_slaves_active++; |
|
203 } |
|
204 } |
|
205 |
|
206 if (eoe_slaves_active && !list_empty(&fsm->master->eoe_handlers)) |
|
207 ec_master_eoe_start(fsm->master); |
|
208 |
163 fsm->master_state = ec_fsm_master_start; |
209 fsm->master_state = ec_fsm_master_start; |
164 fsm->master_state(fsm); // execute immediately |
210 fsm->master_state(fsm); // execute immediately |
165 return; |
211 return; |
166 } |
212 } |
167 |
213 |
214 // init slaves |
243 // init slaves |
215 for (i = 0; i < fsm->master_slaves_responding; i++) { |
244 for (i = 0; i < fsm->master_slaves_responding; i++) { |
216 if (!(slave = |
245 if (!(slave = |
217 (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_ATOMIC))) { |
246 (ec_slave_t *) kmalloc(sizeof(ec_slave_t), GFP_ATOMIC))) { |
218 EC_ERR("FSM failed to allocate slave %i!\n", i); |
247 EC_ERR("FSM failed to allocate slave %i!\n", i); |
219 fsm->master_state = ec_fsm_master_finished; |
248 fsm->master_state = ec_fsm_master_start; |
220 return; |
249 return; |
221 } |
250 } |
222 |
251 |
223 if (ec_slave_init(slave, fsm->master, i, i + 1)) { |
252 if (ec_slave_init(slave, fsm->master, i, i + 1)) { |
224 fsm->master_state = ec_fsm_master_finished; |
253 fsm->master_state = ec_fsm_master_start; |
225 return; |
254 return; |
226 } |
255 } |
227 |
256 |
228 if (kobject_add(&slave->kobj)) { |
257 if (kobject_add(&slave->kobj)) { |
229 EC_ERR("FSM failed to add kobject.\n"); |
258 EC_ERR("FSM failed to add kobject.\n"); |
230 kobject_put(&slave->kobj); // free |
259 kobject_put(&slave->kobj); // free |
231 fsm->master_state = ec_fsm_master_finished; |
260 fsm->master_state = ec_fsm_master_start; |
232 return; |
261 return; |
233 } |
262 } |
234 |
263 |
235 list_add_tail(&slave->list, &fsm->master->slaves); |
264 list_add_tail(&slave->list, &fsm->master->slaves); |
236 } |
265 } |
237 |
266 |
238 // begin scanning of slaves |
267 // begin scanning of slaves |
239 fsm->slave = list_entry(fsm->master->slaves.next, |
268 fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list); |
240 ec_slave_t, list); |
269 fsm->slave_state = ec_fsm_slave_start_reading; |
241 fsm->slave_state = ec_fsm_slave_start; |
270 |
242 |
271 fsm->master_state = ec_fsm_master_scan; |
243 fsm->master_state = ec_fsm_master_slave; |
|
244 fsm->master_state(fsm); // execute immediately |
272 fsm->master_state(fsm); // execute immediately |
245 } |
273 } |
246 |
274 |
247 /*****************************************************************************/ |
275 /*****************************************************************************/ |
248 |
276 |
249 /** |
277 /** |
250 State: Get Slave. |
278 State: Get Slave. |
251 Executes the sub-statemachine of a slave. |
279 Executes the sub-statemachine of a slave. |
252 */ |
280 */ |
253 |
281 |
254 void ec_fsm_master_slave(ec_fsm_t *fsm) |
282 void ec_fsm_master_scan(ec_fsm_t *fsm) |
255 { |
283 { |
256 ec_master_t *master = fsm->master; |
284 ec_master_t *master = fsm->master; |
|
285 ec_slave_t *slave = fsm->slave; |
257 |
286 |
258 fsm->slave_state(fsm); // execute slave state machine |
287 fsm->slave_state(fsm); // execute slave state machine |
259 |
288 |
260 if (fsm->slave_state != ec_fsm_slave_finished) return; |
289 if (fsm->slave_state != ec_fsm_slave_end) return; |
261 |
290 |
262 // have all slaves been fetched? |
291 // have all slaves been fetched? |
263 if (fsm->slave->list.next == &master->slaves) { |
292 if (slave->list.next == &master->slaves) |
264 fsm->master_state = ec_fsm_master_calc; |
293 { |
|
294 uint16_t coupler_index, coupler_subindex; |
|
295 uint16_t reverse_coupler_index, current_coupler_index; |
|
296 ec_slave_t *slave; |
|
297 ec_slave_ident_t *ident; |
|
298 |
|
299 EC_INFO("Bus scanning completed.\n"); |
|
300 |
|
301 // identify all slaves and calculate coupler addressing |
|
302 |
|
303 coupler_index = 0; |
|
304 reverse_coupler_index = 0xFFFF; |
|
305 current_coupler_index = 0x3FFF; |
|
306 coupler_subindex = 0; |
|
307 |
|
308 list_for_each_entry(slave, &master->slaves, list) |
|
309 { |
|
310 // search for identification in "database" |
|
311 ident = slave_idents; |
|
312 while (ident->type) { |
|
313 if (ident->vendor_id == slave->sii_vendor_id |
|
314 && ident->product_code == slave->sii_product_code) { |
|
315 slave->type = ident->type; |
|
316 break; |
|
317 } |
|
318 ident++; |
|
319 } |
|
320 |
|
321 if (!slave->type) { |
|
322 EC_WARN("FSM: Unknown slave device (vendor 0x%08X," |
|
323 " code 0x%08X) at position %i.\n", |
|
324 slave->sii_vendor_id, slave->sii_product_code, |
|
325 slave->ring_position); |
|
326 } |
|
327 else { |
|
328 // if the slave is a bus coupler, change adressing base |
|
329 if (slave->type->special == EC_TYPE_BUS_COUPLER) { |
|
330 if (slave->sii_alias) |
|
331 current_coupler_index = reverse_coupler_index--; |
|
332 else |
|
333 current_coupler_index = coupler_index++; |
|
334 coupler_subindex = 0; |
|
335 } |
|
336 } |
|
337 |
|
338 // determine initial state. |
|
339 if ((slave->type && slave->type->special == EC_TYPE_BUS_COUPLER)) { |
|
340 slave->requested_state = EC_SLAVE_STATE_OP; |
|
341 } |
|
342 else { |
|
343 if (master->mode == EC_MASTER_MODE_RUNNING) |
|
344 slave->requested_state = EC_SLAVE_STATE_PREOP; |
|
345 else |
|
346 slave->requested_state = EC_SLAVE_STATE_INIT; |
|
347 } |
|
348 |
|
349 // calculate coupler-based slave address |
|
350 slave->coupler_index = current_coupler_index; |
|
351 slave->coupler_subindex = coupler_subindex; |
|
352 coupler_subindex++; |
|
353 } |
|
354 |
|
355 fsm->master_state = ec_fsm_master_start; |
265 fsm->master_state(fsm); // execute immediately |
356 fsm->master_state(fsm); // execute immediately |
266 return; |
357 return; |
267 } |
358 } |
268 |
359 |
269 // process next slave |
360 // process next slave |
270 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
361 fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list); |
271 fsm->slave_state = ec_fsm_slave_start; |
362 fsm->slave_state = ec_fsm_slave_start_reading; |
272 fsm->slave_state(fsm); // execute immediately |
363 fsm->slave_state(fsm); // execute immediately |
273 } |
364 } |
274 |
365 |
275 /*****************************************************************************/ |
366 /*****************************************************************************/ |
276 |
367 |
277 /** |
368 /** |
278 Free-Run state: Calc. |
369 Free-Run state: Configure slaves. |
279 */ |
370 */ |
280 |
371 |
281 void ec_fsm_master_calc(ec_fsm_t *fsm) |
372 void ec_fsm_master_conf(ec_fsm_t *fsm) |
282 { |
373 { |
283 uint16_t coupler_index, coupler_subindex; |
374 ec_master_t *master = fsm->master; |
284 uint16_t reverse_coupler_index, current_coupler_index; |
|
285 ec_slave_t *slave; |
375 ec_slave_t *slave; |
286 ec_slave_ident_t *ident; |
376 |
287 ec_master_t *master = fsm->master; |
377 fsm->slave_state(fsm); // execute slave's state machine |
288 |
378 |
289 coupler_index = 0; |
379 if (fsm->slave_state != ec_fsm_slave_end) return; |
290 reverse_coupler_index = 0xFFFF; |
380 |
291 current_coupler_index = 0x3FFF; |
381 // check if any slaves are not in the state, they're supposed to be |
292 coupler_subindex = 0; |
382 list_for_each_entry(slave, &master->slaves, list) { |
293 |
383 if (slave->state_error || |
294 // for every slave on the bus |
384 slave->requested_state == EC_SLAVE_STATE_UNKNOWN || |
295 list_for_each_entry(slave, &master->slaves, list) |
385 slave->current_state == slave->requested_state) continue; |
296 { |
386 |
297 // search for identification in "database" |
387 EC_INFO("Changing state of slave %i from ", slave->ring_position); |
298 ident = slave_idents; |
388 ec_print_states(slave->current_state); |
299 while (ident->type) { |
389 printk(" to "); |
300 if (unlikely(ident->vendor_id == slave->sii_vendor_id |
390 ec_print_states(slave->requested_state); |
301 && ident->product_code == slave->sii_product_code)) { |
391 printk(".\n"); |
302 slave->type = ident->type; |
392 |
303 break; |
393 fsm->slave = slave; |
304 } |
394 fsm->slave_state = ec_fsm_slave_conf; |
305 ident++; |
395 |
306 } |
396 fsm->change_new = EC_SLAVE_STATE_INIT; |
307 |
397 fsm->change_state = ec_fsm_change_start; |
308 if (!slave->type) { |
398 |
309 EC_WARN("FSM: Unknown slave device (vendor 0x%08X, code 0x%08X) at" |
399 fsm->master_state = ec_fsm_master_conf; |
310 " position %i.\n", slave->sii_vendor_id, |
400 fsm->master_state(fsm); // execute immediately |
311 slave->sii_product_code, slave->ring_position); |
401 return; |
312 } |
|
313 else if (slave->type->special == EC_TYPE_BUS_COUPLER) { |
|
314 if (slave->sii_alias) |
|
315 current_coupler_index = reverse_coupler_index--; |
|
316 else |
|
317 current_coupler_index = coupler_index++; |
|
318 coupler_subindex = 0; |
|
319 } |
|
320 |
|
321 slave->coupler_index = current_coupler_index; |
|
322 slave->coupler_subindex = coupler_subindex; |
|
323 coupler_subindex++; |
|
324 } |
402 } |
325 |
403 |
326 fsm->master_state = ec_fsm_master_start; |
404 fsm->master_state = ec_fsm_master_start; |
327 fsm->master_state(fsm); // execute immediately |
405 fsm->master_state(fsm); // execute immediately |
328 } |
|
329 |
|
330 /*****************************************************************************/ |
|
331 |
|
332 /** |
|
333 Free-Run state: Finished. |
|
334 End state of the state machine. Does nothing. |
|
335 */ |
|
336 |
|
337 void ec_fsm_master_finished(ec_fsm_t *fsm) |
|
338 { |
|
339 } |
406 } |
340 |
407 |
341 /****************************************************************************** |
408 /****************************************************************************** |
342 * slave state machine |
409 * slave state machine |
343 *****************************************************************************/ |
410 *****************************************************************************/ |
688 return; |
745 return; |
689 |
746 |
690 out_free: |
747 out_free: |
691 kfree(fsm->slave_cat_data); |
748 kfree(fsm->slave_cat_data); |
692 fsm->slave_cat_data = NULL; |
749 fsm->slave_cat_data = NULL; |
693 fsm->slave_state = ec_fsm_slave_finished; |
750 fsm->slave_state = ec_fsm_slave_end; |
694 } |
751 } |
695 |
752 |
696 /*****************************************************************************/ |
753 /*****************************************************************************/ |
697 |
754 |
698 /** |
755 /** |
699 Slave state: Finished. |
756 Slave state: Start configuring. |
|
757 */ |
|
758 |
|
759 void ec_fsm_slave_conf(ec_fsm_t *fsm) |
|
760 { |
|
761 ec_slave_t *slave = fsm->slave; |
|
762 ec_master_t *master = fsm->master; |
|
763 ec_command_t *command = &fsm->command; |
|
764 |
|
765 fsm->change_state(fsm); // execute state change state machine |
|
766 |
|
767 if (fsm->change_state == ec_fsm_change_error) { |
|
768 fsm->slave_state = ec_fsm_slave_end; |
|
769 return; |
|
770 } |
|
771 |
|
772 if (fsm->change_state != ec_fsm_change_end) return; |
|
773 |
|
774 // slave is now in INIT |
|
775 if (slave->current_state == slave->requested_state) { |
|
776 fsm->slave_state = ec_fsm_slave_end; |
|
777 return; |
|
778 } |
|
779 |
|
780 // check for slave registration |
|
781 if (!slave->type) { |
|
782 EC_WARN("Slave %i has unknown type!\n", slave->ring_position); |
|
783 } |
|
784 |
|
785 // check and reset CRC fault counters |
|
786 //ec_slave_check_crc(slave); |
|
787 |
|
788 if (!slave->base_fmmu_count) { // no fmmus |
|
789 fsm->slave_state = ec_fsm_slave_sync; |
|
790 fsm->slave_state(fsm); // execute immediately |
|
791 return; |
|
792 } |
|
793 |
|
794 // reset FMMUs |
|
795 ec_command_npwr(command, slave->station_address, 0x0600, |
|
796 EC_FMMU_SIZE * slave->base_fmmu_count); |
|
797 memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
798 ec_master_queue_command(master, command); |
|
799 fsm->slave_state = ec_fsm_slave_sync; |
|
800 } |
|
801 |
|
802 /*****************************************************************************/ |
|
803 |
|
804 /** |
|
805 Slave state: Configure sync managers. |
|
806 */ |
|
807 |
|
808 void ec_fsm_slave_sync(ec_fsm_t *fsm) |
|
809 { |
|
810 ec_command_t *command = &fsm->command; |
|
811 ec_slave_t *slave = fsm->slave; |
|
812 unsigned int j; |
|
813 const ec_sync_t *sync; |
|
814 ec_eeprom_sync_t *eeprom_sync, mbox_sync; |
|
815 |
|
816 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
817 EC_ERR("FSM failed to reset FMMUs of slave %i.\n", |
|
818 slave->ring_position); |
|
819 fsm->slave_state = ec_fsm_slave_end; |
|
820 return; |
|
821 } |
|
822 |
|
823 if (!slave->base_sync_count) { // no sync managers |
|
824 fsm->slave_state = ec_fsm_slave_preop; |
|
825 fsm->slave_state(fsm); // execute immediately |
|
826 return; |
|
827 } |
|
828 |
|
829 // configure sync managers |
|
830 ec_command_npwr(command, slave->station_address, 0x0800, |
|
831 EC_SYNC_SIZE * slave->base_sync_count); |
|
832 memset(command->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count); |
|
833 |
|
834 // known slave type, take type's SM information |
|
835 if (slave->type) { |
|
836 for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) { |
|
837 sync = slave->type->sync_managers[j]; |
|
838 ec_sync_config(sync, command->data + EC_SYNC_SIZE * j); |
|
839 } |
|
840 } |
|
841 |
|
842 // unknown type, but slave has mailbox |
|
843 else if (slave->sii_mailbox_protocols) |
|
844 { |
|
845 // does it supply sync manager configurations in its EEPROM? |
|
846 if (!list_empty(&slave->eeprom_syncs)) { |
|
847 list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) { |
|
848 if (eeprom_sync->index >= slave->base_sync_count) { |
|
849 EC_ERR("Invalid sync manager configuration found!"); |
|
850 fsm->slave_state = ec_fsm_slave_end; |
|
851 return; |
|
852 } |
|
853 ec_eeprom_sync_config(eeprom_sync, |
|
854 command->data + EC_SYNC_SIZE |
|
855 * eeprom_sync->index); |
|
856 } |
|
857 } |
|
858 |
|
859 // no sync manager information; guess mailbox settings |
|
860 else { |
|
861 mbox_sync.physical_start_address = |
|
862 slave->sii_rx_mailbox_offset; |
|
863 mbox_sync.length = slave->sii_rx_mailbox_size; |
|
864 mbox_sync.control_register = 0x26; |
|
865 mbox_sync.enable = 1; |
|
866 ec_eeprom_sync_config(&mbox_sync, command->data); |
|
867 |
|
868 mbox_sync.physical_start_address = |
|
869 slave->sii_tx_mailbox_offset; |
|
870 mbox_sync.length = slave->sii_tx_mailbox_size; |
|
871 mbox_sync.control_register = 0x22; |
|
872 mbox_sync.enable = 1; |
|
873 ec_eeprom_sync_config(&mbox_sync, |
|
874 command->data + EC_SYNC_SIZE); |
|
875 } |
|
876 |
|
877 EC_INFO("Mailbox configured for unknown slave %i\n", |
|
878 slave->ring_position); |
|
879 } |
|
880 |
|
881 ec_master_queue_command(fsm->master, command); |
|
882 fsm->slave_state = ec_fsm_slave_preop; |
|
883 } |
|
884 |
|
885 /*****************************************************************************/ |
|
886 |
|
887 /** |
|
888 Slave state: Change slave state to PREOP. |
|
889 */ |
|
890 |
|
891 void ec_fsm_slave_preop(ec_fsm_t *fsm) |
|
892 { |
|
893 ec_command_t *command = &fsm->command; |
|
894 ec_slave_t *slave = fsm->slave; |
|
895 |
|
896 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
897 EC_ERR("FSM failed to set sync managers on slave %i.\n", |
|
898 slave->ring_position); |
|
899 fsm->slave_state = ec_fsm_slave_end; |
|
900 return; |
|
901 } |
|
902 |
|
903 fsm->change_new = EC_SLAVE_STATE_PREOP; |
|
904 fsm->change_state = ec_fsm_change_start; |
|
905 |
|
906 fsm->slave_state = ec_fsm_slave_fmmu; |
|
907 |
|
908 fsm->change_state(fsm); // execute immediately |
|
909 } |
|
910 |
|
911 /*****************************************************************************/ |
|
912 |
|
913 /** |
|
914 Slave state: Configure FMMUs. |
|
915 */ |
|
916 |
|
917 void ec_fsm_slave_fmmu(ec_fsm_t *fsm) |
|
918 { |
|
919 ec_slave_t *slave = fsm->slave; |
|
920 ec_master_t *master = fsm->master; |
|
921 ec_command_t *command = &fsm->command; |
|
922 unsigned int j; |
|
923 |
|
924 fsm->change_state(fsm); // execute state change state machine |
|
925 |
|
926 if (fsm->change_state == ec_fsm_change_error) { |
|
927 fsm->slave_state = ec_fsm_slave_end; |
|
928 return; |
|
929 } |
|
930 |
|
931 if (fsm->change_state != ec_fsm_change_end) return; |
|
932 |
|
933 // slave is now in PREOP |
|
934 if (slave->current_state == slave->requested_state) { |
|
935 fsm->slave_state = ec_fsm_slave_end; |
|
936 return; |
|
937 } |
|
938 |
|
939 // stop activation here for slaves without type |
|
940 if (!slave->type) { |
|
941 fsm->slave_state = ec_fsm_slave_end; |
|
942 return; |
|
943 } |
|
944 |
|
945 #if 0 |
|
946 // slaves that are not registered are only brought into PREOP |
|
947 // state -> nice blinking and mailbox communication possible |
|
948 if (!slave->registered && !slave->type->special) { |
|
949 EC_WARN("Slave %i was not registered!\n", slave->ring_position); |
|
950 fsm->slave_state = ec_fsm_slave_end; |
|
951 return; |
|
952 } |
|
953 #endif |
|
954 |
|
955 if (!slave->base_fmmu_count) { |
|
956 fsm->slave_state = ec_fsm_slave_saveop; |
|
957 fsm->slave_state(fsm); // execute immediately |
|
958 return; |
|
959 } |
|
960 |
|
961 // configure FMMUs |
|
962 ec_command_npwr(command, slave->station_address, |
|
963 0x0600, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
964 memset(command->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count); |
|
965 for (j = 0; j < slave->fmmu_count; j++) { |
|
966 ec_fmmu_config(&slave->fmmus[j], command->data + EC_FMMU_SIZE * j); |
|
967 } |
|
968 |
|
969 ec_master_queue_command(master, command); |
|
970 fsm->slave_state = ec_fsm_slave_saveop; |
|
971 } |
|
972 |
|
973 /*****************************************************************************/ |
|
974 |
|
975 /** |
|
976 Slave state: Set slave state to SAVEOP. |
|
977 */ |
|
978 |
|
979 void ec_fsm_slave_saveop(ec_fsm_t *fsm) |
|
980 { |
|
981 ec_command_t *command = &fsm->command; |
|
982 |
|
983 if (fsm->slave->base_fmmu_count && (command->state != EC_CMD_RECEIVED || |
|
984 command->working_counter != 1)) { |
|
985 EC_ERR("FSM failed to set FMMUs on slave %i.\n", |
|
986 fsm->slave->ring_position); |
|
987 fsm->slave_state = ec_fsm_slave_end; |
|
988 return; |
|
989 } |
|
990 |
|
991 // set state to SAVEOP |
|
992 fsm->slave_state = ec_fsm_slave_op; |
|
993 fsm->change_new = EC_SLAVE_STATE_SAVEOP; |
|
994 fsm->change_state = ec_fsm_change_start; |
|
995 fsm->change_state(fsm); // execute immediately |
|
996 } |
|
997 |
|
998 /*****************************************************************************/ |
|
999 |
|
1000 /** |
|
1001 Slave state: Set slave state to OP. |
|
1002 */ |
|
1003 |
|
1004 void ec_fsm_slave_op(ec_fsm_t *fsm) |
|
1005 { |
|
1006 fsm->change_state(fsm); // execute state change state machine |
|
1007 |
|
1008 if (fsm->change_state == ec_fsm_change_error) { |
|
1009 fsm->slave_state = ec_fsm_slave_end; |
|
1010 return; |
|
1011 } |
|
1012 |
|
1013 if (fsm->change_state != ec_fsm_change_end) return; |
|
1014 |
|
1015 // slave is now in SAVEOP |
|
1016 if (fsm->slave->current_state == fsm->slave->requested_state) { |
|
1017 fsm->slave_state = ec_fsm_slave_end; |
|
1018 return; |
|
1019 } |
|
1020 |
|
1021 // set state to OP |
|
1022 fsm->slave_state = ec_fsm_slave_op2; |
|
1023 fsm->change_new = EC_SLAVE_STATE_OP; |
|
1024 fsm->change_state = ec_fsm_change_start; |
|
1025 fsm->change_state(fsm); // execute immediately |
|
1026 } |
|
1027 |
|
1028 /*****************************************************************************/ |
|
1029 |
|
1030 /** |
|
1031 Slave state: Set slave state to OP. |
|
1032 */ |
|
1033 |
|
1034 void ec_fsm_slave_op2(ec_fsm_t *fsm) |
|
1035 { |
|
1036 fsm->change_state(fsm); // execute state change state machine |
|
1037 |
|
1038 if (fsm->change_state == ec_fsm_change_error) { |
|
1039 fsm->slave_state = ec_fsm_slave_end; |
|
1040 return; |
|
1041 } |
|
1042 |
|
1043 if (fsm->change_state != ec_fsm_change_end) return; |
|
1044 |
|
1045 // slave is now in OP |
|
1046 fsm->slave_state = ec_fsm_slave_end; |
|
1047 } |
|
1048 |
|
1049 /*****************************************************************************/ |
|
1050 |
|
1051 /** |
|
1052 Slave state: End. |
700 End state of the slave state machine. |
1053 End state of the slave state machine. |
701 */ |
1054 */ |
702 |
1055 |
703 void ec_fsm_slave_finished(ec_fsm_t *fsm) |
1056 void ec_fsm_slave_end(ec_fsm_t *fsm) |
704 { |
1057 { |
705 } |
1058 } |
706 |
1059 |
707 /****************************************************************************** |
1060 /****************************************************************************** |
708 * SII state machine |
1061 * SII state machine |
792 |
1145 |
793 void ec_fsm_sii_error(ec_fsm_t *fsm) |
1146 void ec_fsm_sii_error(ec_fsm_t *fsm) |
794 { |
1147 { |
795 } |
1148 } |
796 |
1149 |
797 /*****************************************************************************/ |
1150 /****************************************************************************** |
|
1151 * state change state machine |
|
1152 *****************************************************************************/ |
|
1153 |
|
1154 /** |
|
1155 State change state: Start. |
|
1156 */ |
|
1157 |
|
1158 void ec_fsm_change_start(ec_fsm_t *fsm) |
|
1159 { |
|
1160 ec_command_t *command = &fsm->command; |
|
1161 ec_slave_t *slave = fsm->slave; |
|
1162 |
|
1163 // write new state to slave |
|
1164 ec_command_npwr(command, slave->station_address, 0x0120, 2); |
|
1165 EC_WRITE_U16(command->data, fsm->change_new); |
|
1166 ec_master_queue_command(fsm->master, command); |
|
1167 fsm->change_state = ec_fsm_change_check; |
|
1168 } |
|
1169 |
|
1170 /*****************************************************************************/ |
|
1171 |
|
1172 /** |
|
1173 State change state: Check. |
|
1174 */ |
|
1175 |
|
1176 void ec_fsm_change_check(ec_fsm_t *fsm) |
|
1177 { |
|
1178 ec_command_t *command = &fsm->command; |
|
1179 ec_slave_t *slave = fsm->slave; |
|
1180 |
|
1181 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1182 EC_ERR("FSM: Reception of state command failed.\n"); |
|
1183 slave->state_error = 1; |
|
1184 fsm->change_state = ec_fsm_change_error; |
|
1185 return; |
|
1186 } |
|
1187 |
|
1188 //start = get_cycles(); |
|
1189 //timeout = (cycles_t) 10 * cpu_khz; // 10ms |
|
1190 |
|
1191 // read AL status from slave |
|
1192 ec_command_nprd(command, slave->station_address, 0x0130, 2); |
|
1193 ec_master_queue_command(fsm->master, command); |
|
1194 fsm->change_state = ec_fsm_change_status; |
|
1195 } |
|
1196 |
|
1197 /*****************************************************************************/ |
|
1198 |
|
1199 /** |
|
1200 State change state: Status. |
|
1201 */ |
|
1202 |
|
1203 void ec_fsm_change_status(ec_fsm_t *fsm) |
|
1204 { |
|
1205 ec_command_t *command = &fsm->command; |
|
1206 ec_slave_t *slave = fsm->slave; |
|
1207 |
|
1208 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1209 EC_ERR("FSM: Reception of state check command failed.\n"); |
|
1210 slave->state_error = 1; |
|
1211 fsm->change_state = ec_fsm_change_error; |
|
1212 return; |
|
1213 } |
|
1214 |
|
1215 slave->current_state = EC_READ_U8(command->data); |
|
1216 |
|
1217 if (slave->current_state & 0x10) { // state change error |
|
1218 EC_ERR("Failed to set state 0x%02X - Slave %i refused state change" |
|
1219 " (code 0x%02X)!\n", fsm->change_new, slave->ring_position, |
|
1220 slave->current_state); |
|
1221 |
|
1222 fsm->change_new = slave->current_state & 0x0F; |
|
1223 |
|
1224 // fetch AL status error code |
|
1225 ec_command_nprd(command, slave->station_address, 0x0134, 2); |
|
1226 ec_master_queue_command(fsm->master, command); |
|
1227 fsm->change_state = ec_fsm_change_code; |
|
1228 return; |
|
1229 } |
|
1230 |
|
1231 if (slave->current_state == fsm->change_new) { |
|
1232 fsm->change_state = ec_fsm_change_end; |
|
1233 return; |
|
1234 } |
|
1235 |
|
1236 EC_ERR("Failed to check state 0x%02X of slave %i - Timeout!\n", |
|
1237 fsm->change_new, slave->ring_position); |
|
1238 slave->state_error = 1; |
|
1239 fsm->change_state = ec_fsm_change_error; |
|
1240 } |
|
1241 |
|
1242 /*****************************************************************************/ |
|
1243 |
|
1244 /** |
|
1245 State change state: Code. |
|
1246 */ |
|
1247 |
|
1248 void ec_fsm_change_code(ec_fsm_t *fsm) |
|
1249 { |
|
1250 ec_command_t *command = &fsm->command; |
|
1251 ec_slave_t *slave = fsm->slave; |
|
1252 uint32_t code; |
|
1253 const ec_code_msg_t *al_msg; |
|
1254 |
|
1255 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1256 EC_ERR("FSM: Reception of AL status code command failed.\n"); |
|
1257 slave->state_error = 1; |
|
1258 fsm->change_state = ec_fsm_change_error; |
|
1259 return; |
|
1260 } |
|
1261 |
|
1262 if ((code = EC_READ_U16(command->data))) { |
|
1263 for (al_msg = al_status_messages; al_msg->code; al_msg++) { |
|
1264 if (al_msg->code != code) continue; |
|
1265 EC_ERR("AL status message 0x%04X: \"%s\".\n", |
|
1266 al_msg->code, al_msg->message); |
|
1267 break; |
|
1268 } |
|
1269 if (!al_msg->code) |
|
1270 EC_ERR("Unknown AL status code 0x%04X.\n", code); |
|
1271 } |
|
1272 |
|
1273 // acknowledge "old" slave state |
|
1274 ec_command_npwr(command, slave->station_address, 0x0120, 2); |
|
1275 EC_WRITE_U16(command->data, slave->current_state); |
|
1276 ec_master_queue_command(fsm->master, command); |
|
1277 fsm->change_state = ec_fsm_change_ack; |
|
1278 } |
|
1279 |
|
1280 /*****************************************************************************/ |
|
1281 |
|
1282 /** |
|
1283 State change state: Acknowledge. |
|
1284 */ |
|
1285 |
|
1286 void ec_fsm_change_ack(ec_fsm_t *fsm) |
|
1287 { |
|
1288 ec_command_t *command = &fsm->command; |
|
1289 ec_slave_t *slave = fsm->slave; |
|
1290 |
|
1291 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1292 EC_ERR("FSM: Reception of state ack command failed.\n"); |
|
1293 slave->state_error = 1; |
|
1294 fsm->change_state = ec_fsm_change_error; |
|
1295 return; |
|
1296 } |
|
1297 |
|
1298 // read new AL status |
|
1299 ec_command_nprd(command, slave->station_address, 0x0130, 2); |
|
1300 ec_master_queue_command(fsm->master, command); |
|
1301 fsm->change_state = ec_fsm_change_ack2; |
|
1302 } |
|
1303 |
|
1304 /*****************************************************************************/ |
|
1305 |
|
1306 /** |
|
1307 State change state: Acknowledge 2. |
|
1308 */ |
|
1309 |
|
1310 void ec_fsm_change_ack2(ec_fsm_t *fsm) |
|
1311 { |
|
1312 ec_command_t *command = &fsm->command; |
|
1313 ec_slave_t *slave = fsm->slave; |
|
1314 |
|
1315 if (command->state != EC_CMD_RECEIVED || command->working_counter != 1) { |
|
1316 EC_ERR("FSM: Reception of state ack check command failed.\n"); |
|
1317 slave->state_error = 1; |
|
1318 fsm->change_state = ec_fsm_change_error; |
|
1319 return; |
|
1320 } |
|
1321 |
|
1322 slave->current_state = EC_READ_U8(command->data); |
|
1323 |
|
1324 if (slave->current_state == fsm->change_new) { |
|
1325 EC_INFO("Acknowleged state 0x%02X on slave %i.\n", |
|
1326 slave->current_state, slave->ring_position); |
|
1327 slave->state_error = 1; |
|
1328 fsm->change_state = ec_fsm_change_error; |
|
1329 return; |
|
1330 } |
|
1331 |
|
1332 EC_WARN("Failed to acknowledge state 0x%02X on slave %i" |
|
1333 " - Timeout!\n", fsm->change_new, slave->ring_position); |
|
1334 slave->state_error = 1; |
|
1335 fsm->change_state = ec_fsm_change_error; |
|
1336 } |
|
1337 |
|
1338 /*****************************************************************************/ |
|
1339 |
|
1340 /** |
|
1341 State change state: End. |
|
1342 */ |
|
1343 |
|
1344 void ec_fsm_change_end(ec_fsm_t *fsm) |
|
1345 { |
|
1346 } |
|
1347 |
|
1348 /*****************************************************************************/ |
|
1349 |
|
1350 /** |
|
1351 State change state: Error. |
|
1352 */ |
|
1353 |
|
1354 void ec_fsm_change_error(ec_fsm_t *fsm) |
|
1355 { |
|
1356 } |
|
1357 |
|
1358 /*****************************************************************************/ |
|
1359 |
|
1360 /** |
|
1361 Application layer status messages. |
|
1362 */ |
|
1363 |
|
1364 const ec_code_msg_t al_status_messages[] = { |
|
1365 {0x0001, "Unspecified error"}, |
|
1366 {0x0011, "Invalud requested state change"}, |
|
1367 {0x0012, "Unknown requested state"}, |
|
1368 {0x0013, "Bootstrap not supported"}, |
|
1369 {0x0014, "No valid firmware"}, |
|
1370 {0x0015, "Invalid mailbox configuration"}, |
|
1371 {0x0016, "Invalid mailbox configuration"}, |
|
1372 {0x0017, "Invalid sync manager configuration"}, |
|
1373 {0x0018, "No valid inputs available"}, |
|
1374 {0x0019, "No valid outputs"}, |
|
1375 {0x001A, "Synchronisation error"}, |
|
1376 {0x001B, "Sync manager watchdog"}, |
|
1377 {0x0020, "Slave needs cold start"}, |
|
1378 {0x0021, "Slave needs INIT"}, |
|
1379 {0x0022, "Slave needs PREOP"}, |
|
1380 {0x0023, "Slave needs SAVEOP"}, |
|
1381 {} |
|
1382 }; |
|
1383 |
|
1384 /*****************************************************************************/ |