fp@98: /******************************************************************************
fp@98:  *
fp@98:  *  $Id$
fp@98:  *
fp@197:  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
fp@197:  *
fp@197:  *  This file is part of the IgH EtherCAT Master.
fp@197:  *
fp@197:  *  The IgH EtherCAT Master is free software; you can redistribute it
fp@197:  *  and/or modify it under the terms of the GNU General Public License
fp@246:  *  as published by the Free Software Foundation; either version 2 of the
fp@246:  *  License, or (at your option) any later version.
fp@197:  *
fp@197:  *  The IgH EtherCAT Master is distributed in the hope that it will be
fp@197:  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
fp@197:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fp@197:  *  GNU General Public License for more details.
fp@197:  *
fp@197:  *  You should have received a copy of the GNU General Public License
fp@197:  *  along with the IgH EtherCAT Master; if not, write to the Free Software
fp@197:  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
fp@197:  *
fp@246:  *  The right to use EtherCAT Technology is granted and comes free of
fp@246:  *  charge under condition of compatibility of product made by
fp@246:  *  Licensee. People intending to distribute/sell products based on the
fp@246:  *  code, have to sign an agreement to guarantee that products using
fp@246:  *  software based on IgH EtherCAT master stay compatible with the actual
fp@246:  *  EtherCAT specification (which are released themselves as an open
fp@246:  *  standard) as the (only) precondition to have the right to use EtherCAT
fp@246:  *  Technology, IP and trade marks.
fp@246:  *
fp@98:  *****************************************************************************/
fp@98: 
fp@199: /**
fp@199:    \file
fp@293:    Methods of an EtherCAT datagram.
fp@199: */
fp@199: 
fp@199: /*****************************************************************************/
fp@199: 
fp@98: #include <linux/slab.h>
fp@98: 
fp@293: #include "datagram.h"
fp@98: #include "master.h"
fp@98: 
fp@98: /*****************************************************************************/
fp@98: 
fp@199: /** \cond */
fp@199: 
fp@98: #define EC_FUNC_HEADER \
fp@293:     if (unlikely(ec_datagram_prealloc(datagram, data_size))) \
fp@144:         return -1; \
fp@293:     datagram->index = 0; \
fp@293:     datagram->working_counter = 0; \
fp@325:     datagram->state = EC_DATAGRAM_INIT;
fp@98: 
fp@144: #define EC_FUNC_FOOTER \
fp@293:     datagram->data_size = data_size; \
fp@293:     memset(datagram->data, 0x00, data_size); \
fp@144:     return 0;
fp@144: 
fp@199: /** \endcond */
fp@199: 
fp@144: /*****************************************************************************/
fp@144: 
fp@144: /**
fp@293:    Datagram constructor.
fp@293: */
fp@293: 
fp@293: void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram */)
fp@293: {
fp@446:     INIT_LIST_HEAD(&datagram->queue); // mark as unqueued
fp@325:     datagram->type = EC_DATAGRAM_NONE;
fp@293:     datagram->address.logical = 0x00000000;
fp@293:     datagram->data = NULL;
fp@293:     datagram->mem_size = 0;
fp@293:     datagram->data_size = 0;
fp@293:     datagram->index = 0x00;
fp@293:     datagram->working_counter = 0x00;
fp@325:     datagram->state = EC_DATAGRAM_INIT;
fp@398:     datagram->cycles_queued = 0;
fp@344:     datagram->cycles_sent = 0;
fp@398:     datagram->jiffies_sent = 0;
fp@398:     datagram->cycles_received = 0;
fp@398:     datagram->jiffies_received = 0;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Datagram destructor.
fp@293: */
fp@293: 
fp@293: void ec_datagram_clear(ec_datagram_t *datagram /**< EtherCAT datagram */)
fp@293: {
fp@293:     if (datagram->data) kfree(datagram->data);
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Allocates datagram data memory.
fp@197:    If the allocated memory is already larger than requested, nothing ist done.
fp@197:    \return 0 in case of success, else < 0
fp@197: */
fp@197: 
fp@293: int ec_datagram_prealloc(ec_datagram_t *datagram, /**< EtherCAT datagram */
fp@293:                          size_t size /**< New size in bytes */
fp@293:                          )
fp@293: {
fp@293:     if (size <= datagram->mem_size) return 0;
fp@293: 
fp@293:     if (datagram->data) {
fp@293:         kfree(datagram->data);
fp@293:         datagram->data = NULL;
fp@293:         datagram->mem_size = 0;
fp@144:     }
fp@144: 
fp@293:     if (!(datagram->data = kmalloc(size, GFP_KERNEL))) {
fp@293:         EC_ERR("Failed to allocate %i bytes of datagram memory!\n", size);
fp@144:         return -1;
fp@144:     }
fp@144: 
fp@293:     datagram->mem_size = size;
fp@144:     return 0;
fp@144: }
fp@98: 
fp@98: /*****************************************************************************/
fp@98: 
fp@98: /**
fp@293:    Initializes an EtherCAT NPRD datagram.
fp@98:    Node-adressed physical read.
fp@195:    \return 0 in case of success, else < 0
fp@98: */
fp@98: 
fp@293: int ec_datagram_nprd(ec_datagram_t *datagram,
fp@293:                      /**< EtherCAT datagram */
fp@293:                      uint16_t node_address,
fp@293:                      /**< configured station address */
fp@293:                      uint16_t offset,
fp@293:                      /**< physical memory address */
fp@293:                      size_t data_size
fp@293:                      /**< number of bytes to read */
fp@293:                      )
fp@293: {
fp@293:     if (unlikely(node_address == 0x0000))
fp@293:         EC_WARN("Using node address 0x0000!\n");
fp@293: 
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_NPRD;
fp@293:     datagram->address.physical.slave = node_address;
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT NPWR datagram.
fp@293:    Node-adressed physical write.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_npwr(ec_datagram_t *datagram,
fp@293:                      /**< EtherCAT datagram */
fp@293:                      uint16_t node_address,
fp@293:                      /**< configured station address */
fp@293:                      uint16_t offset,
fp@293:                      /**< physical memory address */
fp@293:                      size_t data_size
fp@293:                      /**< number of bytes to write */
fp@293:                      )
fp@293: {
fp@293:     if (unlikely(node_address == 0x0000))
fp@293:         EC_WARN("Using node address 0x0000!\n");
fp@293: 
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_NPWR;
fp@293:     datagram->address.physical.slave = node_address;
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT APRD datagram.
fp@293:    Autoincrement physical read.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_aprd(ec_datagram_t *datagram,
fp@293:                      /**< EtherCAT datagram */
fp@293:                      uint16_t ring_position,
fp@293:                      /**< auto-increment position */
fp@293:                      uint16_t offset,
fp@293:                      /**< physical memory address */
fp@293:                      size_t data_size
fp@293:                      /**< number of bytes to read */
fp@293:                      )
fp@293: {
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_APRD;
fp@293:     datagram->address.physical.slave = (int16_t) ring_position * (-1);
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT APWR datagram.
fp@293:    Autoincrement physical write.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_apwr(ec_datagram_t *datagram,
fp@293:                      /**< EtherCAT datagram */
fp@293:                      uint16_t ring_position,
fp@293:                      /**< auto-increment position */
fp@293:                      uint16_t offset,
fp@293:                      /**< physical memory address */
fp@293:                      size_t data_size
fp@293:                      /**< number of bytes to write */
fp@293:                      )
fp@293: {
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_APWR;
fp@293:     datagram->address.physical.slave = (int16_t) ring_position * (-1);
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT BRD datagram.
fp@293:    Broadcast read.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_brd(ec_datagram_t *datagram,
fp@293:                     /**< EtherCAT datagram */
fp@195:                     uint16_t offset,
fp@195:                     /**< physical memory address */
fp@195:                     size_t data_size
fp@195:                     /**< number of bytes to read */
fp@144:                     )
fp@98: {
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_BRD;
fp@293:     datagram->address.physical.slave = 0x0000;
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT BWR datagram.
fp@293:    Broadcast write.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_bwr(ec_datagram_t *datagram,
fp@293:                     /**< EtherCAT datagram */
fp@195:                     uint16_t offset,
fp@195:                     /**< physical memory address */
fp@195:                     size_t data_size
fp@195:                     /**< number of bytes to write */
fp@144:                     )
fp@98: {
fp@293:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_BWR;
fp@293:     datagram->address.physical.slave = 0x0000;
fp@293:     datagram->address.physical.mem = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/
fp@293: 
fp@293: /**
fp@293:    Initializes an EtherCAT LRW datagram.
fp@293:    Logical read write.
fp@293:    \return 0 in case of success, else < 0
fp@293: */
fp@293: 
fp@293: int ec_datagram_lrw(ec_datagram_t *datagram,
fp@293:                     /**< EtherCAT datagram */
fp@293:                     uint32_t offset,
fp@293:                     /**< logical address */
fp@195:                     size_t data_size
fp@293:                     /**< number of bytes to read/write */
fp@144:                     )
fp@144: {
fp@144:     EC_FUNC_HEADER;
fp@325:     datagram->type = EC_DATAGRAM_LRW;
fp@293:     datagram->address.logical = offset;
fp@293:     EC_FUNC_FOOTER;
fp@293: }
fp@293: 
fp@293: /*****************************************************************************/