master/canopen.c
branchstable-1.1
changeset 1732 1cc865ba17c2
child 1744 7bc131b92039
equal deleted inserted replaced
1731:60b2aad9d40b 1732:1cc865ba17c2
       
     1 /******************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2006  Florian Pose, Ingenieurgemeinschaft IgH
       
     6  *
       
     7  *  This file is part of the IgH EtherCAT Master.
       
     8  *
       
     9  *  The IgH EtherCAT Master is free software; you can redistribute it
       
    10  *  and/or modify it under the terms of the GNU General Public License
       
    11  *  as published by the Free Software Foundation; either version 2 of the
       
    12  *  License, or (at your option) any later version.
       
    13  *
       
    14  *  The IgH EtherCAT Master is distributed in the hope that it will be
       
    15  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    17  *  GNU General Public License for more details.
       
    18  *
       
    19  *  You should have received a copy of the GNU General Public License
       
    20  *  along with the IgH EtherCAT Master; if not, write to the Free Software
       
    21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    22  *
       
    23  *  The right to use EtherCAT Technology is granted and comes free of
       
    24  *  charge under condition of compatibility of product made by
       
    25  *  Licensee. People intending to distribute/sell products based on the
       
    26  *  code, have to sign an agreement to guarantee that products using
       
    27  *  software based on IgH EtherCAT master stay compatible with the actual
       
    28  *  EtherCAT specification (which are released themselves as an open
       
    29  *  standard) as the (only) precondition to have the right to use EtherCAT
       
    30  *  Technology, IP and trade marks.
       
    31  *
       
    32  *****************************************************************************/
       
    33 
       
    34 /**
       
    35    \file
       
    36    Canopen-over-EtherCAT functions.
       
    37 */
       
    38 
       
    39 /*****************************************************************************/
       
    40 
       
    41 #include <linux/module.h>
       
    42 
       
    43 #include "canopen.h"
       
    44 #include "master.h"
       
    45 
       
    46 /*****************************************************************************/
       
    47 
       
    48 ssize_t ec_show_sdo_attribute(struct kobject *, struct attribute *, char *);
       
    49 ssize_t ec_show_sdo_entry_attribute(struct kobject *, struct attribute *,
       
    50                                     char *);
       
    51 void ec_sdo_clear(struct kobject *);
       
    52 void ec_sdo_entry_clear(struct kobject *);
       
    53 
       
    54 void ec_sdo_request_init_read(ec_sdo_request_t *, ec_sdo_t *,
       
    55                               ec_sdo_entry_t *);
       
    56 void ec_sdo_request_clear(ec_sdo_request_t *);
       
    57 
       
    58 /*****************************************************************************/
       
    59 
       
    60 /** \cond */
       
    61 
       
    62 EC_SYSFS_READ_ATTR(info);
       
    63 EC_SYSFS_READ_ATTR(value);
       
    64 
       
    65 static struct attribute *sdo_def_attrs[] = {
       
    66     &attr_info,
       
    67     NULL,
       
    68 };
       
    69 
       
    70 static struct sysfs_ops sdo_sysfs_ops = {
       
    71     .show = &ec_show_sdo_attribute,
       
    72     .store = NULL
       
    73 };
       
    74 
       
    75 static struct kobj_type ktype_ec_sdo = {
       
    76     .release = ec_sdo_clear,
       
    77     .sysfs_ops = &sdo_sysfs_ops,
       
    78     .default_attrs = sdo_def_attrs
       
    79 };
       
    80 
       
    81 static struct attribute *sdo_entry_def_attrs[] = {
       
    82     &attr_info,
       
    83     &attr_value,
       
    84     NULL,
       
    85 };
       
    86 
       
    87 static struct sysfs_ops sdo_entry_sysfs_ops = {
       
    88     .show = &ec_show_sdo_entry_attribute,
       
    89     .store = NULL
       
    90 };
       
    91 
       
    92 static struct kobj_type ktype_ec_sdo_entry = {
       
    93     .release = ec_sdo_entry_clear,
       
    94     .sysfs_ops = &sdo_entry_sysfs_ops,
       
    95     .default_attrs = sdo_entry_def_attrs
       
    96 };
       
    97 
       
    98 /** \endcond */
       
    99 
       
   100 /*****************************************************************************/
       
   101 
       
   102 /**
       
   103    SDO constructor.
       
   104 */
       
   105 
       
   106 int ec_sdo_init(ec_sdo_t *sdo, /**< SDO */
       
   107                 uint16_t index, /**< SDO index */
       
   108                 ec_slave_t *slave /**< parent slave */
       
   109                 )
       
   110 {
       
   111     sdo->slave = slave;
       
   112     sdo->index = index;
       
   113     sdo->object_code = 0x00;
       
   114     sdo->name = NULL;
       
   115     sdo->subindices = 0;
       
   116     INIT_LIST_HEAD(&sdo->entries);
       
   117 
       
   118     // init kobject and add it to the hierarchy
       
   119     memset(&sdo->kobj, 0x00, sizeof(struct kobject));
       
   120     kobject_init(&sdo->kobj);
       
   121     sdo->kobj.ktype = &ktype_ec_sdo;
       
   122     sdo->kobj.parent = &slave->sdo_kobj;
       
   123     if (kobject_set_name(&sdo->kobj, "%4X", sdo->index)) {
       
   124         EC_ERR("Failed to set kobj name.\n");
       
   125         kobject_put(&sdo->kobj);
       
   126         return -1;
       
   127     }
       
   128     if (kobject_add(&sdo->kobj)) {
       
   129         EC_ERR("Failed to add SDO kobject.\n");
       
   130         kobject_put(&sdo->kobj);
       
   131         return -1;
       
   132     }
       
   133 
       
   134     return 0;
       
   135 }
       
   136 
       
   137 /*****************************************************************************/
       
   138 
       
   139 /**
       
   140    SDO destructor.
       
   141    Clears and frees an SDO object.
       
   142 */
       
   143 
       
   144 void ec_sdo_destroy(ec_sdo_t *sdo /**< SDO */)
       
   145 {
       
   146     ec_sdo_entry_t *entry, *next;
       
   147 
       
   148     // free all entries
       
   149     list_for_each_entry_safe(entry, next, &sdo->entries, list) {
       
   150         list_del(&entry->list);
       
   151         ec_sdo_entry_destroy(entry);
       
   152     }
       
   153 
       
   154     // destroy self
       
   155     kobject_del(&sdo->kobj);
       
   156     kobject_put(&sdo->kobj);
       
   157 }
       
   158 
       
   159 /*****************************************************************************/
       
   160 
       
   161 /**
       
   162    Clear and free SDO.
       
   163    This method is called by the kobject,
       
   164    once there are no more references to it.
       
   165 */
       
   166 
       
   167 void ec_sdo_clear(struct kobject *kobj /**< SDO's kobject */)
       
   168 {
       
   169     ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj);
       
   170 
       
   171     if (sdo->name) kfree(sdo->name);
       
   172 
       
   173     kfree(sdo);
       
   174 }
       
   175 
       
   176 /*****************************************************************************/
       
   177 
       
   178 ssize_t ec_sdo_info(ec_sdo_t *sdo, /**< SDO */
       
   179                     char *buffer /**< target buffer */
       
   180                     )
       
   181 {
       
   182     off_t off = 0;
       
   183 
       
   184     off += sprintf(buffer + off, "Index: 0x%04X\n", sdo->index);
       
   185     off += sprintf(buffer + off, "Name: %s\n", sdo->name ? sdo->name : "");
       
   186     off += sprintf(buffer + off, "Subindices: %i\n", sdo->subindices);
       
   187 
       
   188     return off;
       
   189 }
       
   190 
       
   191 /*****************************************************************************/
       
   192 
       
   193 ssize_t ec_show_sdo_attribute(struct kobject *kobj, /**< kobject */
       
   194                               struct attribute *attr,
       
   195                               char *buffer
       
   196                               )
       
   197 {
       
   198     ec_sdo_t *sdo = container_of(kobj, ec_sdo_t, kobj);
       
   199 
       
   200     if (attr == &attr_info) {
       
   201         return ec_sdo_info(sdo, buffer);
       
   202     }
       
   203 
       
   204     return 0;
       
   205 }
       
   206 
       
   207 /*****************************************************************************/
       
   208 
       
   209 /**
       
   210    SDO entry constructor.
       
   211 */
       
   212 
       
   213 int ec_sdo_entry_init(ec_sdo_entry_t *entry, /**< SDO entry */
       
   214                       uint8_t subindex, /**< SDO entry subindex */
       
   215                       ec_sdo_t *sdo /**< parent SDO */
       
   216                       )
       
   217 {
       
   218     entry->sdo = sdo;
       
   219     entry->subindex = subindex;
       
   220     entry->data_type = 0x0000;
       
   221     entry->bit_length = 0;
       
   222     entry->description = NULL;
       
   223 
       
   224     // init kobject and add it to the hierarchy
       
   225     memset(&entry->kobj, 0x00, sizeof(struct kobject));
       
   226     kobject_init(&entry->kobj);
       
   227     entry->kobj.ktype = &ktype_ec_sdo_entry;
       
   228     entry->kobj.parent = &sdo->kobj;
       
   229     if (kobject_set_name(&entry->kobj, "%i", entry->subindex)) {
       
   230         EC_ERR("Failed to set kobj name.\n");
       
   231         kobject_put(&entry->kobj);
       
   232         return -1;
       
   233     }
       
   234     if (kobject_add(&entry->kobj)) {
       
   235         EC_ERR("Failed to add entry kobject.\n");
       
   236         kobject_put(&entry->kobj);
       
   237         return -1;
       
   238     }
       
   239 
       
   240     return 0;
       
   241 }
       
   242 
       
   243 /*****************************************************************************/
       
   244 
       
   245 /**
       
   246    SDO entry destructor.
       
   247    Clears and frees an SDO entry object.
       
   248 */
       
   249 
       
   250 void ec_sdo_entry_destroy(ec_sdo_entry_t *entry /**< SDO entry */)
       
   251 {
       
   252     // destroy self
       
   253     kobject_del(&entry->kobj);
       
   254     kobject_put(&entry->kobj);
       
   255 }
       
   256 
       
   257 /*****************************************************************************/
       
   258 
       
   259 /**
       
   260    Clear and free SDO entry.
       
   261    This method is called by the kobject,
       
   262    once there are no more references to it.
       
   263 */
       
   264 
       
   265 void ec_sdo_entry_clear(struct kobject *kobj /**< SDO entry's kobject */)
       
   266 {
       
   267     ec_sdo_entry_t *entry = container_of(kobj, ec_sdo_entry_t, kobj);
       
   268 
       
   269     if (entry->description) kfree(entry->description);
       
   270 
       
   271     kfree(entry);
       
   272 }
       
   273 
       
   274 /*****************************************************************************/
       
   275 
       
   276 ssize_t ec_sdo_entry_info(ec_sdo_entry_t *entry, /**< SDO entry */
       
   277                           char *buffer /**< target buffer */
       
   278                           )
       
   279 {
       
   280     off_t off = 0;
       
   281 
       
   282     off += sprintf(buffer + off, "Subindex: 0x%02X\n", entry->subindex);
       
   283     off += sprintf(buffer + off, "Description: %s\n",
       
   284                    entry->description ? entry->description : "");
       
   285     off += sprintf(buffer + off, "Data type: 0x%04X\n", entry->data_type);
       
   286     off += sprintf(buffer + off, "Bit length: %i\n", entry->bit_length);
       
   287 
       
   288     return off;
       
   289 }
       
   290 
       
   291 /*****************************************************************************/
       
   292 
       
   293 ssize_t ec_sdo_entry_format_data(ec_sdo_entry_t *entry, /**< SDO entry */
       
   294                                  ec_sdo_request_t *request, /**< SDO request */
       
   295                                  char *buffer /**< target buffer */
       
   296                                  )
       
   297 {
       
   298     off_t off = 0;
       
   299     unsigned int i;
       
   300 
       
   301     if (entry->data_type == 0x0002 && entry->bit_length == 8) { // int8
       
   302         off += sprintf(buffer + off, "%i\n", *((int8_t *) request->data));
       
   303     }
       
   304     else if (entry->data_type == 0x0003 && entry->bit_length == 16) { // int16
       
   305         off += sprintf(buffer + off, "%i\n", *((int16_t *) request->data));
       
   306     }
       
   307     else if (entry->data_type == 0x0004 && entry->bit_length == 32) { // int32
       
   308         off += sprintf(buffer + off, "%i\n", *((int32_t *) request->data));
       
   309     }
       
   310     else if (entry->data_type == 0x0005 && entry->bit_length == 8) { // uint8
       
   311         off += sprintf(buffer + off, "%i\n", *((uint8_t *) request->data));
       
   312     }
       
   313     else if (entry->data_type == 0x0006 && entry->bit_length == 16) { // uint16
       
   314         off += sprintf(buffer + off, "%i\n", *((uint16_t *) request->data));
       
   315     }
       
   316     else if (entry->data_type == 0x0007 && entry->bit_length == 32) { // uint32
       
   317         off += sprintf(buffer + off, "%i\n", *((uint32_t *) request->data));
       
   318     }
       
   319     else if (entry->data_type == 0x0009) { // string
       
   320         off += sprintf(buffer + off, "%s\n", request->data);
       
   321     }
       
   322     else {
       
   323         for (i = 0; i < request->size; i++)
       
   324             off += sprintf(buffer + off, "%02X (%c)\n",
       
   325                            request->data[i], request->data[i]);
       
   326     }
       
   327 
       
   328     return off;
       
   329 }
       
   330 
       
   331 /*****************************************************************************/
       
   332 
       
   333 ssize_t ec_sdo_entry_read_value(ec_sdo_entry_t *entry, /**< SDO entry */
       
   334                                 char *buffer /**< target buffer */
       
   335                                 )
       
   336 {
       
   337     ec_sdo_t *sdo = entry->sdo;
       
   338     ec_master_t *master = sdo->slave->master;
       
   339     off_t off = 0;
       
   340     ec_sdo_request_t request;
       
   341 
       
   342     if (down_interruptible(&master->sdo_sem)) {
       
   343         // interrupted by signal
       
   344         return -ERESTARTSYS;
       
   345     }
       
   346 
       
   347     ec_sdo_request_init_read(&request, sdo, entry);
       
   348 
       
   349     // this is necessary, because the completion object
       
   350     // is completed by the ec_master_flush_sdo_requests() function.
       
   351     INIT_COMPLETION(master->sdo_complete);
       
   352 
       
   353     master->sdo_request = &request;
       
   354     master->sdo_seq_user++;
       
   355     master->sdo_timer.expires = jiffies + 10;
       
   356     add_timer(&master->sdo_timer);
       
   357 
       
   358     wait_for_completion(&master->sdo_complete);
       
   359 
       
   360     master->sdo_request = NULL;
       
   361     up(&master->sdo_sem);
       
   362 
       
   363     if (request.return_code == 1 && request.data) {
       
   364         off += ec_sdo_entry_format_data(entry, &request, buffer);
       
   365     }
       
   366     else {
       
   367         off = -EINVAL;
       
   368     }
       
   369 
       
   370     ec_sdo_request_clear(&request);
       
   371     return off;
       
   372 }
       
   373 
       
   374 /*****************************************************************************/
       
   375 
       
   376 ssize_t ec_show_sdo_entry_attribute(struct kobject *kobj, /**< kobject */
       
   377                                     struct attribute *attr,
       
   378                                     char *buffer
       
   379                                     )
       
   380 {
       
   381     ec_sdo_entry_t *entry = container_of(kobj, ec_sdo_entry_t, kobj);
       
   382 
       
   383     if (attr == &attr_info) {
       
   384         return ec_sdo_entry_info(entry, buffer);
       
   385     }
       
   386     else if (attr == &attr_value) {
       
   387         return ec_sdo_entry_read_value(entry, buffer);
       
   388     }
       
   389 
       
   390     return 0;
       
   391 }
       
   392 
       
   393 /*****************************************************************************/
       
   394 
       
   395 /**
       
   396    SDO request constructor.
       
   397 */
       
   398 
       
   399 void ec_sdo_request_init_read(ec_sdo_request_t *req, /**< SDO request */
       
   400                               ec_sdo_t *sdo, /**< SDO */
       
   401                               ec_sdo_entry_t *entry /**< SDO entry */
       
   402                               )
       
   403 {
       
   404     req->sdo = sdo;
       
   405     req->entry = entry;
       
   406     req->data = NULL;
       
   407     req->size = 0;
       
   408     req->return_code = 0;
       
   409 }
       
   410 
       
   411 /*****************************************************************************/
       
   412 
       
   413 /**
       
   414    SDO request destructor.
       
   415 */
       
   416 
       
   417 void ec_sdo_request_clear(ec_sdo_request_t *req /**< SDO request */)
       
   418 {
       
   419     if (req->data) kfree(req->data);
       
   420 }
       
   421 
       
   422 /*****************************************************************************/