tools/Master.cpp
changeset 980 c07dd38243ba
parent 978 2962baf7e6d1
child 982 861eb2810f56
equal deleted inserted replaced
979:405cc2d033e0 980:c07dd38243ba
    11 #include <sys/ioctl.h>
    11 #include <sys/ioctl.h>
    12 
    12 
    13 #include <iostream>
    13 #include <iostream>
    14 #include <iomanip>
    14 #include <iomanip>
    15 #include <sstream>
    15 #include <sstream>
       
    16 #include <fstream>
    16 #include <cctype> // toupper()
    17 #include <cctype> // toupper()
    17 using namespace std;
    18 using namespace std;
    18 
    19 
    19 #include "Master.h"
    20 #include "Master.h"
    20 
    21 
   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 }
   606 
   665 
   607 /****************************************************************************/
   666 /****************************************************************************/
   608 
   667 
   609 void Master::siiRead(int slavePosition)
   668 void Master::siiRead(int slavePosition)
   610 {
   669 {
   611     ec_ioctl_sii_read_t data;
   670     ec_ioctl_sii_t data;
   612     ec_ioctl_slave_t slave;
   671     ec_ioctl_slave_t slave;
   613     unsigned int i;
   672     unsigned int i;
   614 
   673 
   615     if (slavePosition < 0) {
   674     if (slavePosition < 0) {
   616         stringstream err;
   675         stringstream err;
   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 /*****************************************************************************/