114 void Master::setIndex(unsigned int i) |
115 void Master::setIndex(unsigned int i) |
115 { |
116 { |
116 index = i; |
117 index = i; |
117 } |
118 } |
118 |
119 |
|
120 /*****************************************************************************/ |
|
121 |
|
122 /** |
|
123 * Writes the Secondary slave address (alias) to the slave's SII. |
|
124 */ |
|
125 void Master::writeAlias( |
|
126 int slavePosition, |
|
127 bool force, |
|
128 const vector<string> &commandArgs |
|
129 ) |
|
130 { |
|
131 ec_ioctl_sii_t data; |
|
132 ec_ioctl_slave_t slave; |
|
133 unsigned int i; |
|
134 uint16_t alias; |
|
135 stringstream err, strAlias; |
|
136 int number; |
|
137 |
|
138 if (commandArgs.size() != 1) { |
|
139 stringstream err; |
|
140 err << "'alias' takes exactly one argument!"; |
|
141 throw MasterException(err.str()); |
|
142 } |
|
143 |
|
144 strAlias << commandArgs[0]; |
|
145 strAlias >> hex >> number; |
|
146 if (strAlias.fail() || number < 0x0000 || number > 0xffff) { |
|
147 err << "Invalid alias '" << commandArgs[0] << "'!"; |
|
148 throw MasterException(err.str()); |
|
149 } |
|
150 alias = number; |
|
151 |
|
152 if (slavePosition == -1) { |
|
153 unsigned int numSlaves, i; |
|
154 |
|
155 if (!force) { |
|
156 err << "This will write the alias addresses of all slaves to 0x" |
|
157 << hex << setfill('0') << setw(4) << alias << "! " |
|
158 << "Please specify --force to proceed."; |
|
159 throw MasterException(err.str()); |
|
160 } |
|
161 |
|
162 open(ReadWrite); |
|
163 numSlaves = slaveCount(); |
|
164 |
|
165 for (i = 0; i < numSlaves; i++) { |
|
166 writeSlaveAlias(i, alias); |
|
167 } |
|
168 } else { |
|
169 open(ReadWrite); |
|
170 writeSlaveAlias(slavePosition, alias); |
|
171 } |
|
172 } |
|
173 |
119 /****************************************************************************/ |
174 /****************************************************************************/ |
120 |
175 |
121 void Master::outputData(int domainIndex) |
176 void Master::outputData(int domainIndex) |
122 { |
177 { |
123 open(Read); |
178 open(Read); |
195 |
250 |
196 lastAlias = 0; |
251 lastAlias = 0; |
197 aliasIndex = 0; |
252 aliasIndex = 0; |
198 for (i = 0; i < numSlaves; i++) { |
253 for (i = 0; i < numSlaves; i++) { |
199 getSlave(&slave, i); |
254 getSlave(&slave, i); |
200 cout << setw(2) << i << " "; |
255 cout << setfill(' ') << setw(2) << i << " "; |
201 |
256 |
202 if (slave.alias) { |
257 if (slave.alias) { |
203 lastAlias = slave.alias; |
258 lastAlias = slave.alias; |
204 aliasIndex = 0; |
259 aliasIndex = 0; |
205 } |
260 } |
206 if (lastAlias) { |
261 if (lastAlias) { |
207 cout << setw(10) << "#" << lastAlias << ":" << aliasIndex; |
262 cout << "#" |
|
263 << hex << setfill('0') << setw(4) << lastAlias |
|
264 << ":" << dec << aliasIndex; |
|
265 aliasIndex++; |
208 } |
266 } |
209 |
267 |
210 cout << " " << slaveState(slave.state) << " "; |
268 cout << " " << slaveState(slave.state) << " "; |
211 |
269 |
212 if (strlen(slave.name)) { |
270 if (strlen(slave.name)) { |
213 cout << slave.name; |
271 cout << slave.name; |
214 } else { |
272 } else { |
215 cout << "0x" << hex << setfill('0') << slave.vendor_id |
273 cout << hex << setfill('0') |
216 << ":0x" << slave.product_code; |
274 << setw(8) << slave.vendor_id << ":" |
|
275 << setw(8) << slave.product_code << dec; |
217 } |
276 } |
218 |
277 |
219 cout << endl; |
278 cout << endl; |
220 } |
279 } |
221 } |
280 } |
641 uint16_t *w = data.words + i; |
700 uint16_t *w = data.words + i; |
642 cout << *(uint8_t *) w << *((uint8_t *) w + 1); |
701 cout << *(uint8_t *) w << *((uint8_t *) w + 1); |
643 } |
702 } |
644 |
703 |
645 delete [] data.words; |
704 delete [] data.words; |
|
705 } |
|
706 |
|
707 /****************************************************************************/ |
|
708 |
|
709 void Master::siiWrite( |
|
710 int slavePosition, |
|
711 bool force, |
|
712 const vector<string> &commandArgs |
|
713 ) |
|
714 { |
|
715 stringstream err; |
|
716 ec_ioctl_sii_t data; |
|
717 ifstream file; |
|
718 unsigned int byte_size; |
|
719 const uint16_t *categoryHeader; |
|
720 uint16_t categoryType, categorySize; |
|
721 uint8_t crc; |
|
722 |
|
723 if (slavePosition < 0) { |
|
724 err << "'sii_write' requires a slave! Please specify --slave."; |
|
725 throw MasterException(err.str()); |
|
726 } |
|
727 data.slave_position = slavePosition; |
|
728 |
|
729 if (commandArgs.size() != 1) { |
|
730 err << "'ssi_write' takes exactly one argument!"; |
|
731 throw MasterException(err.str()); |
|
732 } |
|
733 |
|
734 file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary); |
|
735 if (file.fail()) { |
|
736 err << "Failed to open '" << commandArgs[0] << "'!"; |
|
737 throw MasterException(err.str()); |
|
738 } |
|
739 |
|
740 // get length of file |
|
741 file.seekg(0, ios::end); |
|
742 byte_size = file.tellg(); |
|
743 file.seekg(0, ios::beg); |
|
744 |
|
745 if (!byte_size || byte_size % 2) { |
|
746 stringstream err; |
|
747 err << "Invalid file size! Must be non-zero and even."; |
|
748 throw MasterException(err.str()); |
|
749 } |
|
750 |
|
751 data.nwords = byte_size / 2; |
|
752 if (data.nwords < 0x0041 && !force) { |
|
753 err << "SII data too short (" << data.nwords << " words)! Mimimum is" |
|
754 " 40 fixed words + 1 delimiter. Use --force to write anyway."; |
|
755 throw MasterException(err.str()); |
|
756 } |
|
757 |
|
758 // allocate buffer and read file into buffer |
|
759 data.words = new uint16_t[data.nwords]; |
|
760 file.read((char *) data.words, byte_size); |
|
761 file.close(); |
|
762 |
|
763 if (!force) { |
|
764 // calculate checksum over words 0 to 6 |
|
765 crc = calcSiiCrc((const uint8_t *) data.words, 14); |
|
766 if (crc != ((const uint8_t *) data.words)[14]) { |
|
767 err << "CRC incorrect. Must be 0x" |
|
768 << hex << setfill('0') << setw(2) << (unsigned int) crc |
|
769 << ". Use --force to write anyway."; |
|
770 throw MasterException(err.str()); |
|
771 } |
|
772 |
|
773 // cycle through categories to detect corruption |
|
774 categoryHeader = data.words + 0x0040; |
|
775 categoryType = le16tocpu(*categoryHeader); |
|
776 while (categoryType != 0xffff) { |
|
777 if (categoryHeader + 1 > data.words + data.nwords) { |
|
778 err << "SII data seem to be corrupted! " |
|
779 << "Use --force to write anyway."; |
|
780 throw MasterException(err.str()); |
|
781 } |
|
782 categorySize = le16tocpu(*(categoryHeader + 1)); |
|
783 if (categoryHeader + categorySize + 2 > data.words + data.nwords) { |
|
784 err << "SII data seem to be corrupted! " |
|
785 "Use --force to write anyway."; |
|
786 throw MasterException(err.str()); |
|
787 } |
|
788 categoryHeader += categorySize + 2; |
|
789 categoryType = le16tocpu(*categoryHeader); |
|
790 } |
|
791 } |
|
792 |
|
793 // send data to master |
|
794 open(ReadWrite); |
|
795 data.offset = 0; |
|
796 if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) { |
|
797 stringstream err; |
|
798 err << "Failed to write SII: " << strerror(errno); |
|
799 throw MasterException(err.str()); |
|
800 } |
646 } |
801 } |
647 |
802 |
648 /****************************************************************************/ |
803 /****************************************************************************/ |
649 |
804 |
650 void Master::requestStates( |
805 void Master::requestStates( |
740 { |
895 { |
741 if (fd == -1) |
896 if (fd == -1) |
742 return; |
897 return; |
743 |
898 |
744 ::close(fd); |
899 ::close(fd); |
|
900 } |
|
901 |
|
902 /*****************************************************************************/ |
|
903 |
|
904 /** |
|
905 * Writes the Secondary slave address (alias) to the slave's SII. |
|
906 */ |
|
907 void Master::writeSlaveAlias( |
|
908 uint16_t slavePosition, |
|
909 uint16_t alias |
|
910 ) |
|
911 { |
|
912 ec_ioctl_sii_t data; |
|
913 ec_ioctl_slave_t slave; |
|
914 stringstream err; |
|
915 uint8_t crc; |
|
916 |
|
917 open(ReadWrite); |
|
918 |
|
919 getSlave(&slave, slavePosition); |
|
920 |
|
921 if (slave.sii_nwords < 8) { |
|
922 err << "Current SII contents are too small to set an alias " |
|
923 << "(" << slave.sii_nwords << " words)!"; |
|
924 throw MasterException(err.str()); |
|
925 } |
|
926 |
|
927 data.slave_position = slavePosition; |
|
928 data.offset = 0; |
|
929 data.nwords = 8; |
|
930 data.words = new uint16_t[data.nwords]; |
|
931 |
|
932 // read first 8 SII words |
|
933 if (ioctl(fd, EC_IOCTL_SII_READ, &data) < 0) { |
|
934 delete [] data.words; |
|
935 err << "Failed to read SII: " << strerror(errno); |
|
936 throw MasterException(err.str()); |
|
937 } |
|
938 |
|
939 // write new alias address in word 4 |
|
940 data.words[4] = cputole16(alias); |
|
941 |
|
942 // calculate checksum over words 0 to 6 |
|
943 crc = calcSiiCrc((const uint8_t *) data.words, 14); |
|
944 |
|
945 // write new checksum into first byte of word 7 |
|
946 *(uint8_t *) (data.words + 7) = crc; |
|
947 |
|
948 // write first 8 words with new alias and checksum |
|
949 if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) { |
|
950 delete [] data.words; |
|
951 err << "Failed to write SII: " << strerror(errno); |
|
952 throw MasterException(err.str()); |
|
953 } |
|
954 |
|
955 delete [] data.words; |
745 } |
956 } |
746 |
957 |
747 /****************************************************************************/ |
958 /****************************************************************************/ |
748 |
959 |
749 void Master::outputDomainData(unsigned int domainIndex) |
960 void Master::outputDomainData(unsigned int domainIndex) |
1328 cout << " "; |
1539 cout << " "; |
1329 } |
1540 } |
1330 cout << endl; |
1541 cout << endl; |
1331 } |
1542 } |
1332 |
1543 |
1333 /****************************************************************************/ |
1544 /*****************************************************************************/ |
|
1545 |
|
1546 /** |
|
1547 * Calculates the SII checksum field. |
|
1548 * |
|
1549 * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an |
|
1550 * initial value of 0xff (see IEC 61158-6-12 ch. 5.4). |
|
1551 * |
|
1552 * The below code was originally generated with PYCRC |
|
1553 * http://www.tty1.net/pycrc |
|
1554 * |
|
1555 * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff |
|
1556 * --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit |
|
1557 * |
|
1558 * \return CRC8 |
|
1559 */ |
|
1560 uint8_t Master::calcSiiCrc( |
|
1561 const uint8_t *data, /**< pointer to data */ |
|
1562 size_t length /**< number of bytes in \a data */ |
|
1563 ) |
|
1564 { |
|
1565 unsigned int i; |
|
1566 uint8_t bit, byte, crc = 0x48; |
|
1567 |
|
1568 while (length--) { |
|
1569 byte = *data++; |
|
1570 for (i = 0; i < 8; i++) { |
|
1571 bit = crc & 0x80; |
|
1572 crc = (crc << 1) | ((byte >> (7 - i)) & 0x01); |
|
1573 if (bit) crc ^= 0x07; |
|
1574 } |
|
1575 } |
|
1576 |
|
1577 for (i = 0; i < 8; i++) { |
|
1578 bit = crc & 0x80; |
|
1579 crc <<= 1; |
|
1580 if (bit) crc ^= 0x07; |
|
1581 } |
|
1582 |
|
1583 return crc; |
|
1584 } |
|
1585 |
|
1586 /*****************************************************************************/ |