889 } |
889 } |
890 |
890 |
891 /*****************************************************************************/ |
891 /*****************************************************************************/ |
892 |
892 |
893 /** |
893 /** |
|
894 * Calculates the EEPROM checksum field. |
|
895 * |
|
896 * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an |
|
897 * initial value of 0xff (see IEC 61158-6-12 ch. 5.4). |
|
898 * |
|
899 * The below code was originally generated with PYCRC |
|
900 * http://www.tty1.net/pycrc |
|
901 * |
|
902 * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff |
|
903 * --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit |
|
904 * |
|
905 * \return CRC8 |
|
906 */ |
|
907 |
|
908 uint8_t ec_slave_eeprom_crc(const uint8_t *data, size_t length) |
|
909 { |
|
910 unsigned int i; |
|
911 uint8_t bit, byte, crc = 0x48; |
|
912 |
|
913 while (length--) { |
|
914 byte = *data++; |
|
915 for (i = 0; i < 8; i++) { |
|
916 bit = crc & 0x80; |
|
917 crc = (crc << 1) | ((byte >> (7 - i)) & 0x01); |
|
918 if (bit) crc ^= 0x07; |
|
919 } |
|
920 } |
|
921 |
|
922 for (i = 0; i < 8; i++) { |
|
923 bit = crc & 0x80; |
|
924 crc <<= 1; |
|
925 if (bit) crc ^= 0x07; |
|
926 } |
|
927 |
|
928 return crc; |
|
929 } |
|
930 |
|
931 /*****************************************************************************/ |
|
932 |
|
933 /** |
894 * Writes complete EEPROM contents to a slave. |
934 * Writes complete EEPROM contents to a slave. |
895 * \return data size written in case of success, otherwise error code. |
935 * \return data size written in case of success, otherwise error code. |
896 */ |
936 */ |
897 |
937 |
898 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ |
938 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ |
902 { |
942 { |
903 ec_eeprom_write_request_t request; |
943 ec_eeprom_write_request_t request; |
904 const uint16_t *cat_header; |
944 const uint16_t *cat_header; |
905 uint16_t cat_type, cat_size; |
945 uint16_t cat_type, cat_size; |
906 int ret; |
946 int ret; |
|
947 uint8_t crc; |
907 |
948 |
908 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
949 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
909 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
950 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
910 return -EBUSY; |
951 return -EBUSY; |
911 } |
952 } |
925 if (request.size < 0x0041) { |
966 if (request.size < 0x0041) { |
926 EC_ERR("EEPROM data too short! Dropping.\n"); |
967 EC_ERR("EEPROM data too short! Dropping.\n"); |
927 return -EINVAL; |
968 return -EINVAL; |
928 } |
969 } |
929 |
970 |
|
971 // calculate checksum |
|
972 crc = ec_slave_eeprom_crc(data, 14); // CRC over words 0 to 6 |
|
973 if (crc != data[14]) { |
|
974 EC_WARN("EEPROM CRC incorrect. Must be 0x%02x.\n", crc); |
|
975 } |
|
976 |
930 cat_header = request.words + EC_FIRST_EEPROM_CATEGORY_OFFSET; |
977 cat_header = request.words + EC_FIRST_EEPROM_CATEGORY_OFFSET; |
931 cat_type = EC_READ_U16(cat_header); |
978 cat_type = EC_READ_U16(cat_header); |
932 while (cat_type != 0xFFFF) { // cycle through categories |
979 while (cat_type != 0xFFFF) { // cycle through categories |
933 if (cat_header + 1 > request.words + request.size) { |
980 if (cat_header + 1 > request.words + request.size) { |
934 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
981 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
962 size_t size /**< size of data in bytes */ |
1009 size_t size /**< size of data in bytes */ |
963 ) |
1010 ) |
964 { |
1011 { |
965 ec_eeprom_write_request_t request; |
1012 ec_eeprom_write_request_t request; |
966 char *remainder; |
1013 char *remainder; |
967 uint16_t alias, word; |
1014 uint16_t alias, words[8]; |
968 int ret; |
1015 int ret; |
|
1016 uint8_t crc; |
969 |
1017 |
970 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
1018 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
971 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
1019 EC_ERR("Writing to EEPROM is only allowed in idle mode!\n"); |
972 return -EBUSY; |
1020 return -EBUSY; |
973 } |
1021 } |
974 |
1022 |
975 alias = simple_strtoul(data, &remainder, 0); |
1023 alias = simple_strtoul(data, &remainder, 0); |
976 if (remainder == (char *) data || (*remainder && *remainder != '\n')) { |
1024 if (remainder == (char *) data || (*remainder && *remainder != '\n')) { |
977 EC_ERR("Invalid alias value! Dropping.\n"); |
1025 EC_ERR("Invalid alias value! Dropping.\n"); |
978 return -EINVAL; |
1026 return -EINVAL; |
979 } |
1027 } |
|
1028 |
|
1029 if (!slave->eeprom_data || slave->eeprom_size < 16) { |
|
1030 EC_ERR("Failed to read EEPROM contents from slave %u.\n", |
|
1031 slave->ring_position); |
|
1032 return -EINVAL; |
|
1033 } |
|
1034 |
|
1035 // copy first 7 words of recent EEPROM contents |
|
1036 memcpy(words, slave->eeprom_data, 14); |
980 |
1037 |
981 // correct endianess |
1038 // write new alias address |
982 EC_WRITE_U16(&word, alias); |
1039 EC_WRITE_U16(words + 4, alias); |
|
1040 |
|
1041 // calculate new checksum over words 0 to 6 |
|
1042 crc = ec_slave_eeprom_crc((const uint8_t *) words, 14); |
|
1043 EC_WRITE_U16(words + 7, crc); |
983 |
1044 |
984 // init EEPROM write request |
1045 // init EEPROM write request |
985 INIT_LIST_HEAD(&request.list); |
1046 INIT_LIST_HEAD(&request.list); |
986 request.slave = slave; |
1047 request.slave = slave; |
987 request.words = &word; |
1048 request.words = words; |
988 request.offset = 0x0004; |
1049 request.offset = 0x0000; |
989 request.size = 1; |
1050 request.size = 8; |
990 |
1051 |
991 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
1052 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
992 return ret; // error code |
1053 return ret; // error code |
993 |
1054 |
994 slave->sii_alias = alias; // FIXME: do this in state machine |
1055 slave->sii_alias = alias; // FIXME: do this in state machine |