Implemented SII writing (including alias writing) via ethercat command.
authorFlorian Pose <fp@igh-essen.com>
Tue, 10 Jun 2008 08:48:50 +0000
changeset 980 c07dd38243ba
parent 979 405cc2d033e0
child 981 5a2bd04c555c
Implemented SII writing (including alias writing) via ethercat command.
TODO
master/cdev.c
master/ioctl.h
master/slave.c
master/slave.h
tools/Master.cpp
tools/Master.h
tools/main.cpp
--- a/TODO	Mon Jun 09 14:32:16 2008 +0000
+++ b/TODO	Tue Jun 10 08:48:50 2008 +0000
@@ -9,7 +9,6 @@
 Version 1.4.0:
 
 * Replace all Sysfs files via the new ethercat tool.
-    - Slave alias write
     - Slave info (flags, mailbox, general) 
     - Config info (alias, position, type, Pdos, Sdos)
 * Slaves as array.
@@ -26,6 +25,7 @@
 * Check for sizes of uploaded Sdos when reading mapping from CoE.
 * Attach Pdo names from SII or Coe dictioary to Pdos read via CoE.
 * Make scanning and configuration run parallel (each).
+* List of commands that require a slave.
 
 Future issues:
 
--- a/master/cdev.c	Mon Jun 09 14:32:16 2008 +0000
+++ b/master/cdev.c	Tue Jun 10 08:48:50 2008 +0000
@@ -763,7 +763,7 @@
 
         case EC_IOCTL_SII_READ:
             {
-                ec_ioctl_sii_read_t data;
+                ec_ioctl_sii_t data;
                 const ec_slave_t *slave;
 
                 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
@@ -795,6 +795,54 @@
                 break;
             }
 
+        case EC_IOCTL_SII_WRITE:
+            {
+                ec_ioctl_sii_t data;
+                ec_slave_t *slave;
+                unsigned int byte_size;
+                uint16_t *words;
+
+                if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
+                    retval = -EFAULT;
+                    break;
+                }
+                
+                if (!(slave = ec_master_find_slave(
+                                master, 0, data.slave_position))) {
+                    EC_ERR("Slave %u does not exist!\n", data.slave_position);
+                    retval = -EINVAL;
+                    break;
+                }
+
+                if (!data.nwords)
+                    break;
+
+                byte_size = sizeof(uint16_t) * data.nwords;
+                if (!(words = kmalloc(byte_size, GFP_KERNEL))) {
+                    EC_ERR("Failed to allocate %u bytes for SII contents.\n",
+                            byte_size);
+                    retval = -ENOMEM;
+                    break;
+                }
+
+                if (copy_from_user(words,
+                            (void __user *) data.words, byte_size)) {
+                    retval = -EFAULT;
+                    kfree(words);
+                    break;
+                }
+
+                if (ec_slave_write_sii(slave,
+                            data.offset, data.nwords, words)) {
+                    retval = -EIO;
+                    kfree(words);
+                    break;
+                }
+
+                kfree(words);
+                break;
+            }
+
         default:
             retval = -ENOTTY;
     }
--- a/master/ioctl.h	Mon Jun 09 14:32:16 2008 +0000
+++ b/master/ioctl.h	Tue Jun 10 08:48:50 2008 +0000
@@ -67,7 +67,8 @@
 #define EC_IOCTL_SDO_ENTRY    EC_IOWR(0x0c, ec_ioctl_sdo_entry_t)
 #define EC_IOCTL_SDO_UPLOAD   EC_IOWR(0x0d, ec_ioctl_sdo_upload_t)
 #define EC_IOCTL_SDO_DOWNLOAD  EC_IOW(0x0e, ec_ioctl_sdo_download_t)
-#define EC_IOCTL_SII_READ     EC_IOWR(0x0f, ec_ioctl_sii_read_t)
+#define EC_IOCTL_SII_READ     EC_IOWR(0x0f, ec_ioctl_sii_t)
+#define EC_IOCTL_SII_WRITE     EC_IOW(0x10, ec_ioctl_sii_t)
 
 /*****************************************************************************/
 
@@ -264,7 +265,7 @@
     uint16_t offset;
     uint32_t nwords;
     uint16_t *words;
-} ec_ioctl_sii_read_t;
+} ec_ioctl_sii_t;
 
 /*****************************************************************************/
 
--- a/master/slave.c	Mon Jun 09 14:32:16 2008 +0000
+++ b/master/slave.c	Tue Jun 10 08:48:50 2008 +0000
@@ -57,8 +57,6 @@
 void ec_slave_clear(struct kobject *);
 void ec_slave_sdos_clear(struct kobject *);
 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
-ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *,
-                                 const char *, size_t);
 char *ec_slave_sii_string(ec_slave_t *, unsigned int);
 
 /*****************************************************************************/
@@ -66,19 +64,14 @@
 /** \cond */
 
 EC_SYSFS_READ_ATTR(info);
-EC_SYSFS_READ_WRITE_ATTR(sii);
-EC_SYSFS_READ_WRITE_ATTR(alias);
 
 static struct attribute *def_attrs[] = {
     &attr_info,
-    &attr_sii,
-    &attr_alias,
     NULL,
 };
 
 static struct sysfs_ops sysfs_ops = {
     .show = ec_show_slave_attribute,
-    .store = ec_store_slave_attribute
 };
 
 static struct kobj_type ktype_ec_slave = {
@@ -848,217 +841,59 @@
 /*****************************************************************************/
 
 /**
- * Schedules an SII write request.
- * \return 0 case of success, otherwise error code.
- */
-
-int ec_slave_schedule_sii_writing(
-        ec_sii_write_request_t *request /**< SII write request */
-        )
-{
-    ec_master_t *master = request->slave->master;
-
-    request->state = EC_REQUEST_QUEUED;
-
-    // schedule SII write request.
-    down(&master->sii_sem);
-    list_add_tail(&request->list, &master->sii_requests);
-    up(&master->sii_sem);
-
-    // wait for processing through FSM
-    if (wait_event_interruptible(master->sii_queue,
-                request->state != EC_REQUEST_QUEUED)) {
-        // interrupted by signal
-        down(&master->sii_sem);
-        if (request->state == EC_REQUEST_QUEUED) {
-            list_del(&request->list);
-            up(&master->sii_sem);
-            return -EINTR;
-        }
-        // request already processing: interrupt not possible.
-        up(&master->sii_sem);
-    }
-
-    // wait until master FSM has finished processing
-    wait_event(master->sii_queue,
-            request->state != EC_REQUEST_BUSY);
-
-    return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
-}
-
-/*****************************************************************************/
-
-/**
- * Calculates the SII checksum field.
- *
- * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
- * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
- *
- * The below code was originally generated with PYCRC
- * http://www.tty1.net/pycrc
- *
- * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
- *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
- *
- * \return CRC8
- */
-
-uint8_t ec_slave_sii_crc(
-        const uint8_t *data, /**< pointer to data */
-        size_t length /**< number of bytes in \a data */
-        )
-{
-    unsigned int i;
-    uint8_t bit, byte, crc = 0x48;
-
-    while (length--) {
-        byte = *data++;
-        for (i = 0; i < 8; i++) {
-            bit = crc & 0x80;
-            crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
-            if (bit) crc ^= 0x07;
-        }
-    }
-
-    for (i = 0; i < 8; i++) {
-        bit = crc & 0x80;
-        crc <<= 1;
-        if (bit) crc ^= 0x07;
-    }
-
-    return crc;
-}
-
-/*****************************************************************************/
-
-/**
- * Writes complete SII contents to a slave.
- * \return data size written in case of success, otherwise error code.
- */
-
-ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */
-        const uint8_t *data, /**< new SII data */
-        size_t size /**< size of data in bytes */
-        )
-{
+ * Writes SII contents to a slave.
+ * \return Zero on success, otherwise error code.
+ */
+
+int ec_slave_write_sii(
+        ec_slave_t *slave, /**< EtherCAT slave */
+        uint16_t offset, /**< SII word offset. */
+        unsigned int nwords, /**< Number of words. */
+        const uint16_t *words /**< New SII data. */
+        )
+{
+    ec_master_t *master = slave->master;
     ec_sii_write_request_t request;
-    const uint16_t *cat_header;
-    uint16_t cat_type, cat_size;
-    int ret;
-    uint8_t crc;
-
-    if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
-        EC_ERR("Writing SIIs only allowed in idle mode!\n");
-        return -EBUSY;
-    }
-
-    if (size % 2) {
-        EC_ERR("SII data size is odd (%u bytes)! SII data must be"
-                " word-aligned. Dropping.\n", size);
-        return -EINVAL;
-    }
 
     // init SII write request
     INIT_LIST_HEAD(&request.list);
     request.slave = slave;
-    request.words = (const uint16_t *) data;
-    request.offset = 0;
-    request.nwords = size / 2;
-
-    if (request.nwords < 0x0041) {
-        EC_ERR("SII data too short (%u words)! Mimimum is"
-                " 40 fixed words + 1 delimiter. Dropping.\n",
-                request.nwords);
-        return -EINVAL;
-    }
-
-    // calculate checksum
-    crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6
-    if (crc != data[14]) {
-        EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc);
-    }
-
-    cat_header = request.words + EC_FIRST_SII_CATEGORY_OFFSET;
-    cat_type = EC_READ_U16(cat_header);
-    while (cat_type != 0xFFFF) { // cycle through categories
-        if (cat_header + 1 > request.words + request.nwords) {
-            EC_ERR("SII data corrupted! Dropping.\n");
-            return -EINVAL;
-        }
-        cat_size = EC_READ_U16(cat_header + 1);
-        if (cat_header + cat_size + 2 > request.words + request.nwords) {
-            EC_ERR("SII data corrupted! Dropping.\n");
-            return -EINVAL;
-        }
-        cat_header += cat_size + 2;
-        cat_type = EC_READ_U16(cat_header);
-    }
-
-    // SII data ok. schedule writing.
-    if ((ret = ec_slave_schedule_sii_writing(&request)))
-        return ret; // error code
-
-    return size; // success
-}
-
-/*****************************************************************************/
-
-/**
- * Writes the Secondary slave address (alias) to the slave's SII.
- * \return data size written in case of success, otherwise error code.
- */
-
-ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
-        const uint8_t *data, /**< alias string */
-        size_t size /**< size of data in bytes */
-        )
-{
-    ec_sii_write_request_t request;
-    char *remainder;
-    uint16_t alias;
-    int ret;
-    uint8_t sii_data[16], crc;
-
-    if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
-        EC_ERR("Writing to SII is only allowed in idle mode!\n");
-        return -EBUSY;
-    }
-
-    alias = simple_strtoul(data, &remainder, 0);
-    if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
-        EC_ERR("Invalid alias value! Dropping.\n");
-        return -EINVAL;
-    }
-
-    if (!slave->sii_words || slave->sii_nwords < 8) {
-        EC_ERR("Failed to read SII contents from slave %u.\n",
-                slave->ring_position);
-        return -EINVAL;
-    }
-
-    // copy first 7 words of recent SII contents
-    memcpy(sii_data, (uint8_t *) slave->sii_words, 14);
-    
-    // write new alias address in word 4
-    EC_WRITE_U16(sii_data + 8, alias);
-
-    // calculate new checksum over words 0 to 6
-    crc = ec_slave_sii_crc(sii_data, 14);
-    EC_WRITE_U16(sii_data + 14, crc);
-
-    // init SII write request
-    INIT_LIST_HEAD(&request.list);
-    request.slave = slave;
-    request.words = (const uint16_t *) sii_data;
-    request.offset = 0x0000;
-    request.nwords = 8;
-
-    if ((ret = ec_slave_schedule_sii_writing(&request)))
-        return ret; // error code
-
-    slave->sii.alias = alias; // FIXME: do this in state machine
-
-    return size; // success
+    request.words = words;
+    request.offset = offset;
+    request.nwords = nwords;
+    request.state = EC_REQUEST_QUEUED;
+
+    // schedule SII write request.
+    down(&master->sii_sem);
+    list_add_tail(&request.list, &master->sii_requests);
+    up(&master->sii_sem);
+
+    // wait for processing through FSM
+    if (wait_event_interruptible(master->sii_queue,
+                request.state != EC_REQUEST_QUEUED)) {
+        // interrupted by signal
+        down(&master->sii_sem);
+        if (request.state == EC_REQUEST_QUEUED) {
+            list_del(&request.list);
+            up(&master->sii_sem);
+            return -EINTR;
+        }
+        // request already processing: interrupt not possible.
+        up(&master->sii_sem);
+    }
+
+    // wait until master FSM has finished processing
+    wait_event(master->sii_queue,
+            request.state != EC_REQUEST_BUSY);
+
+    if (request.state == EC_REQUEST_SUCCESS) {
+        if (offset <= 4 && offset + nwords > 4) { // alias was written
+            slave->sii.alias = EC_READ_U16(words + 4);
+        }
+        return 0;
+    } else {
+        return -EIO;
+    }
 }
 
 /*****************************************************************************/
@@ -1074,25 +909,9 @@
                                 )
 {
     ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
-    unsigned int sii_size;
 
     if (attr == &attr_info) {
         return ec_slave_info(slave, buffer);
-    } else if (attr == &attr_sii) {
-        if (slave->sii_words) {
-            sii_size = slave->sii_nwords * 2;
-            if (sii_size > PAGE_SIZE) {
-                EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
-                       slave->ring_position, sii_size,
-                       (int) PAGE_SIZE);
-            }
-            else {
-                memcpy(buffer, (uint8_t *) slave->sii_words, sii_size);
-                return sii_size;
-            }
-        }
-    } else if (attr == &attr_alias) {
-        return sprintf(buffer, "%u\n", slave->sii.alias);
     }
 
     return 0;
@@ -1100,30 +919,6 @@
 
 /*****************************************************************************/
 
-/**
-   Formats attribute data for SysFS write access.
-   \return number of bytes processed, or negative error code
-*/
-
-ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
-                                 struct attribute *attr, /**< attribute */
-                                 const char *buffer, /**< memory with data */
-                                 size_t size /**< size of data to store */
-                                 )
-{
-    ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
-
-    if (attr == &attr_sii) {
-        return ec_slave_write_sii(slave, buffer, size);
-    } else if (attr == &attr_alias) {
-        return ec_slave_write_alias(slave, buffer, size);
-    }
-
-    return -EIO;
-}
-
-/*****************************************************************************/
-
 /** Get the sync manager for either Rx- or Tx-Pdos.
  *
  * \todo This seems not to be correct in every case...
--- a/master/slave.h	Mon Jun 09 14:32:16 2008 +0000
+++ b/master/slave.h	Tue Jun 10 08:48:50 2008 +0000
@@ -228,6 +228,9 @@
 uint16_t ec_slave_sdo_count(const ec_slave_t *);
 const ec_pdo_t *ec_slave_find_pdo(const ec_slave_t *, uint16_t);
 
+int ec_slave_write_sii(ec_slave_t *, uint16_t, unsigned int,
+        const uint16_t *);
+
 /*****************************************************************************/
 
 #endif
--- a/tools/Master.cpp	Mon Jun 09 14:32:16 2008 +0000
+++ b/tools/Master.cpp	Tue Jun 10 08:48:50 2008 +0000
@@ -13,6 +13,7 @@
 #include <iostream>
 #include <iomanip>
 #include <sstream>
+#include <fstream>
 #include <cctype> // toupper()
 using namespace std;
 
@@ -116,6 +117,60 @@
     index = i;
 }
 
+/*****************************************************************************/
+
+/**
+ * Writes the Secondary slave address (alias) to the slave's SII.
+ */
+void Master::writeAlias(
+        int slavePosition,
+        bool force,
+        const vector<string> &commandArgs
+        )
+{
+    ec_ioctl_sii_t data;
+    ec_ioctl_slave_t slave;
+    unsigned int i;
+    uint16_t alias;
+    stringstream err, strAlias;
+    int number;
+
+    if (commandArgs.size() != 1) {
+        stringstream err;
+        err << "'alias' takes exactly one argument!";
+        throw MasterException(err.str());
+    }
+
+    strAlias << commandArgs[0];
+    strAlias >> hex >> number;
+    if (strAlias.fail() || number < 0x0000 || number > 0xffff) {
+        err << "Invalid alias '" << commandArgs[0] << "'!";
+        throw MasterException(err.str());
+    }
+    alias = number;
+
+    if (slavePosition == -1) {
+        unsigned int numSlaves, i;
+
+        if (!force) {
+            err << "This will write the alias addresses of all slaves to 0x"
+                << hex << setfill('0') << setw(4) << alias << "! "
+                << "Please specify --force to proceed.";
+            throw MasterException(err.str());
+        }
+
+        open(ReadWrite);
+        numSlaves = slaveCount();
+
+        for (i = 0; i < numSlaves; i++) {
+            writeSlaveAlias(i, alias);
+        }
+    } else {
+        open(ReadWrite);
+        writeSlaveAlias(slavePosition, alias);
+    }
+}
+
 /****************************************************************************/
 
 void Master::outputData(int domainIndex)
@@ -197,14 +252,17 @@
     aliasIndex = 0;
     for (i = 0; i < numSlaves; i++) {
         getSlave(&slave, i);
-        cout << setw(2) << i << "  ";
+        cout << setfill(' ') << setw(2) << i << "  ";
 
         if (slave.alias) {
             lastAlias = slave.alias;
             aliasIndex = 0;
         }
         if (lastAlias) {
-            cout << setw(10) << "#" << lastAlias << ":" << aliasIndex;
+            cout << "#"
+                << hex << setfill('0') << setw(4) << lastAlias
+                << ":" << dec << aliasIndex;
+            aliasIndex++;
         }
 
         cout << "  " << slaveState(slave.state) << "  ";
@@ -212,8 +270,9 @@
         if (strlen(slave.name)) {
             cout << slave.name;
         } else {
-            cout << "0x" << hex << setfill('0') << slave.vendor_id
-                << ":0x" << slave.product_code;
+            cout << hex << setfill('0')
+                << setw(8) << slave.vendor_id << ":"
+                << setw(8) << slave.product_code << dec;
         }
 
         cout << endl;
@@ -608,7 +667,7 @@
 
 void Master::siiRead(int slavePosition)
 {
-    ec_ioctl_sii_read_t data;
+    ec_ioctl_sii_t data;
     ec_ioctl_slave_t slave;
     unsigned int i;
 
@@ -647,6 +706,102 @@
 
 /****************************************************************************/
 
+void Master::siiWrite(
+        int slavePosition,
+        bool force,
+        const vector<string> &commandArgs
+        )
+{
+    stringstream err;
+    ec_ioctl_sii_t data;
+    ifstream file;
+    unsigned int byte_size;
+    const uint16_t *categoryHeader;
+    uint16_t categoryType, categorySize;
+    uint8_t crc;
+
+    if (slavePosition < 0) {
+        err << "'sii_write' requires a slave! Please specify --slave.";
+        throw MasterException(err.str());
+    }
+    data.slave_position = slavePosition;
+
+    if (commandArgs.size() != 1) {
+        err << "'ssi_write' takes exactly one argument!";
+        throw MasterException(err.str());
+    }
+
+    file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary);
+    if (file.fail()) {
+        err << "Failed to open '" << commandArgs[0] << "'!";
+        throw MasterException(err.str());
+    }
+
+    // get length of file
+    file.seekg(0, ios::end);
+    byte_size = file.tellg();
+    file.seekg(0, ios::beg);
+
+    if (!byte_size || byte_size % 2) {
+        stringstream err;
+        err << "Invalid file size! Must be non-zero and even.";
+        throw MasterException(err.str());
+    }
+
+    data.nwords = byte_size / 2;
+    if (data.nwords < 0x0041 && !force) {
+        err << "SII data too short (" << data.nwords << " words)! Mimimum is"
+                " 40 fixed words + 1 delimiter. Use --force to write anyway.";
+        throw MasterException(err.str());
+    }
+
+    // allocate buffer and read file into buffer
+    data.words = new uint16_t[data.nwords];
+    file.read((char *) data.words, byte_size);
+    file.close();
+
+    if (!force) {
+        // calculate checksum over words 0 to 6
+        crc = calcSiiCrc((const uint8_t *) data.words, 14);
+        if (crc != ((const uint8_t *) data.words)[14]) {
+            err << "CRC incorrect. Must be 0x"
+                << hex << setfill('0') << setw(2) << (unsigned int) crc
+                << ". Use --force to write anyway.";
+            throw MasterException(err.str());
+        }
+
+        // cycle through categories to detect corruption
+        categoryHeader = data.words + 0x0040;
+        categoryType = le16tocpu(*categoryHeader);
+        while (categoryType != 0xffff) {
+            if (categoryHeader + 1 > data.words + data.nwords) {
+                err << "SII data seem to be corrupted! "
+                    << "Use --force to write anyway.";
+                throw MasterException(err.str());
+            }
+            categorySize = le16tocpu(*(categoryHeader + 1));
+            if (categoryHeader + categorySize + 2 > data.words + data.nwords) {
+                err << "SII data seem to be corrupted! "
+                    "Use --force to write anyway.";
+                throw MasterException(err.str());
+            }
+            categoryHeader += categorySize + 2;
+            categoryType = le16tocpu(*categoryHeader);
+        }
+    }
+
+    // send data to master
+    open(ReadWrite);
+    data.offset = 0;
+    if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) {
+        stringstream err;
+        err << "Failed to write SII: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+}
+
+/****************************************************************************/
+
 void Master::requestStates(
         int slavePosition,
         const vector<string> &commandArgs
@@ -744,6 +899,62 @@
     ::close(fd);
 }
 
+/*****************************************************************************/
+
+/**
+ * Writes the Secondary slave address (alias) to the slave's SII.
+ */
+void Master::writeSlaveAlias(
+        uint16_t slavePosition,
+        uint16_t alias
+        )
+{
+    ec_ioctl_sii_t data;
+    ec_ioctl_slave_t slave;
+    stringstream err;
+    uint8_t crc;
+
+    open(ReadWrite);
+
+    getSlave(&slave, slavePosition);
+
+    if (slave.sii_nwords < 8) {
+        err << "Current SII contents are too small to set an alias "
+            << "(" << slave.sii_nwords << " words)!";
+        throw MasterException(err.str());
+    }
+
+    data.slave_position = slavePosition;
+    data.offset = 0;
+    data.nwords = 8;
+    data.words = new uint16_t[data.nwords];
+
+    // read first 8 SII words
+    if (ioctl(fd, EC_IOCTL_SII_READ, &data) < 0) {
+        delete [] data.words;
+        err << "Failed to read SII: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+
+    // write new alias address in word 4
+    data.words[4] = cputole16(alias);
+
+    // calculate checksum over words 0 to 6
+    crc = calcSiiCrc((const uint8_t *) data.words, 14);
+
+    // write new checksum into first byte of word 7
+    *(uint8_t *) (data.words + 7) = crc;
+
+    // write first 8 words with new alias and checksum
+    if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) {
+        delete [] data.words;
+        err << "Failed to write SII: " << strerror(errno);
+        throw MasterException(err.str());
+    }
+
+    delete [] data.words;
+}
+
 /****************************************************************************/
 
 void Master::outputDomainData(unsigned int domainIndex)
@@ -1330,4 +1541,46 @@
     cout << endl;
 }
 
-/****************************************************************************/
+/*****************************************************************************/
+
+/**
+ * Calculates the SII checksum field.
+ *
+ * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
+ * initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
+ *
+ * The below code was originally generated with PYCRC
+ * http://www.tty1.net/pycrc
+ *
+ * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
+ *   --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
+ *
+ * \return CRC8
+ */
+uint8_t Master::calcSiiCrc(
+        const uint8_t *data, /**< pointer to data */
+        size_t length /**< number of bytes in \a data */
+        )
+{
+    unsigned int i;
+    uint8_t bit, byte, crc = 0x48;
+
+    while (length--) {
+        byte = *data++;
+        for (i = 0; i < 8; i++) {
+            bit = crc & 0x80;
+            crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
+            if (bit) crc ^= 0x07;
+        }
+    }
+
+    for (i = 0; i < 8; i++) {
+        bit = crc & 0x80;
+        crc <<= 1;
+        if (bit) crc ^= 0x07;
+    }
+
+    return crc;
+}
+
+/*****************************************************************************/
--- a/tools/Master.h	Mon Jun 09 14:32:16 2008 +0000
+++ b/tools/Master.h	Tue Jun 10 08:48:50 2008 +0000
@@ -41,6 +41,7 @@
 
         void setIndex(unsigned int);
 
+        void writeAlias(int, bool, const vector<string> &);
         void outputData(int);
         void setDebug(const vector<string> &);
         void showDomains(int);
@@ -51,6 +52,7 @@
         void sdoDownload(int, const string &, const vector<string> &);
         void sdoUpload(int, const string &, const vector<string> &);
         void siiRead(int);
+        void siiWrite(int, bool, const vector<string> &);
         void requestStates(int, const vector<string> &);
         void generateXml(int);
 
@@ -59,6 +61,7 @@
         void open(Permissions);
         void close();
 
+        void writeSlaveAlias(uint16_t, uint16_t);
         void outputDomainData(unsigned int);
         void showDomain(unsigned int);
         void listSlavePdos(uint16_t, bool = false, bool = false);
@@ -83,6 +86,7 @@
 
         static string slaveState(uint8_t);
         static void printRawData(const uint8_t *, unsigned int);
+        static uint8_t calcSiiCrc(const uint8_t *, unsigned int);
         
     private:
         enum {DefaultBufferSize = 1024};
--- a/tools/main.cpp	Mon Jun 09 14:32:16 2008 +0000
+++ b/tools/main.cpp	Tue Jun 10 08:48:50 2008 +0000
@@ -24,6 +24,7 @@
 vector<string> commandArgs;
 static bool quiet = false;
 string dataTypeStr;
+bool force = false;
 
 /*****************************************************************************/
 
@@ -32,6 +33,7 @@
     cerr
         << "Usage: ethercat <COMMAND> [OPTIONS]" << endl
 		<< "Commands:" << endl
+        << "  alias              Write alias address(es)." << endl
         << "  data               Output binary domain process data." << endl
         << "  debug              Set the master debug level." << endl
         << "  domain             Show domain information." << endl
@@ -42,6 +44,7 @@
         << "  sdo_download (sd)  Write an Sdo entry." << endl
         << "  sdo_upload (su)    Read an Sdo entry." << endl
         << "  sii_read (sr)      Output a slave's SII contents." << endl
+        << "  sii_write (sw)     Write slave's SII contents." << endl
         << "  state              Request slave states." << endl
         << "  xml                Generate slave information xmls." << endl
 		<< "Global options:" << endl
@@ -56,6 +59,7 @@
         << "                         or 'all' for all domains (default)."
         << endl
         << "  --type    -t <type>    Forced Sdo data type." << endl
+        << "  --force   -f           Force action." << endl
         << "  --quiet   -q           Show less output." << endl
         << "  --help    -h           Show this help." << endl;
 }
@@ -73,13 +77,14 @@
         {"slave",  required_argument, NULL, 's'},
         {"domain", required_argument, NULL, 'd'},
         {"type",   required_argument, NULL, 't'},
+        {"force",  no_argument,       NULL, 'f'},
         {"quiet",  no_argument,       NULL, 'q'},
         {"help",   no_argument,       NULL, 'h'},
         {}
     };
 
     do {
-        c = getopt_long(argc, argv, "m:s:d:t:qh", longOptions, &optionIndex);
+        c = getopt_long(argc, argv, "m:s:d:t:fqh", longOptions, &optionIndex);
 
         switch (c) {
             case 'm':
@@ -127,6 +132,10 @@
                 dataTypeStr = optarg;
                 break;
 
+            case 'f':
+                force = true;
+                break;
+
             case 'q':
                 quiet = true;
                 break;
@@ -166,7 +175,9 @@
     try {
         master.setIndex(masterIndex);
 
-        if (command == "data") {
+        if (command == "alias") {
+            master.writeAlias(slavePosition, force, commandArgs);
+        } else if (command == "data") {
             master.outputData(domainIndex);
         } else if (command == "debug") {
             master.setDebug(commandArgs);
@@ -186,6 +197,8 @@
             master.sdoUpload(slavePosition, dataTypeStr, commandArgs);
         } else if (command == "sii_read" || command == "sr") {
             master.siiRead(slavePosition);
+        } else if (command == "sii_write" || command == "sw") {
+            master.siiWrite(slavePosition, force, commandArgs);
         } else if (command == "state") {
             master.requestStates(slavePosition, commandArgs);
         } else if (command == "xml") {