fp@98: /****************************************************************************** fp@98: * fp@2099: * $Id$ fp@98: * fp@1326: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@197: * fp@197: * This file is part of the IgH EtherCAT Master. fp@197: * fp@1326: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1326: * modify it under the terms of the GNU General Public License version 2, as fp@1326: * published by the Free Software Foundation. fp@1326: * fp@1326: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1326: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1326: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1326: * Public License for more details. fp@1326: * fp@1326: * You should have received a copy of the GNU General Public License along fp@1326: * 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@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. 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 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@1313: ret = ec_datagram_prealloc(datagram, data_size); \ fp@1313: if (unlikely(ret)) \ fp@1313: return ret; \ 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@144: return 0; fp@144: fp@199: /** \endcond */ fp@199: fp@144: /*****************************************************************************/ fp@144: fp@816: /** Array of datagram type strings used in ec_datagram_type_string(). fp@816: * fp@816: * \attention This is indexed by ec_datagram_type_t. fp@816: */ fp@816: static const char *type_strings[] = { fp@816: "?", fp@816: "APRD", fp@816: "APWR", fp@816: "APRW", fp@816: "FPRD", fp@816: "FPWR", fp@816: "FPRW", fp@816: "BRD", fp@816: "BWR", fp@816: "BRW", fp@816: "LRD", fp@816: "LWR", fp@816: "LRW", fp@816: "ARMW", fp@816: "FRMW" fp@816: }; fp@2421: fp@816: /*****************************************************************************/ fp@816: fp@809: /** Constructor. fp@809: */ fp@815: void ec_datagram_init(ec_datagram_t *datagram /**< EtherCAT datagram. */) fp@293: { fp@446: INIT_LIST_HEAD(&datagram->queue); // mark as unqueued fp@2268: datagram->device_index = EC_DEVICE_MAIN; fp@325: datagram->type = EC_DATAGRAM_NONE; fp@708: memset(datagram->address, 0x00, EC_ADDR_LEN); fp@293: datagram->data = NULL; fp@809: datagram->data_origin = EC_ORIG_INTERNAL; fp@293: datagram->mem_size = 0; fp@293: datagram->data_size = 0; fp@293: datagram->index = 0x00; fp@809: datagram->working_counter = 0x0000; fp@325: datagram->state = EC_DATAGRAM_INIT; fp@1040: #ifdef EC_HAVE_CYCLES fp@344: datagram->cycles_sent = 0; fp@1040: #endif fp@398: datagram->jiffies_sent = 0; fp@1040: #ifdef EC_HAVE_CYCLES fp@398: datagram->cycles_received = 0; fp@1040: #endif fp@398: datagram->jiffies_received = 0; fp@719: datagram->skip_count = 0; fp@719: datagram->stats_output_jiffies = 0; fp@809: memset(datagram->name, 0x00, EC_DATAGRAM_NAME_SIZE); fp@809: } fp@809: fp@809: /*****************************************************************************/ fp@809: fp@809: /** Destructor. fp@809: */ fp@815: void ec_datagram_clear(ec_datagram_t *datagram /**< EtherCAT datagram. */) fp@293: { fp@1553: ec_datagram_unqueue(datagram); fp@1553: fp@1333: if (datagram->data_origin == EC_ORIG_INTERNAL && datagram->data) { fp@809: kfree(datagram->data); fp@1507: datagram->data = NULL; fp@1333: } fp@809: } fp@809: fp@809: /*****************************************************************************/ fp@809: fp@1553: /** Unqueue datagram. fp@1553: */ fp@1553: void ec_datagram_unqueue(ec_datagram_t *datagram /**< EtherCAT datagram. */) fp@1553: { fp@1553: if (!list_empty(&datagram->queue)) { fp@1553: list_del_init(&datagram->queue); fp@1553: } fp@1553: } fp@1553: fp@1553: /*****************************************************************************/ fp@1553: fp@809: /** Allocates internal payload memory. fp@809: * fp@809: * If the allocated memory is already larger than requested, nothing ist done. fp@809: * fp@809: * \attention If external payload memory has been provided, no range checking fp@809: * is done! fp@809: * fp@1312: * \return 0 in case of success, otherwise \a -ENOMEM. fp@809: */ fp@815: int ec_datagram_prealloc( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: size_t size /**< New payload size in bytes. */ fp@809: ) fp@809: { fp@809: if (datagram->data_origin == EC_ORIG_EXTERNAL fp@809: || size <= datagram->mem_size) fp@809: 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@998: if (!(datagram->data = kmalloc(size, GFP_KERNEL))) { fp@1543: EC_ERR("Failed to allocate %zu bytes of datagram memory!\n", size); fp@1312: return -ENOMEM; fp@144: } fp@144: fp@293: datagram->mem_size = size; fp@144: return 0; fp@144: } fp@98: fp@98: /*****************************************************************************/ fp@98: fp@1225: /** Fills the datagram payload memory with zeros. fp@1225: */ fp@1225: void ec_datagram_zero(ec_datagram_t *datagram /**< EtherCAT datagram. */) fp@1225: { fp@1225: memset(datagram->data, 0x00, datagram->data_size); fp@1225: } fp@1225: fp@1225: /*****************************************************************************/ fp@1225: fp@809: /** Initializes an EtherCAT APRD datagram. fp@809: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_aprd( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t ring_position, /**< Auto-increment address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to read. */ fp@815: ) fp@293: { fp@1313: int ret; fp@293: EC_FUNC_HEADER; fp@325: datagram->type = EC_DATAGRAM_APRD; fp@708: EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1)); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@293: EC_FUNC_FOOTER; fp@293: } fp@293: fp@293: /*****************************************************************************/ fp@293: fp@809: /** Initializes an EtherCAT APWR datagram. fp@809: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_apwr( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t ring_position, /**< Auto-increment address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@293: { fp@1313: int ret; fp@293: EC_FUNC_HEADER; fp@325: datagram->type = EC_DATAGRAM_APWR; fp@708: EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1)); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT APRW datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_aprw( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t ring_position, /**< Auto-increment address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@815: { fp@1313: int ret; fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_APRW; fp@815: EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1)); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT ARMW datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_armw( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t ring_position, /**< Auto-increment address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to read. */ fp@815: ) fp@815: { fp@1313: int ret; fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_ARMW; fp@815: EC_WRITE_S16(datagram->address, (int16_t) ring_position * (-1)); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT FPRD datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_fprd( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t configured_address, /**< Configured station address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to read. */ fp@815: ) fp@815: { fp@1313: int ret; fp@1313: fp@815: if (unlikely(configured_address == 0x0000)) fp@815: EC_WARN("Using configured station address 0x0000!\n"); fp@815: fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_FPRD; fp@815: EC_WRITE_U16(datagram->address, configured_address); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT FPWR datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_fpwr( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t configured_address, /**< Configured station address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@815: { fp@1313: int ret; fp@1313: fp@815: if (unlikely(configured_address == 0x0000)) fp@815: EC_WARN("Using configured station address 0x0000!\n"); fp@815: fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_FPWR; fp@815: EC_WRITE_U16(datagram->address, configured_address); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT FPRW datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_fprw( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t configured_address, /**< Configured station address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@815: { fp@1313: int ret; fp@1313: fp@815: if (unlikely(configured_address == 0x0000)) fp@815: EC_WARN("Using configured station address 0x0000!\n"); fp@815: fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_FPRW; fp@815: EC_WRITE_U16(datagram->address, configured_address); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT FRMW datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_frmw( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t configured_address, /**< Configured station address. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@815: { fp@1313: int ret; fp@1313: fp@815: if (unlikely(configured_address == 0x0000)) fp@815: EC_WARN("Using configured station address 0x0000!\n"); fp@815: fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_FRMW; fp@815: EC_WRITE_U16(datagram->address, configured_address); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@293: EC_FUNC_FOOTER; fp@293: } fp@293: fp@293: /*****************************************************************************/ fp@293: fp@809: /** Initializes an EtherCAT BRD datagram. fp@809: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_brd( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to read. */ fp@815: ) fp@98: { fp@1313: int ret; fp@293: EC_FUNC_HEADER; fp@325: datagram->type = EC_DATAGRAM_BRD; fp@708: EC_WRITE_U16(datagram->address, 0x0000); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@293: EC_FUNC_FOOTER; fp@293: } fp@293: fp@293: /*****************************************************************************/ fp@293: fp@809: /** Initializes an EtherCAT BWR datagram. fp@809: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_bwr( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@98: { fp@1313: int ret; fp@293: EC_FUNC_HEADER; fp@325: datagram->type = EC_DATAGRAM_BWR; fp@708: EC_WRITE_U16(datagram->address, 0x0000); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT BRW datagram. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@815: int ec_datagram_brw( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint16_t mem_address, /**< Physical memory address. */ fp@815: size_t data_size /**< Number of bytes to write. */ fp@815: ) fp@815: { fp@1313: int ret; fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_BRW; fp@815: EC_WRITE_U16(datagram->address, 0x0000); fp@815: EC_WRITE_U16(datagram->address + 2, mem_address); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@815: /** Initializes an EtherCAT LRD datagram. fp@809: * fp@2269: * \return Return value of ec_datagram_prealloc(). fp@2269: */ fp@2269: int ec_datagram_lrd( fp@2269: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@2269: uint32_t offset, /**< Logical address. */ fp@2269: size_t data_size /**< Number of bytes to read/write. */ fp@2269: ) fp@2269: { fp@2269: int ret; fp@2269: EC_FUNC_HEADER; fp@2269: datagram->type = EC_DATAGRAM_LRD; fp@2269: EC_WRITE_U32(datagram->address, offset); fp@2269: EC_FUNC_FOOTER; fp@2269: } fp@2269: fp@2269: /*****************************************************************************/ fp@2269: fp@2269: /** Initializes an EtherCAT LWR datagram. fp@2269: * fp@2269: * \return Return value of ec_datagram_prealloc(). fp@2269: */ fp@2269: int ec_datagram_lwr( fp@2269: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@2269: uint32_t offset, /**< Logical address. */ fp@2269: size_t data_size /**< Number of bytes to read/write. */ fp@2269: ) fp@2269: { fp@2269: int ret; fp@2269: EC_FUNC_HEADER; fp@2269: datagram->type = EC_DATAGRAM_LWR; fp@2269: EC_WRITE_U32(datagram->address, offset); fp@2269: EC_FUNC_FOOTER; fp@2269: } fp@2269: fp@2269: /*****************************************************************************/ fp@2269: fp@2269: /** Initializes an EtherCAT LRW datagram. fp@2269: * fp@2269: * \return Return value of ec_datagram_prealloc(). fp@2269: */ fp@2269: int ec_datagram_lrw( fp@2269: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@2269: uint32_t offset, /**< Logical address. */ fp@2269: size_t data_size /**< Number of bytes to read/write. */ fp@2269: ) fp@2269: { fp@2269: int ret; fp@2269: EC_FUNC_HEADER; fp@2269: datagram->type = EC_DATAGRAM_LRW; fp@2269: EC_WRITE_U32(datagram->address, offset); fp@2269: EC_FUNC_FOOTER; fp@2269: } fp@2269: fp@2269: /*****************************************************************************/ fp@2269: fp@2269: /** Initializes an EtherCAT LRD datagram with external memory. fp@2269: * fp@809: * \attention It is assumed, that the external memory is at least \a data_size fp@809: * bytes large. fp@809: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@809: */ fp@2269: int ec_datagram_lrd_ext( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint32_t offset, /**< Logical address. */ fp@815: size_t data_size, /**< Number of bytes to read/write. */ fp@815: uint8_t *external_memory /**< Pointer to the memory to use. */ fp@815: ) fp@815: { fp@1313: int ret; fp@815: datagram->data = external_memory; fp@815: datagram->data_origin = EC_ORIG_EXTERNAL; fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_LRD; fp@815: EC_WRITE_U32(datagram->address, offset); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@2269: /** Initializes an EtherCAT LWR datagram with external memory. fp@815: * fp@815: * \attention It is assumed, that the external memory is at least \a data_size fp@815: * bytes large. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@2269: int ec_datagram_lwr_ext( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@815: uint32_t offset, /**< Logical address. */ fp@815: size_t data_size, /**< Number of bytes to read/write. */ fp@815: uint8_t *external_memory /**< Pointer to the memory to use. */ fp@815: ) fp@815: { fp@1313: int ret; fp@815: datagram->data = external_memory; fp@815: datagram->data_origin = EC_ORIG_EXTERNAL; fp@815: EC_FUNC_HEADER; fp@815: datagram->type = EC_DATAGRAM_LWR; fp@815: EC_WRITE_U32(datagram->address, offset); fp@815: EC_FUNC_FOOTER; fp@815: } fp@815: fp@815: /*****************************************************************************/ fp@815: fp@2269: /** Initializes an EtherCAT LRW datagram with external memory. fp@815: * fp@815: * \attention It is assumed, that the external memory is at least \a data_size fp@815: * bytes large. fp@815: * fp@1313: * \return Return value of ec_datagram_prealloc(). fp@815: */ fp@2269: int ec_datagram_lrw_ext( fp@815: ec_datagram_t *datagram, /**< EtherCAT datagram. */ fp@809: uint32_t offset, /**< Logical address. */ fp@809: size_t data_size, /**< Number of bytes to read/write. */ fp@809: uint8_t *external_memory /**< Pointer to the memory to use. */ fp@809: ) fp@809: { fp@1313: int ret; fp@809: datagram->data = external_memory; fp@809: datagram->data_origin = EC_ORIG_EXTERNAL; fp@144: EC_FUNC_HEADER; fp@325: datagram->type = EC_DATAGRAM_LRW; fp@708: EC_WRITE_U32(datagram->address, offset); fp@708: EC_FUNC_FOOTER; fp@708: } fp@708: fp@708: /*****************************************************************************/ fp@713: fp@1822: /** Prints the state of a datagram. fp@1822: * fp@1822: * Outputs a text message. fp@1822: */ fp@1822: void ec_datagram_print_state( fp@1822: const ec_datagram_t *datagram /**< EtherCAT datagram */ fp@1822: ) fp@1822: { fp@1822: printk("Datagram "); fp@1822: switch (datagram->state) { fp@1822: case EC_DATAGRAM_INIT: fp@1822: printk("initialized"); fp@1822: break; fp@1822: case EC_DATAGRAM_QUEUED: fp@1822: printk("queued"); fp@1822: break; fp@1822: case EC_DATAGRAM_SENT: fp@1822: printk("sent"); fp@1822: break; fp@1822: case EC_DATAGRAM_RECEIVED: fp@1822: printk("received"); fp@1822: break; fp@1822: case EC_DATAGRAM_TIMED_OUT: fp@1822: printk("timed out"); fp@1822: break; fp@1822: case EC_DATAGRAM_ERROR: fp@1822: printk("error"); fp@1822: break; fp@1822: default: fp@1822: printk("???"); fp@1822: } fp@1822: fp@1822: printk(".\n"); fp@1822: } fp@1822: fp@1822: /*****************************************************************************/ fp@1822: fp@809: /** Evaluates the working counter of a single-cast datagram. fp@809: * fp@713: * Outputs an error message. fp@713: */ fp@713: void ec_datagram_print_wc_error( fp@758: const ec_datagram_t *datagram /**< EtherCAT datagram */ fp@713: ) fp@713: { fp@713: if (datagram->working_counter == 0) fp@713: printk("No response."); fp@713: else if (datagram->working_counter > 1) fp@713: printk("%u slaves responded!", datagram->working_counter); fp@713: else fp@713: printk("Success."); fp@713: printk("\n"); fp@713: } fp@713: fp@713: /*****************************************************************************/ fp@719: fp@809: /** Outputs datagram statistics at most every second. fp@809: */ fp@719: void ec_datagram_output_stats( fp@719: ec_datagram_t *datagram fp@719: ) fp@719: { fp@2081: if (jiffies - datagram->stats_output_jiffies > HZ) { fp@719: datagram->stats_output_jiffies = jiffies; fp@2421: fp@719: if (unlikely(datagram->skip_count)) { fp@1543: EC_WARN("Datagram %p (%s) was SKIPPED %u time%s.\n", fp@1543: datagram, datagram->name, fp@719: datagram->skip_count, fp@719: datagram->skip_count == 1 ? "" : "s"); fp@719: datagram->skip_count = 0; fp@719: } fp@719: } fp@719: } fp@719: fp@719: /*****************************************************************************/ fp@816: fp@816: /** Returns a string describing the datagram type. fp@2522: * fp@2522: * \return Pointer on a static memory containing the requested string. fp@816: */ fp@816: const char *ec_datagram_type_string( fp@816: const ec_datagram_t *datagram /**< EtherCAT datagram. */ fp@816: ) fp@816: { fp@816: return type_strings[datagram->type]; fp@816: } fp@816: fp@816: /*****************************************************************************/