lib/slave_config.c
changeset 2589 2b9c78543663
parent 2025 2d7e29d82e9a
child 2609 777d1a8b3a27
child 2634 f859d567f94e
--- a/lib/slave_config.c	Thu Sep 06 14:21:02 2012 +0200
+++ b/lib/slave_config.c	Mon Nov 03 15:20:05 2014 +0100
@@ -1,11 +1,11 @@
 /******************************************************************************
- *  
+ *
  *  $Id$
- *  
- *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
- *  
+ *
+ *  Copyright (C) 2006-2012  Florian Pose, Ingenieurgemeinschaft IgH
+ *
  *  This file is part of the IgH EtherCAT master userspace library.
- *  
+ *
  *  The IgH EtherCAT master userspace library is free software; you can
  *  redistribute it and/or modify it under the terms of the GNU Lesser General
  *  Public License as published by the Free Software Foundation; version 2.1
@@ -19,9 +19,9 @@
  *  You should have received a copy of the GNU Lesser General Public License
  *  along with the IgH EtherCAT master userspace library. If not, see
  *  <http://www.gnu.org/licenses/>.
- *  
+ *
  *  ---
- *  
+ *
  *  The license mentioned above concerns the source code only. Using the
  *  EtherCAT technology and brand is only permitted in compliance with the
  *  industrial property and similar rights of Beckhoff Automation GmbH.
@@ -29,23 +29,24 @@
  *****************************************************************************/
 
 #include <stdlib.h>
-#include <sys/ioctl.h>
 #include <stdio.h>
-#include <errno.h>
 #include <string.h>
-
+#include <errno.h> /* ENOENT */
+
+#include "ioctl.h"
 #include "slave_config.h"
 #include "domain.h"
 #include "sdo_request.h"
+#include "reg_request.h"
 #include "voe_handler.h"
 #include "master.h"
-#include "master/ioctl.h"
 
 /*****************************************************************************/
 
 void ec_slave_config_clear(ec_slave_config_t *sc)
 {
     ec_sdo_request_t *r, *next_r;
+    ec_reg_request_t *e, *next_e;
     ec_voe_handler_t *v, *next_v;
 
     r = sc->first_sdo_request;
@@ -55,6 +56,12 @@
         r = next_r;
     }
 
+    e = sc->first_reg_request;
+    while (e) {
+        next_e = e->next;
+        ec_reg_request_clear(e);
+        e = next_e;
+    }
 
     v = sc->first_voe_handler;
     while (v) {
@@ -70,7 +77,7 @@
         ec_direction_t dir, ec_watchdog_mode_t watchdog_mode)
 {
     ec_ioctl_config_t data;
-    unsigned int i;
+    int ret;
 
     if (sync_index >= EC_MAX_SYNC_MANAGERS)
         return -ENOENT;
@@ -81,12 +88,13 @@
     data.syncs[sync_index].watchdog_mode = watchdog_mode;
     data.syncs[sync_index].config_this = 1;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_SYNC, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to config sync manager: %s\n",
-                strerror(errno));
-        return -1; // FIXME
-    }
-    
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
     return 0;
 }
 
@@ -96,32 +104,17 @@
         uint16_t divider, uint16_t intervals)
 {
     ec_ioctl_config_t data;
+    int ret;
 
     memset(&data, 0x00, sizeof(ec_ioctl_config_t));
     data.config_index = sc->index;
     data.watchdog_divider = divider;
     data.watchdog_intervals = intervals;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_WATCHDOG, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_WATCHDOG, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to config watchdog: %s\n",
-                strerror(errno));
-    }
-}
-
-/*****************************************************************************/
-
-void ecrt_slave_config_overlapping_pdos(ec_slave_config_t *sc,
-        uint8_t allow_overlapping_pdos)
-{
-    ec_ioctl_config_t data;
-
-    memset(&data, 0x00, sizeof(ec_ioctl_config_t));
-    data.config_index = sc->index;
-    data.allow_overlapping_pdos = allow_overlapping_pdos;
-
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_OVERLAPPING_IO, &data) == -1) {
-        fprintf(stderr, "Failed to config overlapping PDOs: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
     }
 }
 
@@ -131,17 +124,19 @@
         uint8_t sync_index, uint16_t pdo_index)
 {
     ec_ioctl_config_pdo_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.sync_index = sync_index;
     data.index = pdo_index;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_PDO, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_ADD_PDO, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to add PDO: %s\n",
-                strerror(errno));
-        return -1;  // FIXME
-    }
-    
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
     return 0;
 }
 
@@ -151,13 +146,15 @@
         uint8_t sync_index)
 {
     ec_ioctl_config_pdo_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.sync_index = sync_index;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_PDOS, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_PDOS, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to clear PDOs: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
     }
 }
 
@@ -168,6 +165,7 @@
         uint8_t entry_bit_length)
 {
     ec_ioctl_add_pdo_entry_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.pdo_index = pdo_index;
@@ -175,12 +173,13 @@
     data.entry_subindex = entry_subindex;
     data.entry_bit_length = entry_bit_length;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_ADD_ENTRY, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_ADD_ENTRY, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to add PDO entry: %s\n",
-                strerror(errno));
-        return -1;  // FIXME
-    }
-    
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
     return 0;
 }
 
@@ -190,13 +189,15 @@
         uint16_t pdo_index)
 {
     ec_ioctl_config_pdo_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.index = pdo_index;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_ENTRIES, &data) == -1) {
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_CLEAR_ENTRIES, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to clear PDO entries: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
     }
 }
 
@@ -282,10 +283,10 @@
     data.domain_index = domain->index;
 
     ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_ENTRY, &data);
-    if (ret == -1) {
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to register PDO entry: %s\n",
-                strerror(errno));
-        return -2; // FIXME
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
     }
 
     if (bit_position) {
@@ -295,7 +296,7 @@
             fprintf(stderr, "PDO entry 0x%04X:%02X does not byte-align "
                     "in config %u:%u.\n", index, subindex,
                     sc->alias, sc->position);
-            return -3; // FIXME
+            return -EFAULT;
         }
     }
 
@@ -304,11 +305,53 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_reg_pdo_entry_pos(
+        ec_slave_config_t *sc,
+        uint8_t sync_index,
+        unsigned int pdo_pos,
+        unsigned int entry_pos,
+        ec_domain_t *domain,
+        unsigned int *bit_position
+        )
+{
+    ec_ioctl_reg_pdo_pos_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.sync_index = sync_index;
+    io.pdo_pos = pdo_pos;
+    io.entry_pos = entry_pos;
+    io.domain_index = domain->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_PDO_POS, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to register PDO entry: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    if (bit_position) {
+        *bit_position = io.bit_position;
+    } else {
+        if (io.bit_position) {
+            fprintf(stderr, "PDO entry %u/%u/%u does not byte-align "
+                    "in config %u:%u.\n", sync_index, pdo_pos, entry_pos,
+                    sc->alias, sc->position);
+            return -EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/*****************************************************************************/
+
 void ecrt_slave_config_dc(ec_slave_config_t *sc, uint16_t assign_activate,
-        uint32_t sync0_cycle_time, uint32_t sync0_shift_time,
-        uint32_t sync1_cycle_time, uint32_t sync1_shift_time)
+        uint32_t sync0_cycle_time, int32_t sync0_shift_time,
+        uint32_t sync1_cycle_time, int32_t sync1_shift_time)
 {
     ec_ioctl_config_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.dc_assign_activate = assign_activate;
@@ -317,8 +360,10 @@
     data.dc_sync[1].cycle_time = sync1_cycle_time;
     data.dc_sync[1].shift_time = sync1_shift_time;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_DC, &data) == -1) {
-        fprintf(stderr, "Failed to set assign_activate word.\n");
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_DC, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to set DC parameters: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
     }
 }
 
@@ -328,6 +373,7 @@
         uint8_t subindex, const uint8_t *sdo_data, size_t size)
 {
     ec_ioctl_sc_sdo_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.index = index;
@@ -336,9 +382,11 @@
     data.size = size;
     data.complete_access = 0;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
-        fprintf(stderr, "Failed to configure SDO.\n");
-        return -1; // FIXME
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to configure SDO: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
     }
 
     return 0;
@@ -350,6 +398,7 @@
         const uint8_t *sdo_data, size_t size)
 {
     ec_ioctl_sc_sdo_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.index = index;
@@ -358,9 +407,11 @@
     data.size = size;
     data.complete_access = 1;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) {
-        fprintf(stderr, "Failed to configure SDO.\n");
-        return -1; // FIXME
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to configure SDO: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
     }
 
     return 0;
@@ -401,6 +452,86 @@
 
 /*****************************************************************************/
 
+int ecrt_slave_config_emerg_size(ec_slave_config_t *sc, size_t elements)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.size = elements;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_SIZE, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to set emergency ring size: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_pop(ec_slave_config_t *sc, uint8_t *target)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+    io.target = target;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_POP, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        if (EC_IOCTL_ERRNO(ret) != ENOENT) {
+            fprintf(stderr, "Failed to get emergency message: %s\n",
+                    strerror(EC_IOCTL_ERRNO(ret)));
+        }
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_clear(ec_slave_config_t *sc)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_CLEAR, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to clear emergency ring: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+int ecrt_slave_config_emerg_overruns(ec_slave_config_t *sc)
+{
+    ec_ioctl_sc_emerg_t io;
+    int ret;
+
+    io.config_index = sc->index;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_EMERG_OVERRUNS, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to get emergency overruns: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return io.overruns;
+}
+
+/*****************************************************************************/
+
 void ec_slave_config_add_sdo_request(ec_slave_config_t *sc,
         ec_sdo_request_t *req)
 {
@@ -422,6 +553,7 @@
 {
     ec_ioctl_sdo_request_t data;
     ec_sdo_request_t *req;
+    int ret;
 
     req = malloc(sizeof(ec_sdo_request_t));
     if (!req) {
@@ -445,13 +577,14 @@
     data.sdo_index = index;
     data.sdo_subindex = subindex;
     data.size = size;
-    
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO_REQUEST, &data) == -1) {
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_SDO_REQUEST, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to create SDO request: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
         ec_sdo_request_clear(req);
         free(req);
-        return NULL; 
+        return NULL;
     }
 
     req->next = NULL;
@@ -469,6 +602,71 @@
 
 /*****************************************************************************/
 
+void ec_slave_config_add_reg_request(ec_slave_config_t *sc,
+        ec_reg_request_t *reg)
+{
+    if (sc->first_reg_request) {
+        ec_reg_request_t *r = sc->first_reg_request;
+        while (r->next) {
+            r = r->next;
+        }
+        r->next = reg;
+    } else {
+        sc->first_reg_request = reg;
+    }
+}
+
+/*****************************************************************************/
+
+ec_reg_request_t *ecrt_slave_config_create_reg_request(ec_slave_config_t *sc,
+        size_t size)
+{
+    ec_ioctl_reg_request_t io;
+    ec_reg_request_t *reg;
+    int ret;
+
+    reg = malloc(sizeof(ec_reg_request_t));
+    if (!reg) {
+        fprintf(stderr, "Failed to allocate memory.\n");
+        return NULL;
+    }
+
+    if (size) {
+        reg->data = malloc(size);
+        if (!reg->data) {
+            fprintf(stderr, "Failed to allocate %zu bytes of register data"
+                    " memory.\n", size);
+            free(reg);
+            return 0;
+        }
+    } else {
+        reg->data = NULL;
+    }
+
+    io.config_index = sc->index;
+    io.mem_size = size;
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_REG_REQUEST, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to create register request: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        ec_reg_request_clear(reg);
+        free(reg);
+        return NULL;
+    }
+
+    reg->next = NULL;
+    reg->config = sc;
+    reg->index = io.request_index;
+    reg->mem_size = size;
+
+    ec_slave_config_add_reg_request(sc, reg);
+
+    return reg;
+}
+
+/*****************************************************************************/
+
 void ec_slave_config_add_voe_handler(ec_slave_config_t *sc,
         ec_voe_handler_t *voe)
 {
@@ -490,7 +688,7 @@
 {
     ec_ioctl_voe_t data;
     ec_voe_handler_t *voe;
-    unsigned int index;
+    int ret;
 
     voe = malloc(sizeof(ec_voe_handler_t));
     if (!voe) {
@@ -512,13 +710,14 @@
 
     data.config_index = sc->index;
     data.size = size;
-    
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_VOE, &data) == -1) {
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_VOE, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to create VoE handler: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
         ec_voe_handler_clear(voe);
         free(voe);
-        return NULL; 
+        return NULL;
     }
 
     voe->next = NULL;
@@ -538,13 +737,15 @@
         ec_slave_config_state_t *state)
 {
     ec_ioctl_sc_state_t data;
+    int ret;
 
     data.config_index = sc->index;
     data.state = state;
-    
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_STATE, &data) == -1) {
+
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_STATE, &data);
+    if (EC_IOCTL_IS_ERROR(ret)) {
         fprintf(stderr, "Failed to get slave configuration state: %s\n",
-                strerror(errno));
+                strerror(EC_IOCTL_ERRNO(ret)));
     }
 }
 
@@ -554,6 +755,7 @@
         uint16_t idn, ec_al_state_t al_state, const uint8_t *data, size_t size)
 {
     ec_ioctl_sc_idn_t io;
+    int ret;
 
     io.config_index = sc->index;
     io.drive_no = drive_no;
@@ -562,12 +764,14 @@
     io.data = data;
     io.size = size;
 
-    if (ioctl(sc->master->fd, EC_IOCTL_SC_IDN, &io) == -1) {
-        fprintf(stderr, "Failed to configure IDN.\n");
-        return -1; // FIXME
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
+    ret = ioctl(sc->master->fd, EC_IOCTL_SC_IDN, &io);
+    if (EC_IOCTL_IS_ERROR(ret)) {
+        fprintf(stderr, "Failed to configure IDN: %s\n",
+                strerror(EC_IOCTL_ERRNO(ret)));
+        return -EC_IOCTL_ERRNO(ret);
+    }
+
+    return 0;
+}
+
+/*****************************************************************************/