Calculate checksum when writing EEPROM or alias address.
authorFlorian Pose <fp@igh-essen.com>
Wed, 19 Sep 2007 09:37:01 +0000
changeset 735 0773628aabab
parent 734 8c9d62f7c2cd
child 736 53afedcb52f6
Calculate checksum when writing EEPROM or alias address.
NEWS
master/slave.c
--- a/NEWS	Wed Sep 19 09:07:36 2007 +0000
+++ b/NEWS	Wed Sep 19 09:37:01 2007 +0000
@@ -6,6 +6,7 @@
 
 Changes in version 1.3.2:
 
+* Calculate checksum when writing EEPROM or alias address.
 * Removed config.kbuild and replaced Kbuild files by Kbuild.in files.
 
 -------------------------------------------------------------------------------
--- a/master/slave.c	Wed Sep 19 09:07:36 2007 +0000
+++ b/master/slave.c	Wed Sep 19 09:37:01 2007 +0000
@@ -891,6 +891,46 @@
 /*****************************************************************************/
 
 /**
+ * Calculates the EEPROM 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_eeprom_crc(const uint8_t *data, size_t length)
+{
+    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 EEPROM contents to a slave.
  * \return data size written in case of success, otherwise error code.
  */
@@ -904,6 +944,7 @@
     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 EEPROMs only allowed in idle mode!\n");
@@ -927,6 +968,12 @@
         return -EINVAL;
     }
 
+    // calculate checksum
+    crc = ec_slave_eeprom_crc(data, 14); // CRC over words 0 to 6
+    if (crc != data[14]) {
+        EC_WARN("EEPROM CRC incorrect. Must be 0x%02x.\n", crc);
+    }
+
     cat_header = request.words + EC_FIRST_EEPROM_CATEGORY_OFFSET;
     cat_type = EC_READ_U16(cat_header);
     while (cat_type != 0xFFFF) { // cycle through categories
@@ -964,11 +1011,12 @@
 {
     ec_eeprom_write_request_t request;
     char *remainder;
-    uint16_t alias, word;
+    uint16_t alias, words[8];
     int ret;
+    uint8_t crc;
 
     if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
-        EC_ERR("Writing EEPROMs only allowed in idle mode!\n");
+        EC_ERR("Writing to EEPROM is only allowed in idle mode!\n");
         return -EBUSY;
     }
 
@@ -977,16 +1025,29 @@
         EC_ERR("Invalid alias value! Dropping.\n");
         return -EINVAL;
     }
+
+    if (!slave->eeprom_data || slave->eeprom_size < 16) {
+        EC_ERR("Failed to read EEPROM contents from slave %u.\n",
+                slave->ring_position);
+        return -EINVAL;
+    }
+
+    // copy first 7 words of recent EEPROM contents
+    memcpy(words, slave->eeprom_data, 14);
     
-    // correct endianess
-    EC_WRITE_U16(&word, alias);
+    // write new alias address
+    EC_WRITE_U16(words + 4, alias);
+
+    // calculate new checksum over words 0 to 6
+    crc = ec_slave_eeprom_crc((const uint8_t *) words, 14);
+    EC_WRITE_U16(words + 7, crc);
 
     // init EEPROM write request
     INIT_LIST_HEAD(&request.list);
     request.slave = slave;
-    request.words = &word;
-    request.offset = 0x0004;
-    request.size = 1;
+    request.words = words;
+    request.offset = 0x0000;
+    request.size = 8;
 
     if ((ret = ec_slave_schedule_eeprom_writing(&request)))
         return ret; // error code