859 } |
860 } |
860 |
861 |
861 /*****************************************************************************/ |
862 /*****************************************************************************/ |
862 |
863 |
863 /** |
864 /** |
864 * Schedules an EEPROM write request. |
865 * Schedules an SII write request. |
865 * \return 0 case of success, otherwise error code. |
866 * \return 0 case of success, otherwise error code. |
866 */ |
867 */ |
867 |
868 |
868 int ec_slave_schedule_eeprom_writing( |
869 int ec_slave_schedule_sii_writing( |
869 ec_eeprom_write_request_t *request /**< EEPROM write request */ |
870 ec_sii_write_request_t *request /**< SII write request */ |
870 ) |
871 ) |
871 { |
872 { |
872 ec_master_t *master = request->slave->master; |
873 ec_master_t *master = request->slave->master; |
873 |
874 |
874 request->state = EC_REQUEST_QUEUED; |
875 request->state = EC_REQUEST_QUEUED; |
875 |
876 |
876 // schedule EEPROM write request. |
877 // schedule SII write request. |
877 down(&master->eeprom_sem); |
878 down(&master->sii_sem); |
878 list_add_tail(&request->list, &master->eeprom_requests); |
879 list_add_tail(&request->list, &master->sii_requests); |
879 up(&master->eeprom_sem); |
880 up(&master->sii_sem); |
880 |
881 |
881 // wait for processing through FSM |
882 // wait for processing through FSM |
882 if (wait_event_interruptible(master->eeprom_queue, |
883 if (wait_event_interruptible(master->sii_queue, |
883 request->state != EC_REQUEST_QUEUED)) { |
884 request->state != EC_REQUEST_QUEUED)) { |
884 // interrupted by signal |
885 // interrupted by signal |
885 down(&master->eeprom_sem); |
886 down(&master->sii_sem); |
886 if (request->state == EC_REQUEST_QUEUED) { |
887 if (request->state == EC_REQUEST_QUEUED) { |
887 list_del(&request->list); |
888 list_del(&request->list); |
888 up(&master->eeprom_sem); |
889 up(&master->sii_sem); |
889 return -EINTR; |
890 return -EINTR; |
890 } |
891 } |
891 // request already processing: interrupt not possible. |
892 // request already processing: interrupt not possible. |
892 up(&master->eeprom_sem); |
893 up(&master->sii_sem); |
893 } |
894 } |
894 |
895 |
895 // wait until master FSM has finished processing |
896 // wait until master FSM has finished processing |
896 wait_event(master->eeprom_queue, |
897 wait_event(master->sii_queue, |
897 request->state != EC_REQUEST_BUSY); |
898 request->state != EC_REQUEST_BUSY); |
898 |
899 |
899 return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO; |
900 return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO; |
900 } |
901 } |
901 |
902 |
902 /*****************************************************************************/ |
903 /*****************************************************************************/ |
903 |
904 |
904 /** |
905 /** |
905 * Calculates the EEPROM checksum field. |
906 * Calculates the SII checksum field. |
906 * |
907 * |
907 * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an |
908 * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an |
908 * initial value of 0xff (see IEC 61158-6-12 ch. 5.4). |
909 * initial value of 0xff (see IEC 61158-6-12 ch. 5.4). |
909 * |
910 * |
910 * The below code was originally generated with PYCRC |
911 * The below code was originally generated with PYCRC |
943 } |
944 } |
944 |
945 |
945 /*****************************************************************************/ |
946 /*****************************************************************************/ |
946 |
947 |
947 /** |
948 /** |
948 * Writes complete EEPROM contents to a slave. |
949 * Writes complete SII contents to a slave. |
949 * \return data size written in case of success, otherwise error code. |
950 * \return data size written in case of success, otherwise error code. |
950 */ |
951 */ |
951 |
952 |
952 ssize_t ec_slave_write_eeprom(ec_slave_t *slave, /**< EtherCAT slave */ |
953 ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */ |
953 const uint8_t *data, /**< new EEPROM data */ |
954 const uint8_t *data, /**< new SII data */ |
954 size_t size /**< size of data in bytes */ |
955 size_t size /**< size of data in bytes */ |
955 ) |
956 ) |
956 { |
957 { |
957 ec_eeprom_write_request_t request; |
958 ec_sii_write_request_t request; |
958 const uint16_t *cat_header; |
959 const uint16_t *cat_header; |
959 uint16_t cat_type, cat_size; |
960 uint16_t cat_type, cat_size; |
960 int ret; |
961 int ret; |
961 uint8_t crc; |
962 uint8_t crc; |
962 |
963 |
963 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
964 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
964 EC_ERR("Writing EEPROMs only allowed in idle mode!\n"); |
965 EC_ERR("Writing SIIs only allowed in idle mode!\n"); |
965 return -EBUSY; |
966 return -EBUSY; |
966 } |
967 } |
967 |
968 |
968 if (size % 2) { |
969 if (size % 2) { |
969 EC_ERR("EEPROM data size is odd (%u bytes)! SII data must be" |
970 EC_ERR("SII data size is odd (%u bytes)! SII data must be" |
970 " word-aligned. Dropping.\n", size); |
971 " word-aligned. Dropping.\n", size); |
971 return -EINVAL; |
972 return -EINVAL; |
972 } |
973 } |
973 |
974 |
974 // init EEPROM write request |
975 // init SII write request |
975 INIT_LIST_HEAD(&request.list); |
976 INIT_LIST_HEAD(&request.list); |
976 request.slave = slave; |
977 request.slave = slave; |
977 request.data = data; |
978 request.data = data; |
978 request.word_offset = 0; |
979 request.word_offset = 0; |
979 request.word_size = size / 2; |
980 request.word_size = size / 2; |
980 |
981 |
981 if (request.word_size < 0x0041) { |
982 if (request.word_size < 0x0041) { |
982 EC_ERR("EEPROM data too short (%u words)! Mimimum is" |
983 EC_ERR("SII data too short (%u words)! Mimimum is" |
983 " 40 fixed words + 1 delimiter. Dropping.\n", |
984 " 40 fixed words + 1 delimiter. Dropping.\n", |
984 request.word_size); |
985 request.word_size); |
985 return -EINVAL; |
986 return -EINVAL; |
986 } |
987 } |
987 |
988 |
988 // calculate checksum |
989 // calculate checksum |
989 crc = ec_slave_eeprom_crc(data, 14); // CRC over words 0 to 6 |
990 crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6 |
990 if (crc != data[14]) { |
991 if (crc != data[14]) { |
991 EC_WARN("EEPROM CRC incorrect. Must be 0x%02x.\n", crc); |
992 EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc); |
992 } |
993 } |
993 |
994 |
994 cat_header = (const uint16_t *) request.data |
995 cat_header = (const uint16_t *) request.data |
995 + EC_FIRST_EEPROM_CATEGORY_OFFSET; |
996 + EC_FIRST_SII_CATEGORY_OFFSET; |
996 cat_type = EC_READ_U16(cat_header); |
997 cat_type = EC_READ_U16(cat_header); |
997 while (cat_type != 0xFFFF) { // cycle through categories |
998 while (cat_type != 0xFFFF) { // cycle through categories |
998 if (cat_header + 1 > |
999 if (cat_header + 1 > |
999 (const uint16_t *) request.data + request.word_size) { |
1000 (const uint16_t *) request.data + request.word_size) { |
1000 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
1001 EC_ERR("SII data corrupted! Dropping.\n"); |
1001 return -EINVAL; |
1002 return -EINVAL; |
1002 } |
1003 } |
1003 cat_size = EC_READ_U16(cat_header + 1); |
1004 cat_size = EC_READ_U16(cat_header + 1); |
1004 if (cat_header + cat_size + 2 > |
1005 if (cat_header + cat_size + 2 > |
1005 (const uint16_t *) request.data + request.word_size) { |
1006 (const uint16_t *) request.data + request.word_size) { |
1006 EC_ERR("EEPROM data corrupted! Dropping.\n"); |
1007 EC_ERR("SII data corrupted! Dropping.\n"); |
1007 return -EINVAL; |
1008 return -EINVAL; |
1008 } |
1009 } |
1009 cat_header += cat_size + 2; |
1010 cat_header += cat_size + 2; |
1010 cat_type = EC_READ_U16(cat_header); |
1011 cat_type = EC_READ_U16(cat_header); |
1011 } |
1012 } |
1012 |
1013 |
1013 // EEPROM data ok. schedule writing. |
1014 // SII data ok. schedule writing. |
1014 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
1015 if ((ret = ec_slave_schedule_sii_writing(&request))) |
1015 return ret; // error code |
1016 return ret; // error code |
1016 |
1017 |
1017 return size; // success |
1018 return size; // success |
1018 } |
1019 } |
1019 |
1020 |
1020 /*****************************************************************************/ |
1021 /*****************************************************************************/ |
1021 |
1022 |
1022 /** |
1023 /** |
1023 * Writes the Secondary slave address (alias) to the slave's EEPROM. |
1024 * Writes the Secondary slave address (alias) to the slave's SII. |
1024 * \return data size written in case of success, otherwise error code. |
1025 * \return data size written in case of success, otherwise error code. |
1025 */ |
1026 */ |
1026 |
1027 |
1027 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */ |
1028 ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */ |
1028 const uint8_t *data, /**< alias string */ |
1029 const uint8_t *data, /**< alias string */ |
1029 size_t size /**< size of data in bytes */ |
1030 size_t size /**< size of data in bytes */ |
1030 ) |
1031 ) |
1031 { |
1032 { |
1032 ec_eeprom_write_request_t request; |
1033 ec_sii_write_request_t request; |
1033 char *remainder; |
1034 char *remainder; |
1034 uint16_t alias; |
1035 uint16_t alias; |
1035 int ret; |
1036 int ret; |
1036 uint8_t eeprom_data[16], crc; |
1037 uint8_t sii_data[16], crc; |
1037 |
1038 |
1038 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
1039 if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME |
1039 EC_ERR("Writing to EEPROM is only allowed in idle mode!\n"); |
1040 EC_ERR("Writing to SII is only allowed in idle mode!\n"); |
1040 return -EBUSY; |
1041 return -EBUSY; |
1041 } |
1042 } |
1042 |
1043 |
1043 alias = simple_strtoul(data, &remainder, 0); |
1044 alias = simple_strtoul(data, &remainder, 0); |
1044 if (remainder == (char *) data || (*remainder && *remainder != '\n')) { |
1045 if (remainder == (char *) data || (*remainder && *remainder != '\n')) { |
1045 EC_ERR("Invalid alias value! Dropping.\n"); |
1046 EC_ERR("Invalid alias value! Dropping.\n"); |
1046 return -EINVAL; |
1047 return -EINVAL; |
1047 } |
1048 } |
1048 |
1049 |
1049 if (!slave->eeprom_data || slave->eeprom_size < 16) { |
1050 if (!slave->sii_data || slave->sii_size < 16) { |
1050 EC_ERR("Failed to read EEPROM contents from slave %u.\n", |
1051 EC_ERR("Failed to read SII contents from slave %u.\n", |
1051 slave->ring_position); |
1052 slave->ring_position); |
1052 return -EINVAL; |
1053 return -EINVAL; |
1053 } |
1054 } |
1054 |
1055 |
1055 // copy first 7 words of recent EEPROM contents |
1056 // copy first 7 words of recent SII contents |
1056 memcpy(eeprom_data, slave->eeprom_data, 14); |
1057 memcpy(sii_data, slave->sii_data, 14); |
1057 |
1058 |
1058 // write new alias address in word 4 |
1059 // write new alias address in word 4 |
1059 EC_WRITE_U16(eeprom_data + 8, alias); |
1060 EC_WRITE_U16(sii_data + 8, alias); |
1060 |
1061 |
1061 // calculate new checksum over words 0 to 6 |
1062 // calculate new checksum over words 0 to 6 |
1062 crc = ec_slave_eeprom_crc(eeprom_data, 14); |
1063 crc = ec_slave_sii_crc(sii_data, 14); |
1063 EC_WRITE_U16(eeprom_data + 14, crc); |
1064 EC_WRITE_U16(sii_data + 14, crc); |
1064 |
1065 |
1065 // init EEPROM write request |
1066 // init SII write request |
1066 INIT_LIST_HEAD(&request.list); |
1067 INIT_LIST_HEAD(&request.list); |
1067 request.slave = slave; |
1068 request.slave = slave; |
1068 request.data = eeprom_data; |
1069 request.data = sii_data; |
1069 request.word_offset = 0x0000; |
1070 request.word_offset = 0x0000; |
1070 request.word_size = 8; |
1071 request.word_size = 8; |
1071 |
1072 |
1072 if ((ret = ec_slave_schedule_eeprom_writing(&request))) |
1073 if ((ret = ec_slave_schedule_sii_writing(&request))) |
1073 return ret; // error code |
1074 return ret; // error code |
1074 |
1075 |
1075 slave->sii.alias = alias; // FIXME: do this in state machine |
1076 slave->sii.alias = alias; // FIXME: do this in state machine |
1076 |
1077 |
1077 return size; // success |
1078 return size; // success |