fsm.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  *  $Id: fsm.c 490 2006-08-02 12:25:25Z fp $
00004  *
00005  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
00006  *
00007  *  This file is part of the IgH EtherCAT Master.
00008  *
00009  *  The IgH EtherCAT Master is free software; you can redistribute it
00010  *  and/or modify it under the terms of the GNU General Public License
00011  *  as published by the Free Software Foundation; either version 2 of the
00012  *  License, or (at your option) any later version.
00013  *
00014  *  The IgH EtherCAT Master is distributed in the hope that it will be
00015  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with the IgH EtherCAT Master; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  *  The right to use EtherCAT Technology is granted and comes free of
00024  *  charge under condition of compatibility of product made by
00025  *  Licensee. People intending to distribute/sell products based on the
00026  *  code, have to sign an agreement to guarantee that products using
00027  *  software based on IgH EtherCAT master stay compatible with the actual
00028  *  EtherCAT specification (which are released themselves as an open
00029  *  standard) as the (only) precondition to have the right to use EtherCAT
00030  *  Technology, IP and trade marks.
00031  *
00032  *****************************************************************************/
00033 
00039 /*****************************************************************************/
00040 
00041 #include "globals.h"
00042 #include "fsm.h"
00043 #include "master.h"
00044 
00045 /*****************************************************************************/
00046 
00047 void ec_fsm_master_start(ec_fsm_t *);
00048 void ec_fsm_master_broadcast(ec_fsm_t *);
00049 void ec_fsm_master_read_states(ec_fsm_t *);
00050 void ec_fsm_master_validate_vendor(ec_fsm_t *);
00051 void ec_fsm_master_validate_product(ec_fsm_t *);
00052 void ec_fsm_master_rewrite_addresses(ec_fsm_t *);
00053 void ec_fsm_master_configure_slave(ec_fsm_t *);
00054 void ec_fsm_master_scan_slaves(ec_fsm_t *);
00055 void ec_fsm_master_write_eeprom(ec_fsm_t *);
00056 
00057 void ec_fsm_slavescan_start(ec_fsm_t *);
00058 void ec_fsm_slavescan_address(ec_fsm_t *);
00059 void ec_fsm_slavescan_state(ec_fsm_t *);
00060 void ec_fsm_slavescan_base(ec_fsm_t *);
00061 void ec_fsm_slavescan_datalink(ec_fsm_t *);
00062 void ec_fsm_slavescan_eeprom_size(ec_fsm_t *);
00063 void ec_fsm_slavescan_eeprom_data(ec_fsm_t *);
00064 void ec_fsm_slavescan_end(ec_fsm_t *);
00065 
00066 void ec_fsm_slaveconf_init(ec_fsm_t *);
00067 void ec_fsm_slaveconf_sync(ec_fsm_t *);
00068 void ec_fsm_slaveconf_preop(ec_fsm_t *);
00069 void ec_fsm_slaveconf_fmmu(ec_fsm_t *);
00070 void ec_fsm_slaveconf_saveop(ec_fsm_t *);
00071 void ec_fsm_slaveconf_op(ec_fsm_t *);
00072 void ec_fsm_slaveconf_end(ec_fsm_t *);
00073 
00074 void ec_fsm_sii_start_reading(ec_fsm_t *);
00075 void ec_fsm_sii_read_check(ec_fsm_t *);
00076 void ec_fsm_sii_read_fetch(ec_fsm_t *);
00077 void ec_fsm_sii_start_writing(ec_fsm_t *);
00078 void ec_fsm_sii_write_check(ec_fsm_t *);
00079 void ec_fsm_sii_write_check2(ec_fsm_t *);
00080 void ec_fsm_sii_end(ec_fsm_t *);
00081 void ec_fsm_sii_error(ec_fsm_t *);
00082 
00083 void ec_fsm_change_start(ec_fsm_t *);
00084 void ec_fsm_change_check(ec_fsm_t *);
00085 void ec_fsm_change_status(ec_fsm_t *);
00086 void ec_fsm_change_code(ec_fsm_t *);
00087 void ec_fsm_change_ack(ec_fsm_t *);
00088 void ec_fsm_change_check_ack(ec_fsm_t *);
00089 void ec_fsm_change_end(ec_fsm_t *);
00090 void ec_fsm_change_error(ec_fsm_t *);
00091 
00092 /*****************************************************************************/
00093 
00098 int ec_fsm_init(ec_fsm_t *fsm, 
00099                 ec_master_t *master 
00100     )
00101 {
00102     fsm->master = master;
00103     fsm->master_state = ec_fsm_master_start;
00104     fsm->master_slaves_responding = 0;
00105     fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
00106     fsm->master_validation = 0;
00107 
00108     ec_datagram_init(&fsm->datagram);
00109     if (ec_datagram_prealloc(&fsm->datagram, EC_MAX_DATA_SIZE)) {
00110         EC_ERR("Failed to allocate FSM datagram.\n");
00111         return -1;
00112     }
00113 
00114     return 0;
00115 }
00116 
00117 /*****************************************************************************/
00118 
00123 void ec_fsm_clear(ec_fsm_t *fsm )
00124 {
00125     ec_datagram_clear(&fsm->datagram);
00126 }
00127 
00128 /*****************************************************************************/
00129 
00134 void ec_fsm_reset(ec_fsm_t *fsm )
00135 {
00136     fsm->master_state = ec_fsm_master_start;
00137     fsm->master_slaves_responding = 0;
00138     fsm->master_slave_states = EC_SLAVE_STATE_UNKNOWN;
00139 }
00140 
00141 /*****************************************************************************/
00142 
00147 void ec_fsm_execute(ec_fsm_t *fsm )
00148 {
00149     fsm->master_state(fsm);
00150 }
00151 
00152 /******************************************************************************
00153  *  master state machine
00154  *****************************************************************************/
00155 
00161 void ec_fsm_master_start(ec_fsm_t *fsm)
00162 {
00163     ec_datagram_brd(&fsm->datagram, 0x0130, 2);
00164     ec_master_queue_datagram(fsm->master, &fsm->datagram);
00165     fsm->master_state = ec_fsm_master_broadcast;
00166 }
00167 
00168 /*****************************************************************************/
00169 
00175 void ec_fsm_master_broadcast(ec_fsm_t *fsm )
00176 {
00177     ec_datagram_t *datagram = &fsm->datagram;
00178     unsigned int topology_change, states_change, i;
00179     ec_slave_t *slave;
00180     ec_master_t *master = fsm->master;
00181 
00182     if (datagram->state != EC_CMD_RECEIVED) {
00183         if (!master->device->link_state) {
00184             fsm->master_slaves_responding = 0;
00185             list_for_each_entry(slave, &master->slaves, list) {
00186                 slave->online = 0;
00187             }
00188         }
00189         fsm->master_state = ec_fsm_master_start;
00190         fsm->master_state(fsm); // execute immediately
00191         return;
00192     }
00193 
00194     topology_change = (datagram->working_counter !=
00195                        fsm->master_slaves_responding);
00196     states_change = (EC_READ_U8(datagram->data) != fsm->master_slave_states);
00197 
00198     fsm->master_slave_states = EC_READ_U8(datagram->data);
00199     fsm->master_slaves_responding = datagram->working_counter;
00200 
00201     if (topology_change) {
00202         EC_INFO("%i slave%s responding.\n",
00203                 fsm->master_slaves_responding,
00204                 fsm->master_slaves_responding == 1 ? "" : "s");
00205 
00206         if (master->mode == EC_MASTER_MODE_RUNNING) {
00207             if (fsm->master_slaves_responding == master->slave_count) {
00208                 fsm->master_validation = 1; // start validation later
00209             }
00210             else {
00211                 EC_WARN("Invalid slave count. Bus in tainted state.\n");
00212             }
00213         }
00214     }
00215 
00216     if (states_change) {
00217         EC_INFO("Slave states: ");
00218         ec_print_states(fsm->master_slave_states);
00219         printk(".\n");
00220     }
00221 
00222     // topology change in idle mode: clear all slaves and scan the bus
00223     if (topology_change && master->mode == EC_MASTER_MODE_IDLE) {
00224         EC_INFO("Scanning bus.\n");
00225 
00226         ec_master_eoe_stop(master);
00227         ec_master_clear_slaves(master);
00228 
00229         if (!fsm->master_slaves_responding) {
00230             // no slaves present -> finish state machine.
00231             fsm->master_state = ec_fsm_master_start;
00232             fsm->master_state(fsm); // execute immediately
00233             return;
00234         }
00235 
00236         // init slaves
00237         for (i = 0; i < fsm->master_slaves_responding; i++) {
00238             if (!(slave = (ec_slave_t *) kmalloc(sizeof(ec_slave_t),
00239                                                  GFP_ATOMIC))) {
00240                 EC_ERR("Failed to allocate slave %i!\n", i);
00241                 fsm->master_state = ec_fsm_master_start;
00242                 fsm->master_state(fsm); // execute immediately
00243                 return;
00244             }
00245 
00246             if (ec_slave_init(slave, master, i, i + 1)) {
00247                 fsm->master_state = ec_fsm_master_start;
00248                 fsm->master_state(fsm); // execute immediately
00249                 return;
00250             }
00251 
00252             if (kobject_add(&slave->kobj)) {
00253                 EC_ERR("Failed to add kobject.\n");
00254                 kobject_put(&slave->kobj); // free
00255                 fsm->master_state = ec_fsm_master_start;
00256                 fsm->master_state(fsm); // execute immediately
00257                 return;
00258             }
00259 
00260             list_add_tail(&slave->list, &master->slaves);
00261         }
00262 
00263         // begin scanning of slaves
00264         fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
00265         fsm->slave_state = ec_fsm_slavescan_start;
00266         fsm->master_state = ec_fsm_master_scan_slaves;
00267         fsm->master_state(fsm); // execute immediately
00268         return;
00269     }
00270 
00271     // fetch state from each slave
00272     fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
00273     ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address, 0x0130, 2);
00274     ec_master_queue_datagram(master, &fsm->datagram);
00275     fsm->master_state = ec_fsm_master_read_states;
00276 }
00277 
00278 /*****************************************************************************/
00279 
00285 void ec_fsm_master_action_process_states(ec_fsm_t *fsm
00287                                          )
00288 {
00289     ec_master_t *master = fsm->master;
00290     ec_slave_t *slave;
00291 
00292     // check if any slaves are not in the state, they're supposed to be
00293     list_for_each_entry(slave, &master->slaves, list) {
00294         if (slave->error_flag ||
00295             !slave->online ||
00296             slave->requested_state == EC_SLAVE_STATE_UNKNOWN ||
00297             slave->current_state == slave->requested_state) continue;
00298 
00299         EC_INFO("Changing state of slave %i from ", slave->ring_position);
00300         ec_print_states(slave->current_state);
00301         printk(" to ");
00302         ec_print_states(slave->requested_state);
00303         printk(".\n");
00304 
00305         fsm->slave = slave;
00306         fsm->slave_state = ec_fsm_slaveconf_init;
00307         fsm->change_new = EC_SLAVE_STATE_INIT;
00308         fsm->change_state = ec_fsm_change_start;
00309         fsm->master_state = ec_fsm_master_configure_slave;
00310         fsm->master_state(fsm); // execute immediately
00311         return;
00312     }
00313 
00314     if (master->mode == EC_MASTER_MODE_IDLE) {
00315         // nothing to configure. check for pending EEPROM write operations.
00316         list_for_each_entry(slave, &master->slaves, list) {
00317             if (!slave->new_eeprom_data) continue;
00318 
00319             if (!slave->online || slave->error_flag) {
00320                 kfree(slave->new_eeprom_data);
00321                 slave->new_eeprom_data = NULL;
00322                 EC_ERR("Discarding EEPROM data, slave %i not ready.\n",
00323                        slave->ring_position);
00324                 continue;
00325             }
00326 
00327             // found pending EEPROM write operation. execute it!
00328             EC_INFO("Writing EEPROM of slave %i...\n", slave->ring_position);
00329             fsm->sii_offset = 0x0000;
00330             memcpy(fsm->sii_value, slave->new_eeprom_data, 2);
00331             fsm->sii_mode = 1;
00332             fsm->sii_state = ec_fsm_sii_start_writing;
00333             fsm->slave = slave;
00334             fsm->master_state = ec_fsm_master_write_eeprom;
00335             fsm->master_state(fsm); // execute immediately
00336             return;
00337         }
00338     }
00339 
00340     // nothing to do. restart master state machine.
00341     fsm->master_state = ec_fsm_master_start;
00342     fsm->master_state(fsm); // execute immediately
00343 }
00344 
00345 /*****************************************************************************/
00346 
00351 void ec_fsm_master_action_next_slave_state(ec_fsm_t *fsm)
00353 {
00354     ec_master_t *master = fsm->master;
00355     ec_slave_t *slave = fsm->slave;
00356 
00357     // is there another slave to query?
00358     if (slave->list.next != &master->slaves) {
00359         // process next slave
00360         fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
00361         ec_datagram_nprd(&fsm->datagram, fsm->slave->station_address,
00362                          0x0130, 2);
00363         ec_master_queue_datagram(master, &fsm->datagram);
00364         fsm->master_state = ec_fsm_master_read_states;
00365         return;
00366     }
00367 
00368     // all slave states read
00369 
00370     // check, if a bus validation has to be done
00371     if (fsm->master_validation) {
00372         fsm->master_validation = 0;
00373         list_for_each_entry(slave, &master->slaves, list) {
00374             if (slave->online) continue;
00375 
00376             // At least one slave is offline. validate!
00377             EC_INFO("Validating bus.\n");
00378             fsm->slave = list_entry(master->slaves.next, ec_slave_t, list);
00379             fsm->master_state = ec_fsm_master_validate_vendor;
00380             fsm->sii_offset = 0x0008; // vendor ID
00381             fsm->sii_mode = 0;
00382             fsm->sii_state = ec_fsm_sii_start_reading;
00383             fsm->sii_state(fsm); // execute immediately
00384             return;
00385         }
00386     }
00387 
00388     ec_fsm_master_action_process_states(fsm);
00389 }
00390 
00391 /*****************************************************************************/
00392 
00398 void ec_fsm_master_read_states(ec_fsm_t *fsm )
00399 {
00400     ec_slave_t *slave = fsm->slave;
00401     ec_datagram_t *datagram = &fsm->datagram;
00402     uint8_t new_state;
00403 
00404     if (datagram->state != EC_CMD_RECEIVED) {
00405         fsm->master_state = ec_fsm_master_start;
00406         fsm->master_state(fsm); // execute immediately
00407         return;
00408     }
00409 
00410     // did the slave not respond to its station address?
00411     if (datagram->working_counter != 1) {
00412         if (slave->online) {
00413             slave->online = 0;
00414             EC_INFO("Slave %i: offline.\n", slave->ring_position);
00415         }
00416         ec_fsm_master_action_next_slave_state(fsm);
00417         return;
00418     }
00419 
00420     // slave responded
00421     new_state = EC_READ_U8(datagram->data);
00422     if (!slave->online) { // slave was offline before
00423         slave->online = 1;
00424         slave->error_flag = 0; // clear error flag
00425         slave->current_state = new_state;
00426         EC_INFO("Slave %i: online (", slave->ring_position);
00427         ec_print_states(new_state);
00428         printk(").\n");
00429     }
00430     else if (new_state != slave->current_state) {
00431         EC_INFO("Slave %i: ", slave->ring_position);
00432         ec_print_states(slave->current_state);
00433         printk(" -> ");
00434         ec_print_states(new_state);
00435         printk(".\n");
00436         slave->current_state = new_state;
00437     }
00438 
00439     ec_fsm_master_action_next_slave_state(fsm);
00440 }
00441 
00442 /*****************************************************************************/
00443 
00449 void ec_fsm_master_validate_vendor(ec_fsm_t *fsm )
00450 {
00451     ec_slave_t *slave = fsm->slave;
00452 
00453     fsm->sii_state(fsm); // execute SII state machine
00454 
00455     if (fsm->sii_state == ec_fsm_sii_error) {
00456         fsm->slave->error_flag = 1;
00457         EC_ERR("Failed to validate vendor ID of slave %i.\n",
00458                slave->ring_position);
00459         fsm->master_state = ec_fsm_master_start;
00460         fsm->master_state(fsm); // execute immediately
00461         return;
00462     }
00463 
00464     if (fsm->sii_state != ec_fsm_sii_end) return;
00465 
00466     if (EC_READ_U32(fsm->sii_value) != slave->sii_vendor_id) {
00467         EC_ERR("Slave %i: invalid vendor ID!\n", slave->ring_position);
00468         fsm->master_state = ec_fsm_master_start;
00469         fsm->master_state(fsm); // execute immediately
00470         return;
00471     }
00472 
00473     // vendor ID is ok. check product code.
00474     fsm->master_state = ec_fsm_master_validate_product;
00475     fsm->sii_offset = 0x000A; // product code
00476     fsm->sii_mode = 0;
00477     fsm->sii_state = ec_fsm_sii_start_reading;
00478     fsm->sii_state(fsm); // execute immediately
00479 }
00480 
00481 /*****************************************************************************/
00482 
00489 void ec_fsm_master_action_addresses(ec_fsm_t *fsm )
00490 {
00491     ec_datagram_t *datagram = &fsm->datagram;
00492 
00493     while (fsm->slave->online) {
00494         if (fsm->slave->list.next == &fsm->master->slaves) { // last slave?
00495             fsm->master_state = ec_fsm_master_start;
00496             fsm->master_state(fsm); // execute immediately
00497             return;
00498         }
00499         // check next slave
00500         fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
00501     }
00502 
00503     EC_INFO("Reinitializing slave %i.\n", fsm->slave->ring_position);
00504 
00505     // write station address
00506     ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
00507     EC_WRITE_U16(datagram->data, fsm->slave->station_address);
00508     ec_master_queue_datagram(fsm->master, datagram);
00509     fsm->master_state = ec_fsm_master_rewrite_addresses;
00510 }
00511 
00512 /*****************************************************************************/
00513 
00519 void ec_fsm_master_validate_product(ec_fsm_t *fsm )
00520 {
00521     ec_slave_t *slave = fsm->slave;
00522 
00523     fsm->sii_state(fsm); // execute SII state machine
00524 
00525     if (fsm->sii_state == ec_fsm_sii_error) {
00526         fsm->slave->error_flag = 1;
00527         EC_ERR("Failed to validate product code of slave %i.\n",
00528                slave->ring_position);
00529         fsm->master_state = ec_fsm_master_start;
00530         fsm->master_state(fsm); // execute immediately
00531         return;
00532     }
00533 
00534     if (fsm->sii_state != ec_fsm_sii_end) return;
00535 
00536     if (EC_READ_U32(fsm->sii_value) != slave->sii_product_code) {
00537         EC_ERR("Slave %i: invalid product code!\n", slave->ring_position);
00538         EC_ERR("expected 0x%08X, got 0x%08X.\n", slave->sii_product_code,
00539                EC_READ_U32(fsm->sii_value));
00540         fsm->master_state = ec_fsm_master_start;
00541         fsm->master_state(fsm); // execute immediately
00542         return;
00543     }
00544 
00545     // have all states been validated?
00546     if (slave->list.next == &fsm->master->slaves) {
00547         fsm->slave = list_entry(fsm->master->slaves.next, ec_slave_t, list);
00548         // start writing addresses to offline slaves
00549         ec_fsm_master_action_addresses(fsm);
00550         return;
00551     }
00552 
00553     // validate next slave
00554     fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
00555     fsm->master_state = ec_fsm_master_validate_vendor;
00556     fsm->sii_offset = 0x0008; // vendor ID
00557     fsm->sii_mode = 0;
00558     fsm->sii_state = ec_fsm_sii_start_reading;
00559     fsm->sii_state(fsm); // execute immediately
00560 }
00561 
00562 /*****************************************************************************/
00563 
00569 void ec_fsm_master_rewrite_addresses(ec_fsm_t *fsm
00571                                      )
00572 {
00573     ec_slave_t *slave = fsm->slave;
00574     ec_datagram_t *datagram = &fsm->datagram;
00575 
00576     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
00577         EC_ERR("Failed to write station address on slave %i.\n",
00578                slave->ring_position);
00579     }
00580 
00581     if (fsm->slave->list.next == &fsm->master->slaves) { // last slave?
00582         fsm->master_state = ec_fsm_master_start;
00583         fsm->master_state(fsm); // execute immediately
00584         return;
00585     }
00586 
00587     // check next slave
00588     fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
00589     // Write new station address to slave
00590     ec_fsm_master_action_addresses(fsm);
00591 }
00592 
00593 /*****************************************************************************/
00594 
00600 void ec_fsm_master_scan_slaves(ec_fsm_t *fsm )
00601 {
00602     ec_master_t *master = fsm->master;
00603     ec_slave_t *slave = fsm->slave;
00604     uint16_t coupler_index, coupler_subindex;
00605     uint16_t reverse_coupler_index, current_coupler_index;
00606     ec_slave_ident_t *ident;
00607 
00608     fsm->slave_state(fsm); // execute slave state machine
00609 
00610     if (fsm->slave_state != ec_fsm_slavescan_end) return;
00611 
00612     // have all slaves been fetched?
00613     if (slave->list.next == &master->slaves) {
00614         EC_INFO("Bus scanning completed.\n");
00615 
00616         // identify all slaves and calculate coupler addressing
00617 
00618         coupler_index = 0;
00619         reverse_coupler_index = 0xFFFF;
00620         current_coupler_index = 0x3FFF;
00621         coupler_subindex = 0;
00622 
00623         list_for_each_entry(slave, &master->slaves, list)
00624         {
00625             // search for identification in "database"
00626             ident = slave_idents;
00627             while (ident->type) {
00628                 if (ident->vendor_id == slave->sii_vendor_id
00629                     && ident->product_code == slave->sii_product_code) {
00630                     slave->type = ident->type;
00631                     break;
00632                 }
00633                 ident++;
00634             }
00635 
00636             if (!slave->type) {
00637                 EC_WARN("Unknown slave device (vendor 0x%08X,"
00638                         " code 0x%08X) at position %i.\n",
00639                         slave->sii_vendor_id, slave->sii_product_code,
00640                         slave->ring_position);
00641             }
00642             else {
00643                 // if the slave is a bus coupler, change adressing base
00644                 if (slave->type->special == EC_TYPE_BUS_COUPLER) {
00645                     if (slave->sii_alias)
00646                         current_coupler_index = reverse_coupler_index--;
00647                     else
00648                         current_coupler_index = coupler_index++;
00649                     coupler_subindex = 0;
00650                 }
00651             }
00652 
00653             // determine initial state.
00654             if ((slave->type &&
00655                  (slave->type->special == EC_TYPE_BUS_COUPLER ||
00656                   slave->type->special == EC_TYPE_INFRA))) {
00657                 slave->requested_state = EC_SLAVE_STATE_OP;
00658             }
00659             else {
00660                 if (master->mode == EC_MASTER_MODE_RUNNING)
00661                     slave->requested_state = EC_SLAVE_STATE_PREOP;
00662                 else
00663                     slave->requested_state = EC_SLAVE_STATE_INIT;
00664             }
00665             slave->error_flag = 0;
00666 
00667             // calculate coupler-based slave address
00668             slave->coupler_index = current_coupler_index;
00669             slave->coupler_subindex = coupler_subindex;
00670             coupler_subindex++;
00671         }
00672 
00673         if (master->mode == EC_MASTER_MODE_IDLE) {
00674             // start EoE processing
00675             ec_master_eoe_start(master);
00676         }
00677 
00678         fsm->master_state = ec_fsm_master_start;
00679         fsm->master_state(fsm); // execute immediately
00680         return;
00681     }
00682 
00683     // process next slave
00684     fsm->slave = list_entry(fsm->slave->list.next, ec_slave_t, list);
00685     fsm->slave_state = ec_fsm_slavescan_start;
00686     fsm->slave_state(fsm); // execute immediately
00687 }
00688 
00689 /*****************************************************************************/
00690 
00696 void ec_fsm_master_configure_slave(ec_fsm_t *fsm
00698                                    )
00699 {
00700     fsm->slave_state(fsm); // execute slave's state machine
00701     if (fsm->slave_state != ec_fsm_slaveconf_end) return;
00702 
00703     ec_fsm_master_action_process_states(fsm);
00704 }
00705 
00706 /*****************************************************************************/
00707 
00712 void ec_fsm_master_write_eeprom(ec_fsm_t *fsm )
00713 {
00714     ec_slave_t *slave = fsm->slave;
00715 
00716     fsm->sii_state(fsm); // execute SII state machine
00717 
00718     if (fsm->sii_state == ec_fsm_sii_error) {
00719         fsm->slave->error_flag = 1;
00720         EC_ERR("Failed to write EEPROM contents to slave %i.\n",
00721                slave->ring_position);
00722         kfree(slave->new_eeprom_data);
00723         slave->new_eeprom_data = NULL;
00724         fsm->master_state = ec_fsm_master_start;
00725         fsm->master_state(fsm); // execute immediately
00726         return;
00727     }
00728 
00729     if (fsm->sii_state != ec_fsm_sii_end) return;
00730 
00731     fsm->sii_offset++;
00732     if (fsm->sii_offset < slave->new_eeprom_size) {
00733         memcpy(fsm->sii_value, slave->new_eeprom_data + fsm->sii_offset, 2);
00734         fsm->sii_state = ec_fsm_sii_start_writing;
00735         fsm->sii_state(fsm); // execute immediately
00736         return;
00737     }
00738 
00739     // finished writing EEPROM
00740     EC_INFO("Finished writing EEPROM of slave %i.\n", slave->ring_position);
00741     kfree(slave->new_eeprom_data);
00742     slave->new_eeprom_data = NULL;
00743 
00744     // restart master state machine.
00745     fsm->master_state = ec_fsm_master_start; // TODO: Evaluate new contents!
00746     fsm->master_state(fsm); // execute immediately
00747     return;
00748 }
00749 
00750 /******************************************************************************
00751  *  slave scan sub state machine
00752  *****************************************************************************/
00753 
00760 void ec_fsm_slavescan_start(ec_fsm_t *fsm )
00761 {
00762     ec_datagram_t *datagram = &fsm->datagram;
00763 
00764     // write station address
00765     ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x0010, 2);
00766     EC_WRITE_U16(datagram->data, fsm->slave->station_address);
00767     ec_master_queue_datagram(fsm->master, datagram);
00768     fsm->slave_state = ec_fsm_slavescan_address;
00769 }
00770 
00771 /*****************************************************************************/
00772 
00777 void ec_fsm_slavescan_address(ec_fsm_t *fsm )
00778 {
00779     ec_datagram_t *datagram = &fsm->datagram;
00780 
00781     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
00782         fsm->slave->error_flag = 1;
00783         fsm->slave_state = ec_fsm_slavescan_end;
00784         EC_ERR("Failed to write station address of slave %i.\n",
00785                fsm->slave->ring_position);
00786         return;
00787     }
00788 
00789     // Read AL state
00790     ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0130, 2);
00791     ec_master_queue_datagram(fsm->master, datagram);
00792     fsm->slave_state = ec_fsm_slavescan_state;
00793 }
00794 
00795 /*****************************************************************************/
00796 
00801 void ec_fsm_slavescan_state(ec_fsm_t *fsm )
00802 {
00803     ec_datagram_t *datagram = &fsm->datagram;
00804     ec_slave_t *slave = fsm->slave;
00805 
00806     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
00807         fsm->slave->error_flag = 1;
00808         fsm->slave_state = ec_fsm_slavescan_end;
00809         EC_ERR("Failed to read AL state of slave %i.\n",
00810                fsm->slave->ring_position);
00811         return;
00812     }
00813 
00814     slave->current_state = EC_READ_U8(datagram->data);
00815     if (slave->current_state & EC_ACK) {
00816         EC_WARN("Slave %i has state error bit set (0x%02X)!\n",
00817                 slave->ring_position, slave->current_state);
00818         slave->current_state &= 0x0F;
00819     }
00820 
00821     // read base data
00822     ec_datagram_nprd(datagram, fsm->slave->station_address, 0x0000, 6);
00823     ec_master_queue_datagram(fsm->master, datagram);
00824     fsm->slave_state = ec_fsm_slavescan_base;
00825 }
00826 
00827 /*****************************************************************************/
00828 
00833 void ec_fsm_slavescan_base(ec_fsm_t *fsm )
00834 {
00835     ec_datagram_t *datagram = &fsm->datagram;
00836     ec_slave_t *slave = fsm->slave;
00837 
00838     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
00839         fsm->slave->error_flag = 1;
00840         fsm->slave_state = ec_fsm_slavescan_end;
00841         EC_ERR("Failed to read base data of slave %i.\n",
00842                slave->ring_position);
00843         return;
00844     }
00845 
00846     slave->base_type       = EC_READ_U8 (datagram->data);
00847     slave->base_revision   = EC_READ_U8 (datagram->data + 1);
00848     slave->base_build      = EC_READ_U16(datagram->data + 2);
00849     slave->base_fmmu_count = EC_READ_U8 (datagram->data + 4);
00850     slave->base_sync_count = EC_READ_U8 (datagram->data + 5);
00851 
00852     if (slave->base_fmmu_count > EC_MAX_FMMUS)
00853         slave->base_fmmu_count = EC_MAX_FMMUS;
00854 
00855     // read data link status
00856     ec_datagram_nprd(datagram, slave->station_address, 0x0110, 2);
00857     ec_master_queue_datagram(slave->master, datagram);
00858     fsm->slave_state = ec_fsm_slavescan_datalink;
00859 }
00860 
00861 /*****************************************************************************/
00862 
00867 void ec_fsm_slavescan_datalink(ec_fsm_t *fsm )
00868 {
00869     ec_datagram_t *datagram = &fsm->datagram;
00870     ec_slave_t *slave = fsm->slave;
00871     uint16_t dl_status;
00872     unsigned int i;
00873 
00874     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
00875         fsm->slave->error_flag = 1;
00876         fsm->slave_state = ec_fsm_slavescan_end;
00877         EC_ERR("Failed to read DL status of slave %i.\n",
00878                slave->ring_position);
00879         return;
00880     }
00881 
00882     dl_status = EC_READ_U16(datagram->data);
00883     for (i = 0; i < 4; i++) {
00884         slave->dl_link[i] = dl_status & (1 << (4 + i)) ? 1 : 0;
00885         slave->dl_loop[i] = dl_status & (1 << (8 + i * 2)) ? 1 : 0;
00886         slave->dl_signal[i] = dl_status & (1 << (9 + i * 2)) ? 1 : 0;
00887     }
00888 
00889     // Start fetching EEPROM size
00890 
00891     fsm->sii_offset = 0x0040; // first category header
00892     fsm->sii_mode = 1;
00893     fsm->sii_state = ec_fsm_sii_start_reading;
00894     fsm->slave_state = ec_fsm_slavescan_eeprom_size;
00895     fsm->slave_state(fsm); // execute state immediately
00896 }
00897 
00898 /*****************************************************************************/
00899 
00904 void ec_fsm_slavescan_eeprom_size(ec_fsm_t *fsm )
00905 {
00906     ec_slave_t *slave = fsm->slave;
00907     uint16_t cat_type, cat_size;
00908 
00909     // execute SII state machine
00910     fsm->sii_state(fsm);
00911 
00912     if (fsm->sii_state == ec_fsm_sii_error) {
00913         fsm->slave->error_flag = 1;
00914         fsm->slave_state = ec_fsm_slavescan_end;
00915         EC_ERR("Failed to read EEPROM size of slave %i.\n",
00916                slave->ring_position);
00917         return;
00918     }
00919 
00920     if (fsm->sii_state != ec_fsm_sii_end) return;
00921 
00922     cat_type = EC_READ_U16(fsm->sii_value);
00923     cat_size = EC_READ_U16(fsm->sii_value + 2);
00924 
00925     if (cat_type != 0xFFFF) { // not the last category
00926         fsm->sii_offset += cat_size + 2;
00927         fsm->sii_state = ec_fsm_sii_start_reading;
00928         fsm->sii_state(fsm); // execute state immediately
00929         return;
00930     }
00931 
00932     slave->eeprom_size = (fsm->sii_offset + 1) * 2;
00933 
00934     if (slave->eeprom_data) {
00935         EC_INFO("Freeing old EEPROM data on slave %i...\n",
00936                 slave->ring_position);
00937         kfree(slave->eeprom_data);
00938     }
00939 
00940     if (!(slave->eeprom_data =
00941           (uint8_t *) kmalloc(slave->eeprom_size, GFP_ATOMIC))) {
00942         fsm->slave->error_flag = 1;
00943         fsm->slave_state = ec_fsm_slavescan_end;
00944         EC_ERR("Failed to allocate EEPROM data on slave %i.\n",
00945                slave->ring_position);
00946         return;
00947     }
00948 
00949     // Start fetching EEPROM contents
00950 
00951     fsm->sii_offset = 0x0000;
00952     fsm->sii_mode = 1;
00953     fsm->sii_state = ec_fsm_sii_start_reading;
00954     fsm->slave_state = ec_fsm_slavescan_eeprom_data;
00955     fsm->slave_state(fsm); // execute state immediately
00956 }
00957 
00958 /*****************************************************************************/
00959 
00964 void ec_fsm_slavescan_eeprom_data(ec_fsm_t *fsm )
00965 {
00966     ec_slave_t *slave = fsm->slave;
00967     uint16_t *cat_word, cat_type, cat_size;
00968 
00969     // execute SII state machine
00970     fsm->sii_state(fsm);
00971 
00972     if (fsm->sii_state == ec_fsm_sii_error) {
00973         fsm->slave->error_flag = 1;
00974         fsm->slave_state = ec_fsm_slavescan_end;
00975         EC_ERR("Failed to fetch EEPROM contents of slave %i.\n",
00976                slave->ring_position);
00977         return;
00978     }
00979 
00980     if (fsm->sii_state != ec_fsm_sii_end) return;
00981 
00982     // 2 words fetched
00983 
00984     if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit
00985         memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 4);
00986     }
00987     else { // copy the last word
00988         memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->sii_value, 2);
00989     }
00990 
00991     if (fsm->sii_offset + 2 < slave->eeprom_size / 2) {
00992         // fetch the next 2 words
00993         fsm->sii_offset += 2;
00994         fsm->sii_state = ec_fsm_sii_start_reading;
00995         fsm->sii_state(fsm); // execute state immediately
00996         return;
00997     }
00998 
00999     // Evaluate EEPROM contents
01000 
01001     slave->sii_alias =
01002         EC_READ_U16(slave->eeprom_data + 2 * 0x0004);
01003     slave->sii_vendor_id =
01004         EC_READ_U32(slave->eeprom_data + 2 * 0x0008);
01005     slave->sii_product_code =
01006         EC_READ_U32(slave->eeprom_data + 2 * 0x000A);
01007     slave->sii_revision_number =
01008         EC_READ_U32(slave->eeprom_data + 2 * 0x000C);
01009     slave->sii_serial_number =
01010         EC_READ_U32(slave->eeprom_data + 2 * 0x000E);
01011     slave->sii_rx_mailbox_offset =
01012         EC_READ_U16(slave->eeprom_data + 2 * 0x0018);
01013     slave->sii_rx_mailbox_size =
01014         EC_READ_U16(slave->eeprom_data + 2 * 0x0019);
01015     slave->sii_tx_mailbox_offset =
01016         EC_READ_U16(slave->eeprom_data + 2 * 0x001A);
01017     slave->sii_tx_mailbox_size =
01018         EC_READ_U16(slave->eeprom_data + 2 * 0x001B);
01019     slave->sii_mailbox_protocols =
01020         EC_READ_U16(slave->eeprom_data + 2 * 0x001C);
01021 
01022     // evaluate category data
01023     cat_word = (uint16_t *) slave->eeprom_data + 0x0040;
01024     while (EC_READ_U16(cat_word) != 0xFFFF) {
01025         cat_type = EC_READ_U16(cat_word) & 0x7FFF;
01026         cat_size = EC_READ_U16(cat_word + 1);
01027 
01028         switch (cat_type) {
01029             case 0x000A:
01030                 if (ec_slave_fetch_strings(slave, (uint8_t *) (cat_word + 2)))
01031                     goto end;
01032                 break;
01033             case 0x001E:
01034                 if (ec_slave_fetch_general(slave, (uint8_t *) (cat_word + 2)))
01035                     goto end;
01036                 break;
01037             case 0x0028:
01038                 break;
01039             case 0x0029:
01040                 if (ec_slave_fetch_sync(slave, (uint8_t *) (cat_word + 2),
01041                                         cat_size))
01042                     goto end;
01043                 break;
01044             case 0x0032:
01045                 if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
01046                                        cat_size, EC_TX_PDO))
01047                     goto end;
01048                 break;
01049             case 0x0033:
01050                 if (ec_slave_fetch_pdo(slave, (uint8_t *) (cat_word + 2),
01051                                        cat_size, EC_RX_PDO))
01052                     goto end;
01053                 break;
01054             default:
01055                 EC_WARN("Unknown category type 0x%04X in slave %i.\n",
01056                         cat_type, slave->ring_position);
01057         }
01058 
01059         cat_word += cat_size + 2;
01060     }
01061 
01062     fsm->slave_state = ec_fsm_slavescan_end;
01063 
01064 end:
01065     fsm->slave->error_flag = 1;
01066     fsm->slave_state = ec_fsm_slavescan_end;
01067 }
01068 
01069 /*****************************************************************************/
01070 
01076 void ec_fsm_slavescan_end(ec_fsm_t *fsm )
01077 {
01078 }
01079 
01080 /******************************************************************************
01081  *  slave configuration sub state machine
01082  *****************************************************************************/
01083 
01088 void ec_fsm_slaveconf_init(ec_fsm_t *fsm )
01089 {
01090     ec_slave_t *slave = fsm->slave;
01091     ec_datagram_t *datagram = &fsm->datagram;
01092     const ec_sync_t *sync;
01093     ec_eeprom_sync_t *eeprom_sync, mbox_sync;
01094     unsigned int j;
01095 
01096     fsm->change_state(fsm); // execute state change state machine
01097 
01098     if (fsm->change_state == ec_fsm_change_error) {
01099         slave->error_flag = 1;
01100         fsm->slave_state = ec_fsm_slaveconf_end;
01101         return;
01102     }
01103 
01104     if (fsm->change_state != ec_fsm_change_end) return;
01105 
01106     // slave is now in INIT
01107     if (slave->current_state == slave->requested_state) {
01108         fsm->slave_state = ec_fsm_slaveconf_end; // successful
01109         return;
01110     }
01111 
01112     // check for slave registration
01113     if (!slave->type) {
01114         EC_WARN("Slave %i has unknown type!\n", slave->ring_position);
01115     }
01116 
01117     // check and reset CRC fault counters
01118     //ec_slave_check_crc(slave);
01119     // TODO!
01120 
01121     if (!slave->base_sync_count) { // no sync managers
01122         fsm->slave_state = ec_fsm_slaveconf_preop;
01123         fsm->change_new = EC_SLAVE_STATE_PREOP;
01124         fsm->change_state = ec_fsm_change_start;
01125         fsm->change_state(fsm); // execute immediately
01126         return;
01127     }
01128 
01129     // configure sync managers
01130     ec_datagram_npwr(datagram, slave->station_address, 0x0800,
01131                      EC_SYNC_SIZE * slave->base_sync_count);
01132     memset(datagram->data, 0x00, EC_SYNC_SIZE * slave->base_sync_count);
01133 
01134     // does the slave supply sync manager configurations in its EEPROM?
01135     if (!list_empty(&slave->eeprom_syncs)) {
01136         list_for_each_entry(eeprom_sync, &slave->eeprom_syncs, list) {
01137             if (eeprom_sync->index >= slave->base_sync_count) {
01138                 fsm->slave->error_flag = 1;
01139                 fsm->slave_state = ec_fsm_slaveconf_end;
01140                 EC_ERR("Invalid sync manager configuration found!");
01141                 return;
01142             }
01143             ec_eeprom_sync_config(eeprom_sync, slave,
01144                                   datagram->data + EC_SYNC_SIZE
01145                                   * eeprom_sync->index);
01146         }
01147     }
01148 
01149     // known slave type, take type's SM information
01150     else if (slave->type) {
01151         for (j = 0; slave->type->sync_managers[j] && j < EC_MAX_SYNC; j++) {
01152             sync = slave->type->sync_managers[j];
01153             ec_sync_config(sync, slave, datagram->data + EC_SYNC_SIZE * j);
01154         }
01155     }
01156 
01157     // unknown type, but slave has mailbox
01158     else if (slave->sii_mailbox_protocols)
01159     {
01160         // guess mailbox settings
01161         mbox_sync.physical_start_address =
01162             slave->sii_rx_mailbox_offset;
01163         mbox_sync.length = slave->sii_rx_mailbox_size;
01164         mbox_sync.control_register = 0x26;
01165         mbox_sync.enable = 1;
01166         ec_eeprom_sync_config(&mbox_sync, slave, datagram->data);
01167 
01168         mbox_sync.physical_start_address =
01169             slave->sii_tx_mailbox_offset;
01170         mbox_sync.length = slave->sii_tx_mailbox_size;
01171         mbox_sync.control_register = 0x22;
01172         mbox_sync.enable = 1;
01173         ec_eeprom_sync_config(&mbox_sync, slave,
01174                               datagram->data + EC_SYNC_SIZE);
01175 
01176         EC_INFO("Mailbox configured for unknown slave %i\n",
01177                 slave->ring_position);
01178     }
01179 
01180     ec_master_queue_datagram(fsm->master, datagram);
01181     fsm->slave_state = ec_fsm_slaveconf_sync;
01182 }
01183 
01184 /*****************************************************************************/
01185 
01190 void ec_fsm_slaveconf_sync(ec_fsm_t *fsm )
01191 {
01192     ec_datagram_t *datagram = &fsm->datagram;
01193     ec_slave_t *slave = fsm->slave;
01194 
01195     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01196         slave->error_flag = 1;
01197         fsm->slave_state = ec_fsm_slaveconf_end;
01198         EC_ERR("Failed to set sync managers on slave %i.\n",
01199                slave->ring_position);
01200         return;
01201     }
01202 
01203     fsm->slave_state = ec_fsm_slaveconf_preop;
01204     fsm->change_new = EC_SLAVE_STATE_PREOP;
01205     fsm->change_state = ec_fsm_change_start;
01206     fsm->change_state(fsm); // execute immediately
01207 }
01208 
01209 /*****************************************************************************/
01210 
01215 void ec_fsm_slaveconf_preop(ec_fsm_t *fsm )
01216 {
01217     ec_slave_t *slave = fsm->slave;
01218     ec_master_t *master = fsm->master;
01219     ec_datagram_t *datagram = &fsm->datagram;
01220     unsigned int j;
01221 
01222     fsm->change_state(fsm); // execute state change state machine
01223 
01224     if (fsm->change_state == ec_fsm_change_error) {
01225         slave->error_flag = 1;
01226         fsm->slave_state = ec_fsm_slaveconf_end;
01227         return;
01228     }
01229 
01230     if (fsm->change_state != ec_fsm_change_end) return;
01231 
01232     // slave is now in PREOP
01233     if (slave->current_state == slave->requested_state) {
01234         fsm->slave_state = ec_fsm_slaveconf_end; // successful
01235         return;
01236     }
01237 
01238     // stop activation here for slaves without type
01239     if (!slave->type) {
01240         fsm->slave_state = ec_fsm_slaveconf_end; // successful
01241         return;
01242     }
01243 
01244     if (!slave->base_fmmu_count) {
01245         fsm->slave_state = ec_fsm_slaveconf_saveop;
01246         fsm->change_new = EC_SLAVE_STATE_SAVEOP;
01247         fsm->change_state = ec_fsm_change_start;
01248         fsm->change_state(fsm); // execute immediately
01249         return;
01250     }
01251 
01252     // configure FMMUs
01253     ec_datagram_npwr(datagram, slave->station_address,
01254                      0x0600, EC_FMMU_SIZE * slave->base_fmmu_count);
01255     memset(datagram->data, 0x00, EC_FMMU_SIZE * slave->base_fmmu_count);
01256     for (j = 0; j < slave->fmmu_count; j++) {
01257         ec_fmmu_config(&slave->fmmus[j], slave,
01258                        datagram->data + EC_FMMU_SIZE * j);
01259     }
01260 
01261     ec_master_queue_datagram(master, datagram);
01262     fsm->slave_state = ec_fsm_slaveconf_fmmu;
01263 }
01264 
01265 /*****************************************************************************/
01266 
01271 void ec_fsm_slaveconf_fmmu(ec_fsm_t *fsm )
01272 {
01273     ec_datagram_t *datagram = &fsm->datagram;
01274 
01275     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01276         fsm->slave->error_flag = 1;
01277         fsm->slave_state = ec_fsm_slaveconf_end;
01278         EC_ERR("Failed to set FMMUs on slave %i.\n",
01279                fsm->slave->ring_position);
01280         return;
01281     }
01282 
01283     // set state to SAVEOP
01284     fsm->slave_state = ec_fsm_slaveconf_saveop;
01285     fsm->change_new = EC_SLAVE_STATE_SAVEOP;
01286     fsm->change_state = ec_fsm_change_start;
01287     fsm->change_state(fsm); // execute immediately
01288 }
01289 
01290 /*****************************************************************************/
01291 
01296 void ec_fsm_slaveconf_saveop(ec_fsm_t *fsm )
01297 {
01298     fsm->change_state(fsm); // execute state change state machine
01299 
01300     if (fsm->change_state == ec_fsm_change_error) {
01301         fsm->slave->error_flag = 1;
01302         fsm->slave_state = ec_fsm_slaveconf_end;
01303         return;
01304     }
01305 
01306     if (fsm->change_state != ec_fsm_change_end) return;
01307 
01308     // slave is now in SAVEOP
01309     if (fsm->slave->current_state == fsm->slave->requested_state) {
01310         fsm->slave_state = ec_fsm_slaveconf_end; // successful
01311         return;
01312     }
01313 
01314     // set state to OP
01315     fsm->slave_state = ec_fsm_slaveconf_op;
01316     fsm->change_new = EC_SLAVE_STATE_OP;
01317     fsm->change_state = ec_fsm_change_start;
01318     fsm->change_state(fsm); // execute immediately
01319 }
01320 
01321 /*****************************************************************************/
01322 
01327 void ec_fsm_slaveconf_op(ec_fsm_t *fsm )
01328 {
01329     fsm->change_state(fsm); // execute state change state machine
01330 
01331     if (fsm->change_state == ec_fsm_change_error) {
01332         fsm->slave->error_flag = 1;
01333         fsm->slave_state = ec_fsm_slaveconf_end;
01334         return;
01335     }
01336 
01337     if (fsm->change_state != ec_fsm_change_end) return;
01338 
01339     // slave is now in OP
01340     fsm->slave_state = ec_fsm_slaveconf_end; // successful
01341 }
01342 
01343 /*****************************************************************************/
01344 
01350 void ec_fsm_slaveconf_end(ec_fsm_t *fsm )
01351 {
01352 }
01353 
01354 /******************************************************************************
01355  *  SII sub state machine
01356  *****************************************************************************/
01357 
01363 void ec_fsm_sii_start_reading(ec_fsm_t *fsm )
01364 {
01365     ec_datagram_t *datagram = &fsm->datagram;
01366 
01367     // initiate read operation
01368     if (fsm->sii_mode) {
01369         ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 4);
01370     }
01371     else {
01372         ec_datagram_apwr(datagram, fsm->slave->ring_position, 0x502, 4);
01373     }
01374 
01375     EC_WRITE_U8 (datagram->data,     0x00); // read-only access
01376     EC_WRITE_U8 (datagram->data + 1, 0x01); // request read operation
01377     EC_WRITE_U16(datagram->data + 2, fsm->sii_offset);
01378     ec_master_queue_datagram(fsm->master, datagram);
01379     fsm->sii_state = ec_fsm_sii_read_check;
01380 }
01381 
01382 /*****************************************************************************/
01383 
01389 void ec_fsm_sii_read_check(ec_fsm_t *fsm )
01390 {
01391     ec_datagram_t *datagram = &fsm->datagram;
01392 
01393     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01394         EC_ERR("SII: Reception of read datagram failed.\n");
01395         fsm->sii_state = ec_fsm_sii_error;
01396         return;
01397     }
01398 
01399     fsm->sii_start = get_cycles();
01400 
01401     // issue check/fetch datagram
01402     if (fsm->sii_mode) {
01403         ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10);
01404     }
01405     else {
01406         ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
01407     }
01408 
01409     ec_master_queue_datagram(fsm->master, datagram);
01410     fsm->sii_state = ec_fsm_sii_read_fetch;
01411 }
01412 
01413 /*****************************************************************************/
01414 
01420 void ec_fsm_sii_read_fetch(ec_fsm_t *fsm )
01421 {
01422     ec_datagram_t *datagram = &fsm->datagram;
01423 
01424     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01425         EC_ERR("SII: Reception of check/fetch datagram failed.\n");
01426         fsm->sii_state = ec_fsm_sii_error;
01427         return;
01428     }
01429 
01430     // check "busy bit"
01431     if (EC_READ_U8(datagram->data + 1) & 0x81) {
01432         // still busy... timeout?
01433         if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
01434             EC_ERR("SII: Timeout.\n");
01435             fsm->sii_state = ec_fsm_sii_error;
01436 #if 0
01437             EC_DBG("SII busy: %02X %02X %02X %02X\n",
01438                    EC_READ_U8(datagram->data + 0),
01439                    EC_READ_U8(datagram->data + 1),
01440                    EC_READ_U8(datagram->data + 2),
01441                    EC_READ_U8(datagram->data + 3));
01442 #endif
01443         }
01444 
01445         // issue check/fetch datagram again
01446         if (fsm->sii_mode) {
01447             ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 10);
01448         }
01449         else {
01450             ec_datagram_aprd(datagram, fsm->slave->ring_position, 0x502, 10);
01451         }
01452         ec_master_queue_datagram(fsm->master, datagram);
01453         return;
01454     }
01455 
01456 #if 0
01457     EC_DBG("SII rec: %02X %02X %02X %02X - %02X %02X %02X %02X\n",
01458            EC_READ_U8(datagram->data + 0), EC_READ_U8(datagram->data + 1),
01459            EC_READ_U8(datagram->data + 2), EC_READ_U8(datagram->data + 3),
01460            EC_READ_U8(datagram->data + 6), EC_READ_U8(datagram->data + 7),
01461            EC_READ_U8(datagram->data + 8), EC_READ_U8(datagram->data + 9));
01462 #endif
01463 
01464     // SII value received.
01465     memcpy(fsm->sii_value, datagram->data + 6, 4);
01466     fsm->sii_state = ec_fsm_sii_end;
01467 }
01468 
01469 /*****************************************************************************/
01470 
01476 void ec_fsm_sii_start_writing(ec_fsm_t *fsm )
01477 {
01478     ec_datagram_t *datagram = &fsm->datagram;
01479 
01480     // initiate write operation
01481     ec_datagram_npwr(datagram, fsm->slave->station_address, 0x502, 8);
01482     EC_WRITE_U8 (datagram->data,     0x01); // enable write access
01483     EC_WRITE_U8 (datagram->data + 1, 0x02); // request write operation
01484     EC_WRITE_U32(datagram->data + 2, fsm->sii_offset);
01485     memcpy(datagram->data + 6, fsm->sii_value, 2);
01486     ec_master_queue_datagram(fsm->master, datagram);
01487     fsm->sii_state = ec_fsm_sii_write_check;
01488 }
01489 
01490 /*****************************************************************************/
01491 
01496 void ec_fsm_sii_write_check(ec_fsm_t *fsm )
01497 {
01498     ec_datagram_t *datagram = &fsm->datagram;
01499 
01500     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01501         EC_ERR("SII: Reception of write datagram failed.\n");
01502         fsm->sii_state = ec_fsm_sii_error;
01503         return;
01504     }
01505 
01506     fsm->sii_start = get_cycles();
01507 
01508     // issue check/fetch datagram
01509     ec_datagram_nprd(datagram, fsm->slave->station_address, 0x502, 2);
01510     ec_master_queue_datagram(fsm->master, datagram);
01511     fsm->sii_state = ec_fsm_sii_write_check2;
01512 }
01513 
01514 /*****************************************************************************/
01515 
01520 void ec_fsm_sii_write_check2(ec_fsm_t *fsm )
01521 {
01522     ec_datagram_t *datagram = &fsm->datagram;
01523 
01524     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01525         EC_ERR("SII: Reception of write check datagram failed.\n");
01526         fsm->sii_state = ec_fsm_sii_error;
01527         return;
01528     }
01529 
01530     if (EC_READ_U8(datagram->data + 1) & 0x82) {
01531         // still busy... timeout?
01532         if (get_cycles() - fsm->sii_start >= (cycles_t) 10 * cpu_khz) {
01533             EC_ERR("SII: Write timeout.\n");
01534             fsm->sii_state = ec_fsm_sii_error;
01535         }
01536 
01537         // issue check/fetch datagram again
01538         ec_master_queue_datagram(fsm->master, datagram);
01539     }
01540     else if (EC_READ_U8(datagram->data + 1) & 0x40) {
01541         EC_ERR("SII: Write operation failed!\n");
01542         fsm->sii_state = ec_fsm_sii_error;
01543     }
01544     else { // success
01545         fsm->sii_state = ec_fsm_sii_end;
01546     }
01547 }
01548 
01549 /*****************************************************************************/
01550 
01556 void ec_fsm_sii_end(ec_fsm_t *fsm )
01557 {
01558 }
01559 
01560 /*****************************************************************************/
01561 
01567 void ec_fsm_sii_error(ec_fsm_t *fsm )
01568 {
01569 }
01570 
01571 /******************************************************************************
01572  *  state change sub state machine
01573  *****************************************************************************/
01574 
01579 void ec_fsm_change_start(ec_fsm_t *fsm )
01580 {
01581     ec_datagram_t *datagram = &fsm->datagram;
01582     ec_slave_t *slave = fsm->slave;
01583 
01584     // write new state to slave
01585     ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
01586     EC_WRITE_U16(datagram->data, fsm->change_new);
01587     ec_master_queue_datagram(fsm->master, datagram);
01588     fsm->change_state = ec_fsm_change_check;
01589 }
01590 
01591 /*****************************************************************************/
01592 
01597 void ec_fsm_change_check(ec_fsm_t *fsm )
01598 {
01599     ec_datagram_t *datagram = &fsm->datagram;
01600     ec_slave_t *slave = fsm->slave;
01601 
01602     if (datagram->state != EC_CMD_RECEIVED) {
01603         fsm->change_state = ec_fsm_change_error;
01604         EC_ERR("Failed to send state datagram to slave %i!\n",
01605                fsm->slave->ring_position);
01606         return;
01607     }
01608 
01609     if (datagram->working_counter != 1) {
01610         fsm->change_state = ec_fsm_change_error;
01611         EC_ERR("Failed to set state 0x%02X on slave %i: Slave did not"
01612                " respond.\n", fsm->change_new, fsm->slave->ring_position);
01613         return;
01614     }
01615 
01616     fsm->change_start = get_cycles();
01617 
01618     // read AL status from slave
01619     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
01620     ec_master_queue_datagram(fsm->master, datagram);
01621     fsm->change_state = ec_fsm_change_status;
01622 }
01623 
01624 /*****************************************************************************/
01625 
01630 void ec_fsm_change_status(ec_fsm_t *fsm )
01631 {
01632     ec_datagram_t *datagram = &fsm->datagram;
01633     ec_slave_t *slave = fsm->slave;
01634 
01635     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01636         fsm->change_state = ec_fsm_change_error;
01637         EC_ERR("Failed to check state 0x%02X on slave %i.\n",
01638                fsm->change_new, slave->ring_position);
01639         return;
01640     }
01641 
01642     slave->current_state = EC_READ_U8(datagram->data);
01643 
01644     if (slave->current_state == fsm->change_new) {
01645         // state has been set successfully
01646         fsm->change_state = ec_fsm_change_end;
01647         return;
01648     }
01649 
01650     if (slave->current_state & 0x10) {
01651         // state change error
01652         fsm->change_new = slave->current_state & 0x0F;
01653         EC_ERR("Failed to set state 0x%02X - Slave %i refused state change"
01654                " (code 0x%02X)!\n", fsm->change_new, slave->ring_position,
01655                slave->current_state);
01656         // fetch AL status error code
01657         ec_datagram_nprd(datagram, slave->station_address, 0x0134, 2);
01658         ec_master_queue_datagram(fsm->master, datagram);
01659         fsm->change_state = ec_fsm_change_code;
01660         return;
01661     }
01662 
01663     if (get_cycles() - fsm->change_start >= (cycles_t) 10 * cpu_khz) {
01664         // timeout while checking
01665         fsm->change_state = ec_fsm_change_error;
01666         EC_ERR("Timeout while setting state 0x%02X on slave %i.\n",
01667                fsm->change_new, slave->ring_position);
01668         return;
01669     }
01670 
01671     // still old state: check again
01672     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
01673     ec_master_queue_datagram(fsm->master, datagram);
01674 }
01675 
01676 /*****************************************************************************/
01677 
01682 const ec_code_msg_t al_status_messages[] = {
01683     {0x0001, "Unspecified error"},
01684     {0x0011, "Invalud requested state change"},
01685     {0x0012, "Unknown requested state"},
01686     {0x0013, "Bootstrap not supported"},
01687     {0x0014, "No valid firmware"},
01688     {0x0015, "Invalid mailbox configuration"},
01689     {0x0016, "Invalid mailbox configuration"},
01690     {0x0017, "Invalid sync manager configuration"},
01691     {0x0018, "No valid inputs available"},
01692     {0x0019, "No valid outputs"},
01693     {0x001A, "Synchronisation error"},
01694     {0x001B, "Sync manager watchdog"},
01695     {0x001C, "Invalid sync manager types"},
01696     {0x001D, "Invalid output configuration"},
01697     {0x001E, "Invalid input configuration"},
01698     {0x001F, "Invalid watchdog configuration"},
01699     {0x0020, "Slave needs cold start"},
01700     {0x0021, "Slave needs INIT"},
01701     {0x0022, "Slave needs PREOP"},
01702     {0x0023, "Slave needs SAVEOP"},
01703     {0x0030, "Invalid DC SYNCH configuration"},
01704     {0x0031, "Invalid DC latch configuration"},
01705     {0x0032, "PLL error"},
01706     {0x0033, "Invalid DC IO error"},
01707     {0x0034, "Invalid DC timeout error"},
01708     {0x0042, "MBOX EOE"},
01709     {0x0043, "MBOX COE"},
01710     {0x0044, "MBOX FOE"},
01711     {0x0045, "MBOX SOE"},
01712     {0x004F, "MBOX VOE"},
01713     {}
01714 };
01715 
01716 /*****************************************************************************/
01717 
01722 void ec_fsm_change_code(ec_fsm_t *fsm )
01723 {
01724     ec_datagram_t *datagram = &fsm->datagram;
01725     ec_slave_t *slave = fsm->slave;
01726     uint32_t code;
01727     const ec_code_msg_t *al_msg;
01728 
01729     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01730         fsm->change_state = ec_fsm_change_error;
01731         EC_ERR("Reception of AL status code datagram failed.\n");
01732         return;
01733     }
01734 
01735     if ((code = EC_READ_U16(datagram->data))) {
01736         for (al_msg = al_status_messages; al_msg->code; al_msg++) {
01737             if (al_msg->code != code) continue;
01738             EC_ERR("AL status message 0x%04X: \"%s\".\n",
01739                    al_msg->code, al_msg->message);
01740             break;
01741         }
01742         if (!al_msg->code)
01743             EC_ERR("Unknown AL status code 0x%04X.\n", code);
01744     }
01745 
01746     // acknowledge "old" slave state
01747     ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
01748     EC_WRITE_U16(datagram->data, slave->current_state);
01749     ec_master_queue_datagram(fsm->master, datagram);
01750     fsm->change_state = ec_fsm_change_ack;
01751 }
01752 
01753 /*****************************************************************************/
01754 
01759 void ec_fsm_change_ack(ec_fsm_t *fsm )
01760 {
01761     ec_datagram_t *datagram = &fsm->datagram;
01762     ec_slave_t *slave = fsm->slave;
01763 
01764     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01765         fsm->change_state = ec_fsm_change_error;
01766         EC_ERR("Reception of state ack datagram failed.\n");
01767         return;
01768     }
01769 
01770     fsm->change_start = get_cycles();
01771 
01772     // read new AL status
01773     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
01774     ec_master_queue_datagram(fsm->master, datagram);
01775     fsm->change_state = ec_fsm_change_check_ack;
01776 }
01777 
01778 /*****************************************************************************/
01779 
01784 void ec_fsm_change_check_ack(ec_fsm_t *fsm )
01785 {
01786     ec_datagram_t *datagram = &fsm->datagram;
01787     ec_slave_t *slave = fsm->slave;
01788     ec_slave_state_t ack_state;
01789 
01790     if (datagram->state != EC_CMD_RECEIVED || datagram->working_counter != 1) {
01791         fsm->change_state = ec_fsm_change_error;
01792         EC_ERR("Reception of state ack check datagram failed.\n");
01793         return;
01794     }
01795 
01796     ack_state = EC_READ_U8(datagram->data);
01797 
01798     if (ack_state == slave->current_state) {
01799         fsm->change_state = ec_fsm_change_error;
01800         EC_INFO("Acknowleged state 0x%02X on slave %i.\n",
01801                 slave->current_state, slave->ring_position);
01802         return;
01803     }
01804 
01805     if (get_cycles() - fsm->change_start >= (cycles_t) 100 * cpu_khz) {
01806         // timeout while checking
01807         slave->current_state = EC_SLAVE_STATE_UNKNOWN;
01808         fsm->change_state = ec_fsm_change_error;
01809         EC_ERR("Timeout while acknowleging state 0x%02X on slave %i.\n",
01810                fsm->change_new, slave->ring_position);
01811         return;
01812     }
01813 
01814     // reread new AL status
01815     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
01816     ec_master_queue_datagram(fsm->master, datagram);
01817 }
01818 
01819 /*****************************************************************************/
01820 
01825 void ec_fsm_change_end(ec_fsm_t *fsm )
01826 {
01827 }
01828 
01829 /*****************************************************************************/
01830 
01835 void ec_fsm_change_error(ec_fsm_t *fsm )
01836 {
01837 }
01838 
01839 /*****************************************************************************/

Generated on Wed Aug 2 18:41:43 2006 for IgH EtherCAT master by  doxygen 1.4.6