master/fsm_eoe.c
changeset 2597 0e145bb05859
child 2642 9dc0b2262f90
equal deleted inserted replaced
2596:d71acfbd7319 2597:0e145bb05859
       
     1 /******************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
       
     6  *
       
     7  *  This file is part of the IgH EtherCAT Master.
       
     8  *
       
     9  *  The IgH EtherCAT Master is free software; you can redistribute it and/or
       
    10  *  modify it under the terms of the GNU General Public License version 2, as
       
    11  *  published by the Free Software Foundation.
       
    12  *
       
    13  *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
       
    14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       
    16  *  Public License for more details.
       
    17  *
       
    18  *  You should have received a copy of the GNU General Public License along
       
    19  *  with the IgH EtherCAT Master; if not, write to the Free Software
       
    20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    21  *
       
    22  *  ---
       
    23  *
       
    24  *  The license mentioned above concerns the source code only. Using the
       
    25  *  EtherCAT technology and brand is only permitted in compliance with the
       
    26  *  industrial property and similar rights of Beckhoff Automation GmbH.
       
    27  *
       
    28  *****************************************************************************/
       
    29 
       
    30 /**
       
    31    \file
       
    32    EtherCAT EoE state machines.
       
    33 */
       
    34 
       
    35 /*****************************************************************************/
       
    36 
       
    37 #include "globals.h"
       
    38 #include "master.h"
       
    39 #include "mailbox.h"
       
    40 #include "fsm_eoe.h"
       
    41 
       
    42 /*****************************************************************************/
       
    43 
       
    44 /** Maximum time to wait for a set IP parameter response.
       
    45  */
       
    46 #define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
       
    47 
       
    48 /*****************************************************************************/
       
    49 
       
    50 void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *);
       
    51 void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *);
       
    52 void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *);
       
    53 void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *);
       
    54 
       
    55 void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *);
       
    56 void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *);
       
    57 
       
    58 /*****************************************************************************/
       
    59 
       
    60 /** Constructor.
       
    61  */
       
    62 void ec_fsm_eoe_init(
       
    63         ec_fsm_eoe_t *fsm /**< finite state machine */
       
    64         )
       
    65 {
       
    66     fsm->slave = NULL;
       
    67     fsm->retries = 0;
       
    68     fsm->state = NULL;
       
    69     fsm->datagram = NULL;
       
    70     fsm->jiffies_start = 0;
       
    71     fsm->request = NULL;
       
    72 }
       
    73 
       
    74 /*****************************************************************************/
       
    75 
       
    76 /** Destructor.
       
    77  */
       
    78 void ec_fsm_eoe_clear(
       
    79         ec_fsm_eoe_t *fsm /**< finite state machine */
       
    80         )
       
    81 {
       
    82 }
       
    83 
       
    84 /*****************************************************************************/
       
    85 
       
    86 /** Starts to set the EoE IP partameters of a slave.
       
    87  */
       
    88 void ec_fsm_eoe_set_ip_param(
       
    89         ec_fsm_eoe_t *fsm, /**< State machine. */
       
    90         ec_slave_t *slave, /**< EtherCAT slave. */
       
    91         ec_eoe_request_t *request /**< EoE request. */
       
    92         )
       
    93 {
       
    94     fsm->slave = slave;
       
    95     fsm->request = request;
       
    96     fsm->state = ec_fsm_eoe_set_ip_start;
       
    97 }
       
    98 
       
    99 /*****************************************************************************/
       
   100 
       
   101 /** Executes the current state of the state machine.
       
   102  *
       
   103  * \return 1 if the datagram was used, else 0.
       
   104  */
       
   105 int ec_fsm_eoe_exec(
       
   106         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   107         ec_datagram_t *datagram /**< Datagram to use. */
       
   108         )
       
   109 {
       
   110     int datagram_used = 0;
       
   111 
       
   112     if (fsm->datagram &&
       
   113             (fsm->datagram->state == EC_DATAGRAM_INIT ||
       
   114              fsm->datagram->state == EC_DATAGRAM_QUEUED ||
       
   115              fsm->datagram->state == EC_DATAGRAM_SENT)) {
       
   116         // datagram not received yet
       
   117         return datagram_used;
       
   118     }
       
   119 
       
   120     fsm->state(fsm, datagram);
       
   121 
       
   122     datagram_used =
       
   123         fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error;
       
   124 
       
   125     if (datagram_used) {
       
   126         fsm->datagram = datagram;
       
   127     } else {
       
   128         fsm->datagram = NULL;
       
   129     }
       
   130 
       
   131     return datagram_used;
       
   132 }
       
   133 
       
   134 /*****************************************************************************/
       
   135 
       
   136 /** Returns, if the state machine terminated with success.
       
   137  *
       
   138  * \return non-zero if successful.
       
   139  */
       
   140 int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */)
       
   141 {
       
   142     return fsm->state == ec_fsm_eoe_end;
       
   143 }
       
   144 
       
   145 /******************************************************************************
       
   146  * EoE set IP parameter state machine
       
   147  *****************************************************************************/
       
   148 
       
   149 /** Prepare a set IP parameters operation.
       
   150  *
       
   151  * \return 0 on success, otherwise a negative error code.
       
   152  */
       
   153 int ec_fsm_eoe_prepare_set(
       
   154         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   155         ec_datagram_t *datagram /**< Datagram to use. */
       
   156         )
       
   157 {
       
   158     uint8_t *data, *cur;
       
   159     ec_slave_t *slave = fsm->slave;
       
   160     ec_master_t *master = slave->master;
       
   161     ec_eoe_request_t *req = fsm->request;
       
   162     size_t size = 8;
       
   163 
       
   164     if (req->mac_address_included) {
       
   165         size += ETH_ALEN;
       
   166     }
       
   167 
       
   168     if (req->ip_address_included) {
       
   169         size += 4;
       
   170     }
       
   171 
       
   172     if (req->subnet_mask_included) {
       
   173         size += 4;
       
   174     }
       
   175 
       
   176     if (req->gateway_included) {
       
   177         size += 4;
       
   178     }
       
   179 
       
   180     if (req->dns_included) {
       
   181         size += 4;
       
   182     }
       
   183 
       
   184     if (req->name_included) {
       
   185         size += EC_MAX_HOSTNAME_SIZE;
       
   186     }
       
   187 
       
   188     data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
       
   189             size);
       
   190     if (IS_ERR(data)) {
       
   191         return PTR_ERR(data);
       
   192     }
       
   193 
       
   194     EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
       
   195     EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps
       
   196     EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no.
       
   197 
       
   198     EC_WRITE_U32(data + 4,
       
   199             ((req->mac_address_included != 0) << 0) |
       
   200             ((req->ip_address_included != 0) << 1) |
       
   201             ((req->subnet_mask_included != 0) << 2) |
       
   202             ((req->gateway_included != 0) << 3) |
       
   203             ((req->dns_included != 0) << 4) |
       
   204             ((req->name_included != 0) << 5)
       
   205             );
       
   206 
       
   207     cur = data + 8;
       
   208 
       
   209     if (req->mac_address_included) {
       
   210         memcpy(cur, req->mac_address, ETH_ALEN);
       
   211         cur += ETH_ALEN;
       
   212     }
       
   213 
       
   214     if (req->ip_address_included) {
       
   215         memcpy(cur, &req->ip_address, 4);
       
   216         cur += 4;
       
   217     }
       
   218 
       
   219     if (req->subnet_mask_included) {
       
   220         memcpy(cur, &req->subnet_mask, 4);
       
   221         cur += 4;
       
   222     }
       
   223 
       
   224     if (req->gateway_included) {
       
   225         memcpy(cur, &req->gateway, 4);
       
   226         cur += 4;
       
   227     }
       
   228 
       
   229     if (req->dns_included) {
       
   230         memcpy(cur, &req->dns, 4);
       
   231         cur += 4;
       
   232     }
       
   233 
       
   234     if (req->name_included) {
       
   235         memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
       
   236         cur += EC_MAX_HOSTNAME_SIZE;
       
   237     }
       
   238 
       
   239     if (master->debug_level) {
       
   240         EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
       
   241         ec_print_data(data, cur - data);
       
   242     }
       
   243 
       
   244     fsm->request->jiffies_sent = jiffies;
       
   245 
       
   246     return 0;
       
   247 }
       
   248 
       
   249 /*****************************************************************************/
       
   250 
       
   251 /** EoE state: SET IP START.
       
   252  */
       
   253 void ec_fsm_eoe_set_ip_start(
       
   254         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   255         ec_datagram_t *datagram /**< Datagram to use. */
       
   256         )
       
   257 {
       
   258     ec_slave_t *slave = fsm->slave;
       
   259 
       
   260     EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
       
   261 
       
   262     if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
       
   263         EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
       
   264         fsm->state = ec_fsm_eoe_error;
       
   265         return;
       
   266     }
       
   267 
       
   268     if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
       
   269         fsm->state = ec_fsm_eoe_error;
       
   270         return;
       
   271     }
       
   272 
       
   273     fsm->retries = EC_FSM_RETRIES;
       
   274     fsm->state = ec_fsm_eoe_set_ip_request;
       
   275 }
       
   276 
       
   277 /*****************************************************************************/
       
   278 
       
   279 /** EoE state: SET IP REQUEST.
       
   280  */
       
   281 void ec_fsm_eoe_set_ip_request(
       
   282         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   283         ec_datagram_t *datagram /**< Datagram to use. */
       
   284         )
       
   285 {
       
   286     ec_slave_t *slave = fsm->slave;
       
   287 
       
   288     if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
       
   289         if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
       
   290             fsm->state = ec_fsm_eoe_error;
       
   291         }
       
   292         return;
       
   293     }
       
   294 
       
   295     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
       
   296         fsm->state = ec_fsm_eoe_error;
       
   297         EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
       
   298                 " request: ");
       
   299         ec_datagram_print_state(fsm->datagram);
       
   300         return;
       
   301     }
       
   302 
       
   303     if (fsm->datagram->working_counter != 1) {
       
   304         unsigned long diff_ms =
       
   305             (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
       
   306 
       
   307         if (!fsm->datagram->working_counter) {
       
   308             if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
       
   309                 // no response; send request datagram again
       
   310                 if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
       
   311                     fsm->state = ec_fsm_eoe_error;
       
   312                 }
       
   313                 return;
       
   314             }
       
   315         }
       
   316         fsm->state = ec_fsm_eoe_error;
       
   317         EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
       
   318                 " failed after %lu ms: ", diff_ms);
       
   319         ec_datagram_print_wc_error(fsm->datagram);
       
   320         return;
       
   321     }
       
   322 
       
   323     fsm->jiffies_start = fsm->datagram->jiffies_sent;
       
   324     ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
   325     fsm->retries = EC_FSM_RETRIES;
       
   326     fsm->state = ec_fsm_eoe_set_ip_check;
       
   327 }
       
   328 
       
   329 /*****************************************************************************/
       
   330 
       
   331 /** EoE state: SET IP CHECK.
       
   332  */
       
   333 void ec_fsm_eoe_set_ip_check(
       
   334         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   335         ec_datagram_t *datagram /**< Datagram to use. */
       
   336         )
       
   337 {
       
   338     ec_slave_t *slave = fsm->slave;
       
   339 
       
   340     if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
       
   341         ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
   342         return;
       
   343     }
       
   344 
       
   345     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
       
   346         fsm->state = ec_fsm_eoe_error;
       
   347         EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
       
   348         ec_datagram_print_state(fsm->datagram);
       
   349         return;
       
   350     }
       
   351 
       
   352     if (fsm->datagram->working_counter != 1) {
       
   353         fsm->state = ec_fsm_eoe_error;
       
   354         EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
       
   355                 " datagram failed: ");
       
   356         ec_datagram_print_wc_error(fsm->datagram);
       
   357         return;
       
   358     }
       
   359 
       
   360     if (!ec_slave_mbox_check(fsm->datagram)) {
       
   361         unsigned long diff_ms =
       
   362             (fsm->datagram->jiffies_received - fsm->jiffies_start) *
       
   363             1000 / HZ;
       
   364         if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
       
   365             fsm->state = ec_fsm_eoe_error;
       
   366             EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
       
   367                     " set IP parameter response.\n", diff_ms);
       
   368             return;
       
   369         }
       
   370 
       
   371         ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
       
   372         fsm->retries = EC_FSM_RETRIES;
       
   373         return;
       
   374     }
       
   375 
       
   376     // fetch response
       
   377     ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
       
   378     fsm->retries = EC_FSM_RETRIES;
       
   379     fsm->state = ec_fsm_eoe_set_ip_response;
       
   380 }
       
   381 
       
   382 /*****************************************************************************/
       
   383 
       
   384 /** EoE state: SET IP RESPONSE.
       
   385  */
       
   386 void ec_fsm_eoe_set_ip_response(
       
   387         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   388         ec_datagram_t *datagram /**< Datagram to use. */
       
   389         )
       
   390 {
       
   391     ec_slave_t *slave = fsm->slave;
       
   392     ec_master_t *master = slave->master;
       
   393     uint8_t *data, mbox_prot, frame_type;
       
   394     size_t rec_size;
       
   395     ec_eoe_request_t *req = fsm->request;
       
   396 
       
   397     if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
       
   398         ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
       
   399         return;
       
   400     }
       
   401 
       
   402     if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
       
   403         fsm->state = ec_fsm_eoe_error;
       
   404         EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
       
   405         ec_datagram_print_state(fsm->datagram);
       
   406         return;
       
   407     }
       
   408 
       
   409     if (fsm->datagram->working_counter != 1) {
       
   410         fsm->state = ec_fsm_eoe_error;
       
   411         EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
       
   412         ec_datagram_print_wc_error(fsm->datagram);
       
   413         return;
       
   414     }
       
   415 
       
   416     data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size);
       
   417     if (IS_ERR(data)) {
       
   418         fsm->state = ec_fsm_eoe_error;
       
   419         return;
       
   420     }
       
   421 
       
   422     if (master->debug_level) {
       
   423         EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
       
   424         ec_print_data(data, rec_size);
       
   425     }
       
   426 
       
   427     if (mbox_prot != EC_MBOX_TYPE_EOE) {
       
   428         fsm->state = ec_fsm_eoe_error;
       
   429         EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
       
   430                 mbox_prot);
       
   431         return;
       
   432     }
       
   433 
       
   434     if (rec_size < 4) {
       
   435         fsm->state = ec_fsm_eoe_error;
       
   436         EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
       
   437                 " (%zu bytes)!\n", rec_size);
       
   438         ec_print_data(data, rec_size);
       
   439         return;
       
   440     }
       
   441 
       
   442     frame_type = EC_READ_U8(data) & 0x0f;
       
   443 
       
   444     if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
       
   445         EC_SLAVE_ERR(slave, "Received no set IP parameter response"
       
   446                 " (frame type %x).\n", frame_type);
       
   447         ec_print_data(data, rec_size);
       
   448         fsm->state = ec_fsm_eoe_error;
       
   449         return;
       
   450     }
       
   451 
       
   452     req->result = EC_READ_U16(data + 2);
       
   453 
       
   454     if (req->result) {
       
   455         fsm->state = ec_fsm_eoe_error;
       
   456         EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
       
   457                 " 0x%04X.\n", req->result);
       
   458     } else {
       
   459         fsm->state = ec_fsm_eoe_end; // success
       
   460     }
       
   461 }
       
   462 
       
   463 /*****************************************************************************/
       
   464 
       
   465 /** State: ERROR.
       
   466  */
       
   467 void ec_fsm_eoe_error(
       
   468         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   469         ec_datagram_t *datagram /**< Datagram to use. */
       
   470         )
       
   471 {
       
   472 }
       
   473 
       
   474 /*****************************************************************************/
       
   475 
       
   476 /** State: END.
       
   477  */
       
   478 void ec_fsm_eoe_end(
       
   479         ec_fsm_eoe_t *fsm, /**< finite state machine */
       
   480         ec_datagram_t *datagram /**< Datagram to use. */
       
   481         )
       
   482 {
       
   483 }
       
   484 
       
   485 /*****************************************************************************/