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