Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

fsm_change.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  *  $Id: fsm_change.c 682 2006-11-07 12:13:30Z 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 "master.h"
00043 #include "fsm_change.h"
00044 
00045 /*****************************************************************************/
00046 
00047 void ec_fsm_change_state_start(ec_fsm_change_t *);
00048 void ec_fsm_change_state_check(ec_fsm_change_t *);
00049 void ec_fsm_change_state_status(ec_fsm_change_t *);
00050 void ec_fsm_change_state_code(ec_fsm_change_t *);
00051 void ec_fsm_change_state_start_ack(ec_fsm_change_t *);
00052 void ec_fsm_change_state_ack(ec_fsm_change_t *);
00053 void ec_fsm_change_state_check_ack(ec_fsm_change_t *);
00054 void ec_fsm_change_state_end(ec_fsm_change_t *);
00055 void ec_fsm_change_state_error(ec_fsm_change_t *);
00056 
00057 /*****************************************************************************/
00058 
00063 void ec_fsm_change_init(ec_fsm_change_t *fsm, 
00064                         ec_datagram_t *datagram 
00065                         )
00066 {
00067     fsm->state = NULL;
00068     fsm->datagram = datagram;
00069 }
00070 
00071 /*****************************************************************************/
00072 
00077 void ec_fsm_change_clear(ec_fsm_change_t *fsm )
00078 {
00079 }
00080 
00081 /*****************************************************************************/
00082 
00087 void ec_fsm_change_start(ec_fsm_change_t *fsm, 
00088                          ec_slave_t *slave, 
00089                          ec_slave_state_t state 
00090                          )
00091 {
00092     fsm->mode = EC_FSM_CHANGE_MODE_FULL;
00093     fsm->slave = slave;
00094     fsm->requested_state = state;
00095     fsm->state = ec_fsm_change_state_start;
00096 }
00097 
00098 /*****************************************************************************/
00099 
00104 void ec_fsm_change_ack(ec_fsm_change_t *fsm, 
00105                        ec_slave_t *slave 
00106                        )
00107 {
00108     fsm->mode = EC_FSM_CHANGE_MODE_ACK_ONLY;
00109     fsm->slave = slave;
00110     fsm->requested_state = EC_SLAVE_STATE_UNKNOWN;
00111     fsm->state = ec_fsm_change_state_start_ack;
00112 }
00113 
00114 /*****************************************************************************/
00115 
00121 int ec_fsm_change_exec(ec_fsm_change_t *fsm )
00122 {
00123     fsm->state(fsm);
00124 
00125     return fsm->state != ec_fsm_change_state_end
00126         && fsm->state != ec_fsm_change_state_error;
00127 }
00128 
00129 /*****************************************************************************/
00130 
00136 int ec_fsm_change_success(ec_fsm_change_t *fsm )
00137 {
00138     return fsm->state == ec_fsm_change_state_end;
00139 }
00140 
00141 /******************************************************************************
00142  *  state change state machine
00143  *****************************************************************************/
00144 
00149 void ec_fsm_change_state_start(ec_fsm_change_t *fsm)
00151 {
00152     ec_datagram_t *datagram = fsm->datagram;
00153     ec_slave_t *slave = fsm->slave;
00154 
00155     fsm->take_time = 1;
00156     fsm->old_state = fsm->slave->current_state;
00157 
00158     // write new state to slave
00159     ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
00160     EC_WRITE_U16(datagram->data, fsm->requested_state);
00161     ec_master_queue_datagram(fsm->slave->master, datagram);
00162     fsm->state = ec_fsm_change_state_check;
00163 }
00164 
00165 /*****************************************************************************/
00166 
00171 void ec_fsm_change_state_check(ec_fsm_change_t *fsm)
00173 {
00174     ec_datagram_t *datagram = fsm->datagram;
00175     ec_slave_t *slave = fsm->slave;
00176 
00177     if (datagram->state != EC_DATAGRAM_RECEIVED) {
00178         fsm->state = ec_fsm_change_state_error;
00179         EC_ERR("Failed to send state datagram to slave %i!\n",
00180                fsm->slave->ring_position);
00181         return;
00182     }
00183 
00184     if (fsm->take_time) {
00185         fsm->take_time = 0;
00186         fsm->jiffies_start = datagram->jiffies_sent;
00187     }
00188 
00189     if (datagram->working_counter != 1) {
00190         if (datagram->jiffies_received - fsm->jiffies_start >= 3 * HZ) {
00191             char state_str[EC_STATE_STRING_SIZE];
00192             ec_state_string(fsm->requested_state, state_str);
00193             fsm->state = ec_fsm_change_state_error;
00194             EC_ERR("Failed to set state %s on slave %i: Slave did not"
00195                    " respond.\n", state_str, fsm->slave->ring_position);
00196             return;
00197         }
00198 
00199         // repeat writing new state to slave
00200         ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
00201         EC_WRITE_U16(datagram->data, fsm->requested_state);
00202         ec_master_queue_datagram(fsm->slave->master, datagram);
00203         return;
00204     }
00205 
00206     fsm->take_time = 1;
00207 
00208     // read AL status from slave
00209     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
00210     ec_master_queue_datagram(fsm->slave->master, datagram);
00211     fsm->state = ec_fsm_change_state_status;
00212 }
00213 
00214 /*****************************************************************************/
00215 
00220 void ec_fsm_change_state_status(ec_fsm_change_t *fsm)
00222 {
00223     ec_datagram_t *datagram = fsm->datagram;
00224     ec_slave_t *slave = fsm->slave;
00225 
00226     if (datagram->state != EC_DATAGRAM_RECEIVED
00227         || datagram->working_counter != 1) {
00228         char req_state[EC_STATE_STRING_SIZE];
00229         ec_state_string(fsm->requested_state, req_state);
00230         fsm->state = ec_fsm_change_state_error;
00231         EC_ERR("Failed to check state %s on slave %i.\n",
00232                req_state, slave->ring_position);
00233         return;
00234     }
00235 
00236     if (fsm->take_time) {
00237         fsm->take_time = 0;
00238         fsm->jiffies_start = datagram->jiffies_sent;
00239     }
00240 
00241     slave->current_state = EC_READ_U8(datagram->data);
00242 
00243     if (slave->current_state == fsm->requested_state) {
00244         // state has been set successfully
00245         fsm->state = ec_fsm_change_state_end;
00246         return;
00247     }
00248 
00249     if (slave->current_state != fsm->old_state) { // state changed
00250         char req_state[EC_STATE_STRING_SIZE], cur_state[EC_STATE_STRING_SIZE];
00251 
00252         ec_state_string(slave->current_state, cur_state);
00253 
00254         if ((slave->current_state & 0x0F) != (fsm->old_state & 0x0F)) {
00255             // Slave spontaneously changed its state just before the new state
00256             // was written. Accept current state as old state and wait for
00257             // state change
00258             fsm->old_state = slave->current_state;
00259             EC_WARN("Slave %i changed to %s in the meantime.\n",
00260                     slave->ring_position, cur_state);
00261             goto again;
00262         }
00263 
00264         // state change error
00265 
00266         slave->error_flag = 1;
00267         ec_state_string(fsm->requested_state, req_state);
00268 
00269         EC_ERR("Failed to set %s state, slave %i refused state change (%s).\n",
00270                req_state, slave->ring_position, cur_state);
00271         // fetch AL status error code
00272         ec_datagram_nprd(datagram, slave->station_address, 0x0134, 2);
00273         ec_master_queue_datagram(fsm->slave->master, datagram);
00274         fsm->state = ec_fsm_change_state_code;
00275         return;
00276     }
00277 
00278     // still old state
00279 
00280     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
00281         // timeout while checking
00282         char state_str[EC_STATE_STRING_SIZE];
00283         ec_state_string(fsm->requested_state, state_str);
00284         fsm->state = ec_fsm_change_state_error;
00285         EC_ERR("Timeout while setting state %s on slave %i.\n",
00286                state_str, slave->ring_position);
00287         return;
00288     }
00289 
00290  again:
00291     // no timeout yet. check again
00292     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
00293     ec_master_queue_datagram(fsm->slave->master, datagram);
00294 }
00295 
00296 /*****************************************************************************/
00297 
00302 const ec_code_msg_t al_status_messages[] = {
00303     {0x0001, "Unspecified error"},
00304     {0x0011, "Invalud requested state change"},
00305     {0x0012, "Unknown requested state"},
00306     {0x0013, "Bootstrap not supported"},
00307     {0x0014, "No valid firmware"},
00308     {0x0015, "Invalid mailbox configuration"},
00309     {0x0016, "Invalid mailbox configuration"},
00310     {0x0017, "Invalid sync manager configuration"},
00311     {0x0018, "No valid inputs available"},
00312     {0x0019, "No valid outputs"},
00313     {0x001A, "Synchronisation error"},
00314     {0x001B, "Sync manager watchdog"},
00315     {0x001C, "Invalid sync manager types"},
00316     {0x001D, "Invalid output configuration"},
00317     {0x001E, "Invalid input configuration"},
00318     {0x001F, "Invalid watchdog configuration"},
00319     {0x0020, "Slave needs cold start"},
00320     {0x0021, "Slave needs INIT"},
00321     {0x0022, "Slave needs PREOP"},
00322     {0x0023, "Slave needs SAVEOP"},
00323     {0x0030, "Invalid DC SYNCH configuration"},
00324     {0x0031, "Invalid DC latch configuration"},
00325     {0x0032, "PLL error"},
00326     {0x0033, "Invalid DC IO error"},
00327     {0x0034, "Invalid DC timeout error"},
00328     {0x0042, "MBOX EOE"},
00329     {0x0043, "MBOX COE"},
00330     {0x0044, "MBOX FOE"},
00331     {0x0045, "MBOX SOE"},
00332     {0x004F, "MBOX VOE"},
00333     {}
00334 };
00335 
00336 /*****************************************************************************/
00337 
00342 void ec_fsm_change_state_code(ec_fsm_change_t *fsm)
00344 {
00345     ec_datagram_t *datagram = fsm->datagram;
00346     uint32_t code;
00347     const ec_code_msg_t *al_msg;
00348 
00349     if (datagram->state != EC_DATAGRAM_RECEIVED
00350         || datagram->working_counter != 1) {
00351         EC_WARN("Reception of AL status code datagram failed.\n");
00352     }
00353     else {
00354         if ((code = EC_READ_U16(datagram->data))) {
00355             for (al_msg = al_status_messages; al_msg->code; al_msg++) {
00356                 if (al_msg->code != code) continue;
00357                 EC_ERR("AL status message 0x%04X: \"%s\".\n",
00358                        al_msg->code, al_msg->message);
00359                 break;
00360             }
00361             if (!al_msg->code)
00362                 EC_ERR("Unknown AL status code 0x%04X.\n", code);
00363         }
00364     }
00365 
00366     // acknowledge "old" slave state
00367     ec_fsm_change_state_start_ack(fsm); // execute immediately
00368 }
00369 
00370 /*****************************************************************************/
00371 
00376 void ec_fsm_change_state_start_ack(ec_fsm_change_t *fsm)
00378 {
00379     ec_slave_t *slave = fsm->slave;
00380     ec_datagram_t *datagram = fsm->datagram;
00381 
00382     ec_datagram_npwr(datagram, slave->station_address, 0x0120, 2);
00383     EC_WRITE_U16(datagram->data, slave->current_state);
00384     ec_master_queue_datagram(fsm->slave->master, datagram);
00385     fsm->state = ec_fsm_change_state_ack;
00386 }
00387 
00388 /*****************************************************************************/
00389 
00394 void ec_fsm_change_state_ack(ec_fsm_change_t *fsm )
00395 {
00396     ec_datagram_t *datagram = fsm->datagram;
00397     ec_slave_t *slave = fsm->slave;
00398 
00399     if (datagram->state != EC_DATAGRAM_RECEIVED
00400         || datagram->working_counter != 1) {
00401         fsm->state = ec_fsm_change_state_error;
00402         EC_ERR("Reception of state ack datagram failed.\n");
00403         return;
00404     }
00405 
00406     fsm->take_time = 1;
00407 
00408     // read new AL status
00409     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
00410     ec_master_queue_datagram(fsm->slave->master, datagram);
00411     fsm->state = ec_fsm_change_state_check_ack;
00412 }
00413 
00414 /*****************************************************************************/
00415 
00420 void ec_fsm_change_state_check_ack(ec_fsm_change_t *fsm)
00422 {
00423     ec_datagram_t *datagram = fsm->datagram;
00424     ec_slave_t *slave = fsm->slave;
00425 
00426     if (datagram->state != EC_DATAGRAM_RECEIVED
00427         || datagram->working_counter != 1) {
00428         fsm->state = ec_fsm_change_state_error;
00429         EC_ERR("Reception of state ack check datagram failed.\n");
00430         return;
00431     }
00432 
00433     if (fsm->take_time) {
00434         fsm->take_time = 0;
00435         fsm->jiffies_start = datagram->jiffies_sent;
00436     }
00437 
00438     slave->current_state = EC_READ_U8(datagram->data);
00439 
00440     if (!(slave->current_state & EC_SLAVE_STATE_ACK_ERR)) {
00441         char state_str[EC_STATE_STRING_SIZE];
00442         ec_state_string(slave->current_state, state_str);
00443         if (fsm->mode == EC_FSM_CHANGE_MODE_FULL) {
00444             fsm->state = ec_fsm_change_state_error;
00445         }
00446         else { // EC_FSM_CHANGE_MODE_ACK_ONLY
00447             fsm->state = ec_fsm_change_state_end;
00448         }
00449         EC_INFO("Acknowledged state %s on slave %i.\n",
00450                 state_str, slave->ring_position);
00451         return;
00452     }
00453 
00454     if (datagram->jiffies_received - fsm->jiffies_start >= HZ) { // 1s
00455         // timeout while checking
00456         char state_str[EC_STATE_STRING_SIZE];
00457         ec_state_string(slave->current_state, state_str);
00458         fsm->state = ec_fsm_change_state_error;
00459         EC_ERR("Timeout while acknowledging state %s on slave %i.\n",
00460                state_str, slave->ring_position);
00461         return;
00462     }
00463 
00464     // reread new AL status
00465     ec_datagram_nprd(datagram, slave->station_address, 0x0130, 2);
00466     ec_master_queue_datagram(fsm->slave->master, datagram);
00467 }
00468 
00469 /*****************************************************************************/
00470 
00475 void ec_fsm_change_state_error(ec_fsm_change_t *fsm)
00477 {
00478 }
00479 
00480 /*****************************************************************************/
00481 
00486 void ec_fsm_change_state_end(ec_fsm_change_t *fsm)
00488 {
00489 }
00490 
00491 /*****************************************************************************/

Generated on Tue Nov 7 15:03:35 2006 for IgH EtherCAT master by  doxygen 1.4.4