fp@1255: /******************************************************************************
fp@1266:  *  
fp@1266:  * $Id$
fp@1266:  * 
fp@1266:  * Copyright (C) 2006-2008  Florian Pose, Ingenieurgemeinschaft IgH
fp@1266:  * 
fp@1266:  * This file is part of the IgH EtherCAT master userspace library.
fp@1266:  * 
fp@1287:  * The IgH EtherCAT master userspace library is free software; you can
fp@1266:  * redistribute it and/or modify it under the terms of the GNU Lesser General
fp@1287:  * Public License as published by the Free Software Foundation; version 2.1 of
fp@1266:  * the License.
fp@1287:  *
fp@1266:  * The IgH EtherCAT master userspace library is distributed in the hope that
fp@1266:  * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
fp@1266:  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
fp@1266:  * GNU Lesser General Public License for more details.
fp@1287:  *
fp@1266:  * You should have received a copy of the GNU Lesser General Public License
fp@1266:  * along with the IgH EtherCAT master userspace library. If not, see
fp@1266:  * <http://www.gnu.org/licenses/>.
fp@1266:  * 
fp@1266:  * The right to use EtherCAT Technology is granted and comes free of charge
fp@1266:  * under condition of compatibility of product made by Licensee. People
fp@1266:  * intending to distribute/sell products based on the code, have to sign an
fp@1266:  * agreement to guarantee that products using software based on IgH EtherCAT
fp@1266:  * master stay compatible with the actual EtherCAT specification (which are
fp@1266:  * released themselves as an open standard) as the (only) precondition to have
fp@1266:  * the right to use EtherCAT Technology, IP and trade marks.
fp@1255:  *
fp@1255:  *****************************************************************************/
fp@1255: 
fp@1255: #include <stdlib.h>
fp@1255: #include <sys/ioctl.h>
fp@1255: #include <stdio.h>
fp@1255: #include <errno.h>
fp@1255: #include <string.h>
fp@1255: 
fp@1255: #include "slave_config.h"
fp@1255: #include "domain.h"
fp@1264: #include "voe_handler.h"
fp@1255: #include "master.h"
fp@1255: #include "master/ioctl.h"
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_sync_manager(ec_slave_config_t *sc, uint8_t sync_index,
fp@1255:         ec_direction_t dir)
fp@1255: {
fp@1255:     ec_ioctl_config_t data;
fp@1255:     unsigned int i;
fp@1255: 
fp@1255:     if (sync_index >= EC_MAX_SYNC_MANAGERS)
fp@1313:         return -ENOENT;
fp@1255: 
fp@1255:     memset(&data, 0x00, sizeof(ec_ioctl_config_t));
fp@1255:     data.config_index = sc->index;
fp@1255:     data.syncs[sync_index].dir = dir;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to config sync manager: %s\n",
fp@1255:                 strerror(errno));
fp@1313:         return -1; // FIXME
fp@1255:     }
fp@1255:     
fp@1255:     return 0;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_pdo_assign_add(ec_slave_config_t *sc,
fp@1255:         uint8_t sync_index, uint16_t pdo_index)
fp@1255: {
fp@1255:     ec_ioctl_config_pdo_t data;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.sync_index = sync_index;
fp@1255:     data.index = pdo_index;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_PDO, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to add Pdo: %s\n",
fp@1255:                 strerror(errno));
fp@1313:         return -1;  // FIXME
fp@1255:     }
fp@1255:     
fp@1255:     return 0;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: void ecrt_slave_config_pdo_assign_clear(ec_slave_config_t *sc,
fp@1255:         uint8_t sync_index)
fp@1255: {
fp@1255:     ec_ioctl_config_pdo_t data;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.sync_index = sync_index;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_PDOS, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to clear Pdos: %s\n",
fp@1255:                 strerror(errno));
fp@1255:     }
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_pdo_mapping_add(ec_slave_config_t *sc,
fp@1255:         uint16_t pdo_index, uint16_t entry_index, uint8_t entry_subindex,
fp@1255:         uint8_t entry_bit_length)
fp@1255: {
fp@1255:     ec_ioctl_add_pdo_entry_t data;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.pdo_index = pdo_index;
fp@1255:     data.entry_index = entry_index;
fp@1255:     data.entry_subindex = entry_subindex;
fp@1255:     data.entry_bit_length = entry_bit_length;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_ENTRY, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to add Pdo entry: %s\n",
fp@1255:                 strerror(errno));
fp@1313:         return -1;  // FIXME
fp@1255:     }
fp@1255:     
fp@1255:     return 0;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: void ecrt_slave_config_pdo_mapping_clear(ec_slave_config_t *sc,
fp@1255:         uint16_t pdo_index)
fp@1255: {
fp@1255:     ec_ioctl_config_pdo_t data;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.index = pdo_index;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_ENTRIES, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to clear Pdo entries: %s\n",
fp@1255:                 strerror(errno));
fp@1255:     }
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_pdos(ec_slave_config_t *sc,
fp@1255:         unsigned int n_syncs, const ec_sync_info_t syncs[])
fp@1255: {
fp@1313:     int ret;
fp@1255:     unsigned int i, j, k;
fp@1255:     const ec_sync_info_t *sync_info;
fp@1255:     const ec_pdo_info_t *pdo_info;
fp@1255:     const ec_pdo_entry_info_t *entry_info;
fp@1255: 
fp@1255:     if (!syncs)
fp@1255:         return 0;
fp@1255: 
fp@1255:     for (i = 0; i < n_syncs; i++) {
fp@1255:         sync_info = &syncs[i];
fp@1255: 
fp@1255:         if (sync_info->index == (uint8_t) EC_END)
fp@1255:             break;
fp@1255: 
fp@1255:         if (sync_info->index >= EC_MAX_SYNC_MANAGERS) {
fp@1255:             fprintf(stderr, "Invalid sync manager index %u!\n",
fp@1255:                     sync_info->index);
fp@1313:             return -ENOENT;
fp@1255:         }
fp@1255: 
fp@1313:         ret = ecrt_slave_config_sync_manager(
fp@1313:                 sc, sync_info->index, sync_info->dir);
fp@1313:         if (ret)
fp@1313:             return ret;
fp@1255: 
fp@1255:         if (sync_info->n_pdos && sync_info->pdos) {
fp@1255:             ecrt_slave_config_pdo_assign_clear(sc, sync_info->index);
fp@1255: 
fp@1255:             for (j = 0; j < sync_info->n_pdos; j++) {
fp@1255:                 pdo_info = &sync_info->pdos[j];
fp@1255: 
fp@1313:                 ret = ecrt_slave_config_pdo_assign_add(
fp@1313:                         sc, sync_info->index, pdo_info->index);
fp@1313:                 if (ret)
fp@1313:                     return ret;
fp@1255: 
fp@1255:                 if (pdo_info->n_entries && pdo_info->entries) {
fp@1255:                     ecrt_slave_config_pdo_mapping_clear(sc, pdo_info->index);
fp@1255: 
fp@1255:                     for (k = 0; k < pdo_info->n_entries; k++) {
fp@1255:                         entry_info = &pdo_info->entries[k];
fp@1255: 
fp@1313:                         ret = ecrt_slave_config_pdo_mapping_add(sc,
fp@1313:                                 pdo_info->index, entry_info->index,
fp@1313:                                 entry_info->subindex,
fp@1313:                                 entry_info->bit_length);
fp@1313:                         if (ret)
fp@1313:                             return ret;
fp@1255:                     }
fp@1255:                 }
fp@1255:             }
fp@1255:         }
fp@1255:     }
fp@1255: 
fp@1255:     return 0;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_reg_pdo_entry(
fp@1255:         ec_slave_config_t *sc,
fp@1255:         uint16_t index,
fp@1255:         uint8_t subindex,
fp@1255:         ec_domain_t *domain,
fp@1255:         unsigned int *bit_position
fp@1255:         )
fp@1255: {
fp@1255:     ec_ioctl_reg_pdo_entry_t data;
fp@1255:     int ret;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.entry_index = index;
fp@1255:     data.entry_subindex = subindex;
fp@1255:     data.domain_index = domain->index;
fp@1255: 
fp@1255:     ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_ENTRY, &data);
fp@1255:     if (ret == -1) {
fp@1255:         fprintf(stderr, "Failed to register Pdo entry: %s\n",
fp@1255:                 strerror(errno));
fp@1313:         return -2; // FIXME
fp@1255:     }
fp@1255: 
fp@1255:     if (bit_position) {
fp@1255:         *bit_position = data.bit_position;
fp@1255:     } else {
fp@1255:         if (data.bit_position) {
fp@1255:             fprintf(stderr, "Pdo entry 0x%04X:%02X does not byte-align "
fp@1255:                     "in config %u:%u.\n", index, subindex,
fp@1255:                     sc->alias, sc->position);
fp@1313:             return -3; // FIXME
fp@1255:         }
fp@1255:     }
fp@1255: 
fp@1255:     return ret;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index,
fp@1255:         uint8_t subindex, const uint8_t *sdo_data, size_t size)
fp@1255: {
fp@1255:     ec_ioctl_sc_sdo_t data;
fp@1255: 
fp@1255:     data.config_index = sc->index;
fp@1255:     data.index = index;
fp@1255:     data.subindex = subindex;
fp@1255:     data.data = sdo_data;
fp@1255:     data.size = size;
fp@1255: 
fp@1255:     if (ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_ENTRY, &data) == -1) {
fp@1255:         fprintf(stderr, "Failed to configure Sdo.\n");
fp@1313:         return -1; // FIXME
fp@1255:     }
fp@1255: 
fp@1255:     return 0;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_sdo8(ec_slave_config_t *sc, uint16_t index,
fp@1255:         uint8_t subindex, uint8_t value)
fp@1255: {
fp@1255:     uint8_t data[1];
fp@1255: 
fp@1255:     EC_WRITE_U8(data, value);
fp@1255:     return ecrt_slave_config_sdo(sc, index, subindex, data, 1);
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_sdo16(ec_slave_config_t *sc, uint16_t index,
fp@1255:         uint8_t subindex, uint16_t value)
fp@1255: {
fp@1255:     uint8_t data[2];
fp@1255: 
fp@1255:     EC_WRITE_U16(data, value);
fp@1255:     return ecrt_slave_config_sdo(sc, index, subindex, data, 2);
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: int ecrt_slave_config_sdo32(ec_slave_config_t *sc, uint16_t index,
fp@1255:         uint8_t subindex, uint32_t value)
fp@1255: {
fp@1255:     uint8_t data[4];
fp@1255: 
fp@1255:     EC_WRITE_U32(data, value);
fp@1255:     return ecrt_slave_config_sdo(sc, index, subindex, data, 4);
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
fp@1255:         uint16_t index, uint8_t subindex, size_t size)
fp@1255: {
fp@1259:     return 0; // TODO
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
fp@1255:         size_t size)
fp@1255: {
fp@1264:     ec_ioctl_voe_t data;
fp@1264:     ec_voe_handler_t *voe;
fp@1264:     unsigned int index;
fp@1264: 
fp@1264:     voe = malloc(sizeof(ec_voe_handler_t));
fp@1264:     if (!voe) {
fp@1264:         fprintf(stderr, "Failed to allocate memory.\n");
fp@1264:         return 0;
fp@1264:     }
fp@1264: 
fp@1264:     if (size) {
fp@1264:         voe->data = malloc(size);
fp@1264:         if (!voe->data) {
fp@1264:             fprintf(stderr, "Failed to allocate %u bytes of VoE data"
fp@1264:                     " memory.\n", size);
fp@1264:             free(voe);
fp@1264:             return 0;
fp@1264:         }
fp@1264:     } else {
fp@1264:         voe->data = NULL;
fp@1264:     }
fp@1264: 
fp@1264:     data.config_index = sc->index;
fp@1264:     data.size = size;
fp@1264:     
fp@1264:     if (ioctl(sc->master->fd, EC_IOCTL_SC_VOE, &data) == -1) {
fp@1264:         fprintf(stderr, "Failed to create VoE handler: %s\n",
fp@1264:                 strerror(errno));
fp@1264:         if (voe->data)
fp@1264:             free(voe->data);
fp@1264:         free(voe);
fp@1264:         return NULL; 
fp@1264:     }
fp@1264: 
fp@1264:     voe->config = sc;
fp@1264:     voe->index = data.voe_index;
fp@1264:     voe->data_size = size;
fp@1264:     voe->mem_size = size;
fp@1264:     return voe;
fp@1255: }
fp@1255: 
fp@1255: /*****************************************************************************/
fp@1255: 
fp@1255: void ecrt_slave_config_state(const ec_slave_config_t *sc,
fp@1255:         ec_slave_config_state_t *state)
fp@1255: {
fp@1259:     ec_ioctl_sc_state_t data;
fp@1259: 
fp@1259:     data.config_index = sc->index;
fp@1259:     data.state = state;
fp@1259:     
fp@1259:     if (ioctl(sc->master->fd, EC_IOCTL_SC_STATE, &data) == -1) {
fp@1259:         fprintf(stderr, "Failed to get slave configuration state: %s\n",
fp@1259:                 strerror(errno));
fp@1259:     }
fp@1259: }
fp@1259: 
fp@1259: /*****************************************************************************/