fp@922: /***************************************************************************** fp@922: * fp@922: * $Id$ fp@922: * fp@922: ****************************************************************************/ fp@922: fp@922: #include fp@922: #include fp@922: #include fp@922: #include fp@922: #include fp@922: fp@922: #include fp@922: #include fp@922: #include fp@980: #include fp@960: #include // toupper() fp@988: #include fp@922: using namespace std; fp@922: fp@922: #include "Master.h" fp@922: fp@974: #define swap16(x) \ fp@968: ((uint16_t)( \ fp@968: (((uint16_t)(x) & 0x00ffU) << 8) | \ fp@968: (((uint16_t)(x) & 0xff00U) >> 8) )) fp@974: #define swap32(x) \ fp@968: ((uint32_t)( \ fp@968: (((uint32_t)(x) & 0x000000ffUL) << 24) | \ fp@968: (((uint32_t)(x) & 0x0000ff00UL) << 8) | \ fp@968: (((uint32_t)(x) & 0x00ff0000UL) >> 8) | \ fp@968: (((uint32_t)(x) & 0xff000000UL) >> 24) )) fp@968: fp@974: #if __BYTE_ORDER == __LITTLE_ENDIAN fp@974: fp@974: #define le16tocpu(x) x fp@974: #define le32tocpu(x) x fp@974: fp@974: #define cputole16(x) x fp@974: #define cputole32(x) x fp@974: fp@974: #elif __BYTE_ORDER == __BIG_ENDIAN fp@974: fp@974: #define le16tocpu(x) swap16(x) fp@974: #define le32tocpu(x) swap32(x) fp@974: fp@974: #define cputole16(x) swap16(x) fp@974: #define cputole32(x) swap32(x) fp@974: fp@968: #endif fp@968: fp@968: /****************************************************************************/ fp@968: fp@968: struct CoEDataType { fp@968: const char *name; fp@968: uint16_t coeCode; fp@968: unsigned int byteSize; fp@968: }; fp@968: fp@968: static const CoEDataType dataTypes[] = { fp@968: {"int8", 0x0002, 1}, fp@968: {"int16", 0x0003, 2}, fp@968: {"int32", 0x0004, 4}, fp@968: {"uint8", 0x0005, 1}, fp@968: {"uint16", 0x0006, 2}, fp@968: {"uint32", 0x0007, 4}, fp@968: {"string", 0x0009, 0}, fp@968: {"raw", 0xffff, 0}, fp@968: {} fp@968: }; fp@968: fp@968: /****************************************************************************/ fp@968: fp@968: const CoEDataType *findDataType(const string &str) fp@968: { fp@968: const CoEDataType *d; fp@968: fp@968: for (d = dataTypes; d->name; d++) fp@968: if (str == d->name) fp@968: return d; fp@968: fp@968: return NULL; fp@968: } fp@968: fp@968: /****************************************************************************/ fp@968: fp@968: const CoEDataType *findDataType(uint16_t code) fp@968: { fp@968: const CoEDataType *d; fp@968: fp@968: for (d = dataTypes; d->name; d++) fp@968: if (code == d->coeCode) fp@968: return d; fp@968: fp@968: return NULL; fp@968: } fp@968: fp@922: /****************************************************************************/ fp@922: fp@922: Master::Master() fp@922: { fp@922: index = 0; fp@922: fd = -1; fp@922: } fp@922: fp@922: /****************************************************************************/ fp@922: fp@922: Master::~Master() fp@922: { fp@922: close(); fp@922: } fp@922: fp@922: /****************************************************************************/ fp@922: fp@972: void Master::setIndex(unsigned int i) fp@972: { fp@972: index = i; fp@922: } fp@922: fp@980: /*****************************************************************************/ fp@980: fp@980: /** fp@980: * Writes the Secondary slave address (alias) to the slave's SII. fp@980: */ fp@980: void Master::writeAlias( fp@980: int slavePosition, fp@980: bool force, fp@980: const vector &commandArgs fp@980: ) fp@980: { fp@980: ec_ioctl_sii_t data; fp@980: ec_ioctl_slave_t slave; fp@980: unsigned int i; fp@980: uint16_t alias; fp@980: stringstream err, strAlias; fp@980: int number; fp@980: fp@980: if (commandArgs.size() != 1) { fp@980: stringstream err; fp@980: err << "'alias' takes exactly one argument!"; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: strAlias << commandArgs[0]; fp@980: strAlias >> hex >> number; fp@980: if (strAlias.fail() || number < 0x0000 || number > 0xffff) { fp@980: err << "Invalid alias '" << commandArgs[0] << "'!"; fp@980: throw MasterException(err.str()); fp@980: } fp@980: alias = number; fp@980: fp@980: if (slavePosition == -1) { fp@980: unsigned int numSlaves, i; fp@980: fp@980: if (!force) { fp@980: err << "This will write the alias addresses of all slaves to 0x" fp@980: << hex << setfill('0') << setw(4) << alias << "! " fp@980: << "Please specify --force to proceed."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: open(ReadWrite); fp@980: numSlaves = slaveCount(); fp@980: fp@980: for (i = 0; i < numSlaves; i++) { fp@980: writeSlaveAlias(i, alias); fp@980: } fp@980: } else { fp@980: open(ReadWrite); fp@980: writeSlaveAlias(slavePosition, alias); fp@980: } fp@980: } fp@980: fp@990: /*****************************************************************************/ fp@990: fp@990: /** fp@990: * Lists the bus configuration. fp@990: */ fp@990: void Master::showConfig() fp@990: { fp@990: ec_ioctl_master_t master; fp@990: unsigned int i, j, k, l; fp@990: ec_ioctl_config_t config; fp@990: ec_ioctl_config_pdo_t pdo; fp@990: ec_ioctl_config_pdo_entry_t entry; fp@990: ec_ioctl_config_sdo_t sdo; fp@990: fp@990: open(Read); fp@990: getMaster(&master); fp@990: fp@990: for (i = 0; i < master.config_count; i++) { fp@990: getConfig(&config, i); fp@990: fp@990: cout << "Alias: 0x" fp@990: << hex << setfill('0') << setw(4) << config.alias << endl fp@990: << "Position: " << dec << config.position << endl fp@990: << "Vendor Id: 0x" fp@990: << hex << setw(8) << config.vendor_id << endl fp@990: << "Product code: 0x" fp@990: << hex << setw(8) << config.product_code << endl fp@990: << "Attached: " << (config.attached ? "yes" : "no") << endl; fp@990: fp@990: for (j = 0; j < 2; j++) { fp@990: if (config.pdo_count[j]) { fp@990: cout << (j ? "Input" : "Output") fp@990: << " Pdo assignment / mapping " << endl; fp@990: for (k = 0; k < config.pdo_count[j]; k++) { fp@990: getConfigPdo(&pdo, i, j, k); fp@990: fp@990: cout << " Pdo 0x" fp@990: << hex << setfill('0') << setw(4) << pdo.index fp@990: << " \"" << pdo.name << "\"" << endl; fp@990: fp@990: for (l = 0; l < pdo.entry_count; l++) { fp@990: getConfigPdoEntry(&entry, i, j, k, l); fp@990: fp@990: cout << " Pdo entry 0x" fp@990: << hex << setfill('0') << setw(4) << entry.index fp@990: << ":" << setw(2) << (unsigned int) entry.subindex fp@990: << ", " << dec << (unsigned int) entry.bit_length fp@990: << " bit, \"" << entry.name << "\"" << endl; fp@990: } fp@990: } fp@990: } fp@990: } fp@990: fp@990: if (config.sdo_count) { fp@990: cout << "Sdo configuration:" << endl; fp@990: for (j = 0; j < config.sdo_count; j++) { fp@990: getConfigSdo(&sdo, i, j); fp@990: fp@990: cout << " 0x" fp@990: << hex << setfill('0') << setw(4) << sdo.index fp@990: << ":" << setw(2) << (unsigned int) sdo.subindex fp@990: << ", " << sdo.size << " byte: " << hex; fp@990: fp@990: switch (sdo.size) { fp@990: case 1: fp@990: cout << "0x" << setw(2) fp@990: << (unsigned int) *(uint8_t *) &sdo.data; fp@990: break; fp@990: case 2: fp@990: cout << "0x" << setw(4) fp@990: << le16tocpu(*(uint16_t *) &sdo.data); fp@990: break; fp@990: case 4: fp@990: cout << "0x" << setw(8) fp@990: << le32tocpu(*(uint32_t *) &sdo.data); fp@990: break; fp@990: default: fp@990: cout << "???"; fp@990: } fp@990: fp@990: cout << endl; fp@990: } fp@990: } fp@990: fp@990: cout << endl; fp@990: } fp@990: } fp@990: fp@922: /****************************************************************************/ fp@922: fp@949: void Master::outputData(int domainIndex) fp@949: { fp@972: open(Read); fp@972: fp@949: if (domainIndex == -1) { fp@1001: unsigned int i; fp@1001: ec_ioctl_master_t master; fp@1001: fp@1001: getMaster(&master); fp@1001: fp@1001: for (i = 0; i < master.domain_count; i++) { fp@949: outputDomainData(i); fp@949: } fp@949: } else { fp@949: outputDomainData(domainIndex); fp@949: } fp@949: } fp@949: fp@949: /****************************************************************************/ fp@949: fp@956: void Master::setDebug(const vector &commandArgs) fp@956: { fp@956: stringstream str; fp@956: int debugLevel; fp@956: fp@956: if (commandArgs.size() != 1) { fp@956: stringstream err; fp@956: err << "'debug' takes exactly one argument!"; fp@956: throw MasterException(err.str()); fp@956: } fp@956: fp@956: str << commandArgs[0]; fp@956: str >> debugLevel; fp@956: fp@956: if (str.fail()) { fp@956: stringstream err; fp@956: err << "Invalid debug level '" << commandArgs[0] << "'!"; fp@956: throw MasterException(err.str()); fp@956: } fp@956: fp@972: open(ReadWrite); fp@972: fp@957: if (ioctl(fd, EC_IOCTL_SET_DEBUG, debugLevel) < 0) { fp@956: stringstream err; fp@956: err << "Failed to set debug level: " << strerror(errno); fp@956: throw MasterException(err.str()); fp@956: } fp@956: } fp@956: fp@956: /****************************************************************************/ fp@956: fp@948: void Master::showDomains(int domainIndex) fp@948: { fp@972: open(Read); fp@972: fp@948: if (domainIndex == -1) { fp@1001: unsigned int i; fp@1001: ec_ioctl_master_t master; fp@1001: fp@1001: getMaster(&master); fp@1001: fp@1001: for (i = 0; i < master.domain_count; i++) { fp@948: showDomain(i); fp@948: } fp@948: } else { fp@948: showDomain(domainIndex); fp@948: } fp@948: } fp@948: fp@948: /****************************************************************************/ fp@948: fp@988: struct SlaveInfo { fp@988: string pos; fp@988: string alias; fp@988: string relPos; fp@988: string state; fp@988: string flag; fp@988: string name; fp@988: }; fp@988: fp@922: void Master::listSlaves() fp@922: { fp@972: unsigned int numSlaves, i; fp@935: ec_ioctl_slave_t slave; fp@922: uint16_t lastAlias, aliasIndex; fp@988: SlaveInfo slaveInfo; fp@988: typedef list SlaveInfoList; fp@988: SlaveInfoList slaveInfoList; fp@988: SlaveInfoList::const_iterator iter; fp@988: stringstream str; fp@988: unsigned int maxPosWidth = 0, maxAliasWidth = 0, fp@988: maxRelPosWidth = 0, maxStateWidth = 0; fp@922: fp@972: open(Read); fp@972: fp@972: numSlaves = slaveCount(); fp@972: fp@922: lastAlias = 0; fp@922: aliasIndex = 0; fp@922: for (i = 0; i < numSlaves; i++) { fp@935: getSlave(&slave, i); fp@988: fp@988: str << dec << i; fp@988: slaveInfo.pos = str.str(); fp@988: str.clear(); fp@988: str.str(""); fp@935: fp@935: if (slave.alias) { fp@935: lastAlias = slave.alias; fp@922: aliasIndex = 0; fp@922: } fp@922: if (lastAlias) { fp@988: str << "#" << hex << lastAlias; fp@988: slaveInfo.alias = str.str(); fp@988: str.str(""); fp@988: str << ":" << dec << aliasIndex; fp@988: slaveInfo.relPos = str.str(); fp@988: str.str(""); fp@980: aliasIndex++; fp@988: } else { fp@988: slaveInfo.alias = ""; fp@988: slaveInfo.relPos = ""; fp@988: } fp@988: fp@988: slaveInfo.state = slaveState(slave.state); fp@988: slaveInfo.flag = (slave.error_flag ? 'E' : '+'); fp@935: fp@935: if (strlen(slave.name)) { fp@988: slaveInfo.name = slave.name; fp@922: } else { fp@988: str << hex << setfill('0') fp@980: << setw(8) << slave.vendor_id << ":" fp@988: << setw(8) << slave.product_code; fp@988: slaveInfo.name = str.str(); fp@988: str.str(""); fp@988: } fp@988: fp@988: slaveInfoList.push_back(slaveInfo); fp@988: if (slaveInfo.pos.length() > maxPosWidth) fp@988: maxPosWidth = slaveInfo.pos.length(); fp@988: if (slaveInfo.alias.length() > maxAliasWidth) fp@988: maxAliasWidth = slaveInfo.alias.length(); fp@988: if (slaveInfo.relPos.length() > maxRelPosWidth) fp@988: maxRelPosWidth = slaveInfo.relPos.length(); fp@988: if (slaveInfo.state.length() > maxStateWidth) fp@988: maxStateWidth = slaveInfo.state.length(); fp@988: } fp@988: fp@988: for (iter = slaveInfoList.begin(); iter != slaveInfoList.end(); iter++) { fp@988: cout << setfill(' ') << right fp@988: << setw(maxPosWidth) << iter->pos << " " fp@988: << setw(maxAliasWidth) << iter->alias fp@988: << left fp@988: << setw(maxRelPosWidth) << iter->relPos << " " fp@988: << setw(maxStateWidth) << iter->state << " " fp@988: << iter->flag << " " fp@988: << iter->name << endl; fp@922: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@957: void Master::showMaster() fp@957: { fp@957: ec_ioctl_master_t data; fp@957: stringstream err; fp@957: unsigned int i; fp@957: fp@972: open(Read); fp@957: getMaster(&data); fp@957: fp@957: cout fp@957: << "Master" << index << endl fp@1029: << " Phase: "; fp@1029: fp@1029: switch (data.phase) { fp@957: case 0: cout << "Waiting for device..."; break; fp@957: case 1: cout << "Idle"; break; fp@957: case 2: cout << "Operation"; break; fp@957: default: fp@1029: err << "Invalid master phase " << data.phase; fp@957: throw MasterException(err.str()); fp@957: } fp@957: fp@957: cout << endl fp@957: << " Slaves: " << data.slave_count << endl; fp@957: fp@957: for (i = 0; i < 2; i++) { fp@957: cout << " Device" << i << ": "; fp@957: if (data.devices[i].address[0] == 0x00 fp@957: && data.devices[i].address[1] == 0x00 fp@957: && data.devices[i].address[2] == 0x00 fp@957: && data.devices[i].address[3] == 0x00 fp@957: && data.devices[i].address[4] == 0x00 fp@957: && data.devices[i].address[5] == 0x00) { fp@957: cout << "None."; fp@957: } else { fp@957: cout << hex << setfill('0') fp@957: << setw(2) << (unsigned int) data.devices[i].address[0] << ":" fp@957: << setw(2) << (unsigned int) data.devices[i].address[1] << ":" fp@957: << setw(2) << (unsigned int) data.devices[i].address[2] << ":" fp@957: << setw(2) << (unsigned int) data.devices[i].address[3] << ":" fp@957: << setw(2) << (unsigned int) data.devices[i].address[4] << ":" fp@957: << setw(2) << (unsigned int) data.devices[i].address[5] << " (" fp@957: << (data.devices[i].attached ? "attached" : "waiting...") fp@957: << ")" << endl << dec fp@957: << " Tx count: " << data.devices[i].tx_count << endl fp@957: << " Rx count: " << data.devices[i].rx_count; fp@957: } fp@957: cout << endl; fp@957: } fp@957: } fp@957: fp@957: /****************************************************************************/ fp@957: fp@966: void Master::listPdos(int slavePosition, bool quiet) fp@935: { fp@972: open(Read); fp@972: fp@936: if (slavePosition == -1) { fp@936: unsigned int numSlaves = slaveCount(), i; fp@936: fp@936: for (i = 0; i < numSlaves; i++) { fp@966: listSlavePdos(i, quiet, true); fp@936: } fp@936: } else { fp@966: listSlavePdos(slavePosition, quiet, false); fp@966: } fp@966: } fp@966: fp@966: /****************************************************************************/ fp@966: fp@966: void Master::listSdos(int slavePosition, bool quiet) fp@965: { fp@972: open(Read); fp@972: fp@965: if (slavePosition == -1) { fp@965: unsigned int numSlaves = slaveCount(), i; fp@965: fp@965: for (i = 0; i < numSlaves; i++) { fp@966: listSlaveSdos(i, quiet, true); fp@965: } fp@965: } else { fp@966: listSlaveSdos(slavePosition, quiet, false); fp@965: } fp@965: } fp@965: fp@965: /****************************************************************************/ fp@965: fp@974: void Master::sdoDownload( fp@974: int slavePosition, fp@974: const string &dataTypeStr, fp@974: const vector &commandArgs fp@974: ) fp@974: { fp@974: stringstream strIndex, strSubIndex, strValue, err; fp@974: int number, sval; fp@974: ec_ioctl_sdo_download_t data; fp@974: unsigned int i, uval; fp@974: const CoEDataType *dataType = NULL; fp@974: fp@974: if (slavePosition < 0) { fp@974: err << "'sdo_download' requires a slave! Please specify --slave."; fp@974: throw MasterException(err.str()); fp@974: } fp@974: data.slave_position = slavePosition; fp@974: fp@974: if (commandArgs.size() != 3) { fp@974: err << "'sdo_download' takes 3 arguments!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: fp@974: strIndex << commandArgs[0]; fp@974: strIndex >> hex >> number; fp@974: if (strIndex.fail() || number < 0x0000 || number > 0xffff) { fp@974: err << "Invalid Sdo index '" << commandArgs[0] << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: data.sdo_index = number; fp@974: fp@974: strSubIndex << commandArgs[1]; fp@974: strSubIndex >> hex >> number; fp@974: if (strSubIndex.fail() || number < 0x00 || number > 0xff) { fp@974: err << "Invalid Sdo subindex '" << commandArgs[1] << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: data.sdo_entry_subindex = number; fp@974: fp@974: if (dataTypeStr != "") { // data type specified fp@974: if (!(dataType = findDataType(dataTypeStr))) { fp@974: err << "Invalid data type '" << dataTypeStr << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: } else { // no data type specified: fetch from dictionary fp@974: ec_ioctl_sdo_entry_t entry; fp@974: unsigned int entryByteSize; fp@974: fp@982: open(ReadWrite); fp@974: fp@974: try { fp@974: getSdoEntry(&entry, slavePosition, fp@974: data.sdo_index, data.sdo_entry_subindex); fp@974: } catch (MasterException &e) { fp@974: err << "Failed to determine Sdo entry data type. " fp@974: << "Please specify --type."; fp@974: throw MasterException(err.str()); fp@974: } fp@974: if (!(dataType = findDataType(entry.data_type))) { fp@974: err << "Pdo entry has unknown data type 0x" fp@974: << hex << setfill('0') << setw(4) << entry.data_type << "!" fp@974: << " Please specify --type."; fp@974: throw MasterException(err.str()); fp@974: } fp@974: } fp@974: fp@974: if (dataType->byteSize) { fp@974: data.data_size = dataType->byteSize; fp@974: } else { fp@974: data.data_size = DefaultBufferSize; fp@974: } fp@974: fp@974: data.data = new uint8_t[data.data_size + 1]; fp@974: fp@974: strValue << commandArgs[2]; fp@974: fp@974: switch (dataType->coeCode) { fp@974: case 0x0002: // int8 fp@974: strValue >> sval; fp@974: if ((uint32_t) sval > 0xff) { fp@974: delete [] data.data; fp@974: err << "Invalid value for type '" fp@974: << dataType->name << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: *data.data = (int8_t) sval; fp@974: break; fp@974: case 0x0003: // int16 fp@974: strValue >> sval; fp@974: if ((uint32_t) sval > 0xffff) { fp@974: delete [] data.data; fp@974: err << "Invalid value for type '" fp@974: << dataType->name << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: *(int16_t *) data.data = cputole16(sval); fp@974: break; fp@974: case 0x0004: // int32 fp@974: strValue >> sval; fp@974: *(int32_t *) data.data = cputole32(sval); fp@974: break; fp@974: case 0x0005: // uint8 fp@974: strValue >> uval; fp@974: if ((uint32_t) uval > 0xff) { fp@974: delete [] data.data; fp@974: err << "Invalid value for type '" fp@974: << dataType->name << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: *data.data = (uint8_t) uval; fp@974: break; fp@974: case 0x0006: // uint16 fp@974: strValue >> uval; fp@974: if ((uint32_t) uval > 0xffff) { fp@974: delete [] data.data; fp@974: err << "Invalid value for type '" fp@974: << dataType->name << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: *(uint16_t *) data.data = cputole16(uval); fp@974: break; fp@974: case 0x0007: // uint32 fp@974: strValue >> uval; fp@974: *(uint32_t *) data.data = cputole32(uval); fp@974: break; fp@974: case 0x0009: // string fp@974: if (strValue.str().size() >= data.data_size) { fp@974: err << "String too big"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: data.data_size = strValue.str().size(); fp@974: strValue >> (char *) data.data; fp@974: break; fp@974: default: fp@974: break; fp@974: } fp@974: fp@974: if (strValue.fail()) { fp@974: err << "Invalid value argument '" << commandArgs[2] << "'!"; fp@974: throw MasterException(err.str()); fp@974: } fp@974: fp@974: open(ReadWrite); fp@974: fp@974: if (ioctl(fd, EC_IOCTL_SDO_DOWNLOAD, &data) < 0) { fp@974: stringstream err; fp@974: err << "Failed to download Sdo: " << strerror(errno); fp@974: delete [] data.data; fp@974: throw MasterException(err.str()); fp@974: } fp@974: fp@974: delete [] data.data; fp@974: } fp@974: fp@974: /****************************************************************************/ fp@974: fp@968: void Master::sdoUpload( fp@968: int slavePosition, fp@968: const string &dataTypeStr, fp@968: const vector &commandArgs fp@968: ) fp@968: { fp@968: stringstream strIndex, strSubIndex; fp@968: int number, sval; fp@968: ec_ioctl_sdo_upload_t data; fp@968: unsigned int i, uval; fp@968: const CoEDataType *dataType = NULL; fp@968: fp@968: if (slavePosition < 0) { fp@968: stringstream err; fp@968: err << "'sdo_upload' requires a slave! Please specify --slave."; fp@968: throw MasterException(err.str()); fp@968: } fp@968: data.slave_position = slavePosition; fp@968: fp@968: if (commandArgs.size() != 2) { fp@968: stringstream err; fp@968: err << "'sdo_upload' takes two arguments!"; fp@968: throw MasterException(err.str()); fp@968: } fp@968: fp@968: strIndex << commandArgs[0]; fp@968: strIndex >> hex >> number; fp@968: if (strIndex.fail() || number < 0x0000 || number > 0xffff) { fp@968: stringstream err; fp@968: err << "Invalid Sdo index '" << commandArgs[0] << "'!"; fp@968: throw MasterException(err.str()); fp@968: } fp@968: data.sdo_index = number; fp@968: fp@968: strSubIndex << commandArgs[1]; fp@968: strSubIndex >> hex >> number; fp@968: if (strSubIndex.fail() || number < 0x00 || number > 0xff) { fp@968: stringstream err; fp@968: err << "Invalid Sdo subindex '" << commandArgs[1] << "'!"; fp@968: throw MasterException(err.str()); fp@968: } fp@968: data.sdo_entry_subindex = number; fp@968: fp@968: if (dataTypeStr != "") { // data type specified fp@968: if (!(dataType = findDataType(dataTypeStr))) { fp@968: stringstream err; fp@968: err << "Invalid data type '" << dataTypeStr << "'!"; fp@968: throw MasterException(err.str()); fp@968: } fp@968: } else { // no data type specified: fetch from dictionary fp@968: ec_ioctl_sdo_entry_t entry; fp@968: unsigned int entryByteSize; fp@972: fp@972: open(Read); fp@972: fp@968: try { fp@968: getSdoEntry(&entry, slavePosition, fp@968: data.sdo_index, data.sdo_entry_subindex); fp@968: } catch (MasterException &e) { fp@968: stringstream err; fp@968: err << "Failed to determine Sdo entry data type. " fp@968: << "Please specify --type."; fp@968: throw MasterException(err.str()); fp@968: } fp@968: if (!(dataType = findDataType(entry.data_type))) { fp@968: stringstream err; fp@968: err << "Pdo entry has unknown data type 0x" fp@968: << hex << setfill('0') << setw(4) << entry.data_type << "!" fp@968: << " Please specify --type."; fp@968: throw MasterException(err.str()); fp@968: } fp@968: } fp@968: fp@968: if (dataType->byteSize) { fp@968: data.target_size = dataType->byteSize; fp@968: } else { fp@974: data.target_size = DefaultBufferSize; fp@968: } fp@968: fp@968: data.target = new uint8_t[data.target_size + 1]; fp@968: fp@972: open(Read); fp@972: fp@968: if (ioctl(fd, EC_IOCTL_SDO_UPLOAD, &data) < 0) { fp@968: stringstream err; fp@968: err << "Failed to upload Sdo: " << strerror(errno); fp@968: delete [] data.target; fp@972: close(); fp@972: throw MasterException(err.str()); fp@972: } fp@972: fp@972: close(); fp@968: fp@968: if (dataType->byteSize && data.data_size != dataType->byteSize) { fp@968: stringstream err; fp@968: err << "Data type mismatch. Expected " << dataType->name fp@970: << " with " << dataType->byteSize << " byte, but got " fp@970: << data.data_size << " byte."; fp@968: throw MasterException(err.str()); fp@968: } fp@968: fp@968: cout << setfill('0'); fp@968: switch (dataType->coeCode) { fp@968: case 0x0002: // int8 fp@968: sval = *(int8_t *) data.target; fp@968: cout << sval << " 0x" << hex << setw(2) << sval << endl; fp@968: break; fp@968: case 0x0003: // int16 fp@968: sval = le16tocpu(*(int16_t *) data.target); fp@968: cout << sval << " 0x" << hex << setw(4) << sval << endl; fp@968: break; fp@968: case 0x0004: // int32 fp@968: sval = le32tocpu(*(int32_t *) data.target); fp@968: cout << sval << " 0x" << hex << setw(8) << sval << endl; fp@968: break; fp@968: case 0x0005: // uint8 fp@968: uval = (unsigned int) *(uint8_t *) data.target; fp@968: cout << uval << " 0x" << hex << setw(2) << uval << endl; fp@968: break; fp@968: case 0x0006: // uint16 fp@968: uval = le16tocpu(*(uint16_t *) data.target); fp@968: cout << uval << " 0x" << hex << setw(4) << uval << endl; fp@968: break; fp@968: case 0x0007: // uint32 fp@968: uval = le32tocpu(*(uint32_t *) data.target); fp@968: cout << uval << " 0x" << hex << setw(8) << uval << endl; fp@968: break; fp@968: case 0x0009: // string fp@968: cout << string((const char *) data.target, data.data_size) fp@968: << endl; fp@968: break; fp@968: default: fp@968: printRawData(data.target, data.data_size); fp@968: break; fp@968: } fp@968: fp@968: delete [] data.target; fp@968: } fp@968: fp@968: /****************************************************************************/ fp@968: fp@989: void Master::showSlaves(int slavePosition) fp@989: { fp@989: open(Read); fp@989: fp@989: if (slavePosition == -1) { fp@989: unsigned int numSlaves = slaveCount(), i; fp@989: fp@989: for (i = 0; i < numSlaves; i++) { fp@989: showSlave(i); fp@989: } fp@989: } else { fp@989: showSlave(slavePosition); fp@989: } fp@989: } fp@989: fp@989: /****************************************************************************/ fp@989: fp@978: void Master::siiRead(int slavePosition) fp@978: { fp@980: ec_ioctl_sii_t data; fp@978: ec_ioctl_slave_t slave; fp@978: unsigned int i; fp@978: fp@978: if (slavePosition < 0) { fp@978: stringstream err; fp@978: err << "'sii_read' requires a slave! Please specify --slave."; fp@978: throw MasterException(err.str()); fp@978: } fp@978: data.slave_position = slavePosition; fp@978: fp@978: open(Read); fp@978: fp@978: getSlave(&slave, slavePosition); fp@978: fp@978: if (!slave.sii_nwords) fp@978: return; fp@978: fp@978: data.offset = 0; fp@978: data.nwords = slave.sii_nwords; fp@978: data.words = new uint16_t[data.nwords]; fp@978: fp@978: if (ioctl(fd, EC_IOCTL_SII_READ, &data) < 0) { fp@978: stringstream err; fp@978: delete [] data.words; fp@978: err << "Failed to read SII: " << strerror(errno); fp@978: throw MasterException(err.str()); fp@978: } fp@978: fp@978: for (i = 0; i < data.nwords; i++) { fp@978: uint16_t *w = data.words + i; fp@978: cout << *(uint8_t *) w << *((uint8_t *) w + 1); fp@978: } fp@978: fp@978: delete [] data.words; fp@978: } fp@978: fp@978: /****************************************************************************/ fp@978: fp@980: void Master::siiWrite( fp@980: int slavePosition, fp@980: bool force, fp@980: const vector &commandArgs fp@980: ) fp@980: { fp@980: stringstream err; fp@980: ec_ioctl_sii_t data; fp@980: ifstream file; fp@980: unsigned int byte_size; fp@980: const uint16_t *categoryHeader; fp@980: uint16_t categoryType, categorySize; fp@980: uint8_t crc; fp@980: fp@980: if (slavePosition < 0) { fp@980: err << "'sii_write' requires a slave! Please specify --slave."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: data.slave_position = slavePosition; fp@980: fp@980: if (commandArgs.size() != 1) { fp@980: err << "'ssi_write' takes exactly one argument!"; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary); fp@980: if (file.fail()) { fp@980: err << "Failed to open '" << commandArgs[0] << "'!"; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: // get length of file fp@980: file.seekg(0, ios::end); fp@980: byte_size = file.tellg(); fp@980: file.seekg(0, ios::beg); fp@980: fp@980: if (!byte_size || byte_size % 2) { fp@980: stringstream err; fp@980: err << "Invalid file size! Must be non-zero and even."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: data.nwords = byte_size / 2; fp@980: if (data.nwords < 0x0041 && !force) { fp@980: err << "SII data too short (" << data.nwords << " words)! Mimimum is" fp@980: " 40 fixed words + 1 delimiter. Use --force to write anyway."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: // allocate buffer and read file into buffer fp@980: data.words = new uint16_t[data.nwords]; fp@980: file.read((char *) data.words, byte_size); fp@980: file.close(); fp@980: fp@980: if (!force) { fp@980: // calculate checksum over words 0 to 6 fp@980: crc = calcSiiCrc((const uint8_t *) data.words, 14); fp@980: if (crc != ((const uint8_t *) data.words)[14]) { fp@980: err << "CRC incorrect. Must be 0x" fp@980: << hex << setfill('0') << setw(2) << (unsigned int) crc fp@980: << ". Use --force to write anyway."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: // cycle through categories to detect corruption fp@980: categoryHeader = data.words + 0x0040; fp@980: categoryType = le16tocpu(*categoryHeader); fp@980: while (categoryType != 0xffff) { fp@980: if (categoryHeader + 1 > data.words + data.nwords) { fp@980: err << "SII data seem to be corrupted! " fp@980: << "Use --force to write anyway."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: categorySize = le16tocpu(*(categoryHeader + 1)); fp@980: if (categoryHeader + categorySize + 2 > data.words + data.nwords) { fp@980: err << "SII data seem to be corrupted! " fp@980: "Use --force to write anyway."; fp@980: throw MasterException(err.str()); fp@980: } fp@980: categoryHeader += categorySize + 2; fp@980: categoryType = le16tocpu(*categoryHeader); fp@980: } fp@980: } fp@980: fp@980: // send data to master fp@980: open(ReadWrite); fp@980: data.offset = 0; fp@980: if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) { fp@980: stringstream err; fp@980: err << "Failed to write SII: " << strerror(errno); fp@980: throw MasterException(err.str()); fp@980: } fp@980: } fp@980: fp@980: /****************************************************************************/ fp@980: fp@960: void Master::requestStates( fp@960: int slavePosition, fp@960: const vector &commandArgs fp@960: ) fp@960: { fp@960: string stateStr; fp@960: uint8_t state; fp@960: fp@960: if (commandArgs.size() != 1) { fp@960: stringstream err; fp@960: err << "'state' takes exactly one argument!"; fp@960: throw MasterException(err.str()); fp@960: } fp@960: fp@960: stateStr = commandArgs[0]; fp@960: transform(stateStr.begin(), stateStr.end(), fp@960: stateStr.begin(), (int (*) (int)) std::toupper); fp@960: fp@960: if (stateStr == "INIT") { fp@960: state = 0x01; fp@960: } else if (stateStr == "PREOP") { fp@960: state = 0x02; fp@960: } else if (stateStr == "SAFEOP") { fp@960: state = 0x04; fp@960: } else if (stateStr == "OP") { fp@960: state = 0x08; fp@960: } else { fp@960: stringstream err; fp@960: err << "Invalid state '" << commandArgs[0] << "'!"; fp@960: throw MasterException(err.str()); fp@960: } fp@960: fp@972: open(ReadWrite); fp@972: fp@960: if (slavePosition == -1) { fp@960: unsigned int i, numSlaves = slaveCount(); fp@960: for (i = 0; i < numSlaves; i++) fp@960: requestState(i, state); fp@960: } else { fp@960: requestState(slavePosition, state); fp@960: } fp@960: } fp@960: fp@960: /****************************************************************************/ fp@960: fp@938: void Master::generateXml(int slavePosition) fp@938: { fp@972: open(Read); fp@972: fp@938: if (slavePosition == -1) { fp@938: unsigned int numSlaves = slaveCount(), i; fp@938: fp@938: for (i = 0; i < numSlaves; i++) { fp@938: generateSlaveXml(i); fp@938: } fp@938: } else { fp@938: generateSlaveXml(slavePosition); fp@938: } fp@938: } fp@938: fp@938: /****************************************************************************/ fp@938: fp@972: void Master::open(Permissions perm) fp@972: { fp@972: stringstream deviceName; fp@972: fp@972: if (fd != -1) { // already open fp@982: return; fp@972: } fp@972: fp@972: deviceName << "/dev/EtherCAT" << index; fp@972: fp@972: if ((fd = ::open(deviceName.str().c_str(), fp@972: perm == ReadWrite ? O_RDWR : O_RDONLY)) == -1) { fp@972: stringstream err; fp@972: err << "Failed to open master device " << deviceName.str() << ": " fp@972: << strerror(errno); fp@972: throw MasterException(err.str()); fp@972: } fp@972: } fp@972: fp@972: /****************************************************************************/ fp@972: fp@972: void Master::close() fp@972: { fp@972: if (fd == -1) fp@972: return; fp@972: fp@972: ::close(fd); fp@982: fd = -1; fp@972: } fp@972: fp@980: /*****************************************************************************/ fp@980: fp@980: /** fp@980: * Writes the Secondary slave address (alias) to the slave's SII. fp@980: */ fp@980: void Master::writeSlaveAlias( fp@980: uint16_t slavePosition, fp@980: uint16_t alias fp@980: ) fp@980: { fp@980: ec_ioctl_sii_t data; fp@980: ec_ioctl_slave_t slave; fp@980: stringstream err; fp@980: uint8_t crc; fp@980: fp@980: open(ReadWrite); fp@980: fp@980: getSlave(&slave, slavePosition); fp@980: fp@980: if (slave.sii_nwords < 8) { fp@980: err << "Current SII contents are too small to set an alias " fp@980: << "(" << slave.sii_nwords << " words)!"; fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: data.slave_position = slavePosition; fp@980: data.offset = 0; fp@980: data.nwords = 8; fp@980: data.words = new uint16_t[data.nwords]; fp@980: fp@980: // read first 8 SII words fp@980: if (ioctl(fd, EC_IOCTL_SII_READ, &data) < 0) { fp@980: delete [] data.words; fp@980: err << "Failed to read SII: " << strerror(errno); fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: // write new alias address in word 4 fp@980: data.words[4] = cputole16(alias); fp@980: fp@980: // calculate checksum over words 0 to 6 fp@980: crc = calcSiiCrc((const uint8_t *) data.words, 14); fp@980: fp@980: // write new checksum into first byte of word 7 fp@980: *(uint8_t *) (data.words + 7) = crc; fp@980: fp@980: // write first 8 words with new alias and checksum fp@980: if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) { fp@980: delete [] data.words; fp@980: err << "Failed to write SII: " << strerror(errno); fp@980: throw MasterException(err.str()); fp@980: } fp@980: fp@980: delete [] data.words; fp@980: } fp@980: fp@972: /****************************************************************************/ fp@972: fp@949: void Master::outputDomainData(unsigned int domainIndex) fp@949: { fp@949: ec_ioctl_domain_t domain; fp@949: ec_ioctl_data_t data; fp@949: unsigned char *processData; fp@949: unsigned int i; fp@949: fp@949: getDomain(&domain, domainIndex); fp@949: fp@950: if (!domain.data_size) fp@950: return; fp@950: fp@949: processData = new unsigned char[domain.data_size]; fp@949: fp@950: try { fp@950: getData(&data, domainIndex, domain.data_size, processData); fp@950: } catch (MasterException &e) { fp@949: delete [] processData; fp@950: throw e; fp@949: } fp@949: fp@949: for (i = 0; i < data.data_size; i++) fp@949: cout << processData[i]; fp@949: cout.flush(); fp@949: fp@949: delete [] processData; fp@949: } fp@949: fp@949: /****************************************************************************/ fp@949: fp@948: void Master::showDomain(unsigned int domainIndex) fp@948: { fp@950: ec_ioctl_domain_t domain; fp@950: unsigned char *processData; fp@950: ec_ioctl_data_t data; fp@950: unsigned int i, j; fp@950: ec_ioctl_domain_fmmu_t fmmu; fp@950: unsigned int dataOffset; fp@948: fp@950: getDomain(&domain, domainIndex); fp@948: fp@948: cout << "Domain" << domainIndex << ":" fp@948: << " LogBaseAddr 0x" fp@950: << hex << setfill('0') << setw(8) << domain.logical_base_address fp@950: << ", Size " << dec << setfill(' ') << setw(3) << domain.data_size fp@948: << ", WorkingCounter " fp@951: << dec << domain.working_counter << "/" fp@951: << domain.expected_working_counter << endl; fp@950: fp@950: if (!domain.data_size) fp@950: return; fp@950: fp@950: processData = new unsigned char[domain.data_size]; fp@950: fp@950: try { fp@950: getData(&data, domainIndex, domain.data_size, processData); fp@950: } catch (MasterException &e) { fp@950: delete [] processData; fp@950: throw e; fp@950: } fp@950: fp@950: for (i = 0; i < domain.fmmu_count; i++) { fp@950: getFmmu(&fmmu, domainIndex, i); fp@950: fp@951: cout << " SlaveConfig " fp@951: << fmmu.slave_config_alias << ":" << fmmu.slave_config_position fp@951: << ", Dir " fp@951: << setfill(' ') << setw(3) << (fmmu.fmmu_dir ? "In" : "Out") fp@950: << ", LogAddr 0x" fp@950: << hex << setfill('0') << setw(8) << fmmu.logical_address fp@951: << ", Size " << dec << fmmu.data_size << endl; fp@950: fp@950: dataOffset = fmmu.logical_address - domain.logical_base_address; fp@950: if (dataOffset + fmmu.data_size > domain.data_size) { fp@950: stringstream err; fp@950: err << "Fmmu information corrupted!"; fp@950: delete [] processData; fp@950: throw MasterException(err.str()); fp@950: } fp@950: fp@950: cout << " " << hex << setfill('0'); fp@950: for (j = 0; j < fmmu.data_size; j++) { fp@950: cout << setw(2) fp@950: << (unsigned int) *(processData + dataOffset + j) << " "; fp@950: } fp@950: cout << endl; fp@950: } fp@950: fp@950: delete [] processData; fp@948: } fp@948: fp@948: /****************************************************************************/ fp@948: fp@966: void Master::listSlavePdos( fp@966: uint16_t slavePosition, fp@966: bool quiet, fp@966: bool withHeader fp@966: ) fp@936: { fp@935: ec_ioctl_slave_t slave; fp@935: ec_ioctl_sync_t sync; fp@935: ec_ioctl_pdo_t pdo; fp@935: ec_ioctl_pdo_entry_t entry; fp@935: unsigned int i, j, k; fp@935: fp@935: getSlave(&slave, slavePosition); fp@935: fp@965: if (withHeader) fp@936: cout << "=== Slave " << slavePosition << " ===" << endl; fp@936: fp@935: for (i = 0; i < slave.sync_count; i++) { fp@935: getSync(&sync, slavePosition, i); fp@935: fp@935: cout << "SM" << i << ":" fp@935: << " PhysAddr 0x" fp@935: << hex << setfill('0') << setw(4) << sync.physical_start_address fp@935: << ", DefaultSize " fp@935: << dec << setfill(' ') << setw(4) << sync.default_size fp@935: << ", ControlRegister 0x" fp@935: << hex << setfill('0') << setw(2) fp@935: << (unsigned int) sync.control_register fp@935: << ", Enable " << dec << (unsigned int) sync.enable fp@935: << endl; fp@935: fp@935: for (j = 0; j < sync.pdo_count; j++) { fp@935: getPdo(&pdo, slavePosition, i, j); fp@935: fp@935: cout << " " << (pdo.dir ? "T" : "R") << "xPdo 0x" fp@935: << hex << setfill('0') << setw(4) << pdo.index fp@935: << " \"" << pdo.name << "\"" << endl; fp@935: fp@966: if (quiet) fp@966: continue; fp@966: fp@935: for (k = 0; k < pdo.entry_count; k++) { fp@935: getPdoEntry(&entry, slavePosition, i, j, k); fp@935: fp@935: cout << " Pdo entry 0x" fp@935: << hex << setfill('0') << setw(4) << entry.index fp@990: << ":" << setw(2) << (unsigned int) entry.subindex fp@935: << ", " << dec << (unsigned int) entry.bit_length fp@935: << " bit, \"" << entry.name << "\"" << endl; fp@935: } fp@935: } fp@935: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@966: void Master::listSlaveSdos( fp@966: uint16_t slavePosition, fp@966: bool quiet, fp@966: bool withHeader fp@966: ) fp@965: { fp@965: ec_ioctl_slave_t slave; fp@965: ec_ioctl_sdo_t sdo; fp@965: ec_ioctl_sdo_entry_t entry; fp@965: unsigned int i, j, k; fp@970: const CoEDataType *d; fp@965: fp@965: getSlave(&slave, slavePosition); fp@965: fp@965: if (withHeader) fp@965: cout << "=== Slave " << slavePosition << " ===" << endl; fp@965: fp@965: for (i = 0; i < slave.sdo_count; i++) { fp@965: getSdo(&sdo, slavePosition, i); fp@965: fp@970: cout << "Sdo " fp@965: << hex << setfill('0') << setw(4) << sdo.sdo_index fp@965: << ", \"" << sdo.name << "\"" << endl; fp@965: fp@966: if (quiet) fp@966: continue; fp@966: fp@965: for (j = 0; j <= sdo.max_subindex; j++) { fp@968: getSdoEntry(&entry, slavePosition, -i, j); fp@965: fp@983: cout << " " << hex << setfill('0') fp@983: << setw(4) << sdo.sdo_index << ":" fp@983: << setw(2) << (unsigned int) entry.sdo_entry_subindex fp@970: << ", "; fp@970: fp@970: if ((d = findDataType(entry.data_type))) { fp@970: cout << d->name; fp@970: } else { fp@970: cout << "type " << setw(4) << entry.data_type; fp@970: } fp@970: fp@970: cout << ", " << dec << entry.bit_length << " bit, \"" fp@965: << entry.description << "\"" << endl; fp@965: } fp@965: } fp@965: } fp@965: fp@965: /****************************************************************************/ fp@965: fp@989: void Master::showSlave(uint16_t slavePosition) fp@989: { fp@989: ec_ioctl_slave_t slave; fp@989: list protoList; fp@989: list::const_iterator protoIter; fp@989: fp@989: getSlave(&slave, slavePosition); fp@989: fp@989: cout << "Slave " << dec << slavePosition << endl fp@989: << "Alias: 0x" << hex << setfill('0') << setw(4) << slave.alias << endl fp@989: << "State: " << slaveState(slave.state) << endl fp@989: << "Flag: " << (slave.error_flag ? 'E' : '+') << endl fp@989: << "Identity:" << endl fp@989: << " Vendor Id: 0x" fp@989: << hex << setfill('0') << setw(8) << slave.vendor_id << endl fp@989: << " Product code: 0x" fp@989: << setw(8) << slave.product_code << endl fp@989: << " Revision number: 0x" fp@989: << setw(8) << slave.revision_number << endl fp@989: << " Serial number: 0x" fp@989: << setw(8) << slave.serial_number << endl; fp@989: fp@989: if (slave.mailbox_protocols) { fp@989: cout << "Mailboxes:" << endl fp@989: << " RX: 0x" fp@989: << hex << setw(4) << slave.rx_mailbox_offset << "/" fp@989: << dec << slave.rx_mailbox_size fp@989: << ", TX: 0x" fp@989: << hex << setw(4) << slave.tx_mailbox_offset << "/" fp@989: << dec << slave.tx_mailbox_size << endl fp@989: << " Supported protocols: "; fp@989: fp@989: if (slave.mailbox_protocols & EC_MBOX_AOE) { fp@989: protoList.push_back("AoE"); fp@989: } fp@989: if (slave.mailbox_protocols & EC_MBOX_EOE) { fp@989: protoList.push_back("EoE"); fp@989: } fp@989: if (slave.mailbox_protocols & EC_MBOX_COE) { fp@989: protoList.push_back("CoE"); fp@989: } fp@989: if (slave.mailbox_protocols & EC_MBOX_FOE) { fp@989: protoList.push_back("FoE"); fp@989: } fp@989: if (slave.mailbox_protocols & EC_MBOX_SOE) { fp@989: protoList.push_back("SoE"); fp@989: } fp@989: if (slave.mailbox_protocols & EC_MBOX_VOE) { fp@989: protoList.push_back("VoE"); fp@989: } fp@989: fp@989: for (protoIter = protoList.begin(); protoIter != protoList.end(); fp@989: protoIter++) { fp@989: if (protoIter != protoList.begin()) fp@989: cout << ", "; fp@989: cout << *protoIter; fp@989: } fp@989: cout << endl; fp@989: } fp@989: fp@989: if (slave.has_general_category) { fp@989: cout << "General:" << endl fp@989: << " Name: " << slave.name << endl; fp@989: fp@989: if (slave.mailbox_protocols & EC_MBOX_COE) { fp@989: cout << " CoE details:" << endl fp@989: << " Enable Sdo: " fp@989: << (slave.coe_details.enable_sdo ? "yes" : "no") << endl fp@989: << " Enable Sdo Info: " fp@989: << (slave.coe_details.enable_sdo_info ? "yes" : "no") << endl fp@989: << " Enable Pdo Assign: " fp@989: << (slave.coe_details.enable_pdo_assign fp@989: ? "yes" : "no") << endl fp@989: << " Enable Pdo Configuration: " fp@989: << (slave.coe_details.enable_pdo_configuration fp@989: ? "yes" : "no") << endl fp@989: << " Enable Upload at startup: " fp@989: << (slave.coe_details.enable_upload_at_startup fp@989: ? "yes" : "no") << endl fp@989: << " Enable Sdo complete access: " fp@989: << (slave.coe_details.enable_sdo_complete_access fp@989: ? "yes" : "no") << endl; fp@989: } fp@989: fp@989: cout << " Flags:" << endl fp@989: << " Enable SafeOp: " fp@989: << (slave.general_flags.enable_safeop ? "yes" : "no") << endl fp@989: << " Enable notLRW: " fp@989: << (slave.general_flags.enable_not_lrw ? "yes" : "no") << endl fp@989: << " Current consumption: " fp@990: << dec << slave.current_on_ebus << " mA" << endl; fp@989: } fp@989: cout << endl; fp@989: } fp@989: fp@989: /****************************************************************************/ fp@989: fp@938: void Master::generateSlaveXml(uint16_t slavePosition) fp@938: { fp@938: ec_ioctl_slave_t slave; fp@938: ec_ioctl_sync_t sync; fp@938: ec_ioctl_pdo_t pdo; fp@938: ec_ioctl_pdo_entry_t entry; fp@938: unsigned int i, j, k; fp@938: fp@938: getSlave(&slave, slavePosition); fp@938: fp@938: cout fp@938: << "" << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << slave.vendor_id << "" << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << endl; fp@938: fp@938: for (i = 0; i < slave.sync_count; i++) { fp@938: getSync(&sync, slavePosition, i); fp@938: fp@938: for (j = 0; j < sync.pdo_count; j++) { fp@938: getPdo(&pdo, slavePosition, i, j); fp@938: fp@938: cout fp@938: << " <" << (pdo.dir ? "T" : "R") << "xPdo>" << endl fp@938: << " #x" fp@938: << hex << setfill('0') << setw(4) << pdo.index fp@938: << "" << endl fp@938: << " " << pdo.name << "" << endl; fp@938: fp@938: for (k = 0; k < pdo.entry_count; k++) { fp@938: getPdoEntry(&entry, slavePosition, i, j, k); fp@938: fp@938: cout fp@938: << " " << endl fp@938: << " #x" fp@938: << hex << setfill('0') << setw(4) << entry.index fp@938: << "" << endl; fp@938: if (entry.index) fp@938: cout fp@938: << " " fp@938: << dec << (unsigned int) entry.subindex fp@938: << "" << endl; fp@938: fp@938: cout fp@938: << " " fp@1030: << dec << (unsigned int) entry.bit_length fp@938: << "" << endl; fp@938: fp@938: if (entry.index) { fp@938: cout fp@938: << " " << entry.name fp@938: << "" << endl fp@938: << " "; fp@938: fp@938: if (entry.bit_length == 1) { fp@938: cout << "BOOL"; fp@938: } else if (!(entry.bit_length % 8)) { fp@938: if (entry.bit_length <= 64) fp@938: cout << "UINT" << (unsigned int) entry.bit_length; fp@938: else fp@938: cout << "STRING(" fp@938: << (unsigned int) (entry.bit_length / 8) fp@938: << ")"; fp@938: } else { fp@938: cerr << "Invalid bit length " fp@938: << (unsigned int) entry.bit_length << endl; fp@938: } fp@938: fp@938: cout << "" << endl; fp@938: } fp@938: fp@938: cout << " " << endl; fp@938: } fp@938: fp@938: cout fp@938: << " " << endl; fp@938: } fp@938: } fp@938: fp@938: cout fp@938: << " " << endl fp@938: << " " << endl fp@938: << " " << endl fp@938: << "" << endl; fp@938: } fp@938: fp@938: /****************************************************************************/ fp@938: fp@935: unsigned int Master::slaveCount() fp@935: { fp@957: ec_ioctl_master_t data; fp@957: fp@957: getMaster(&data); fp@957: return data.slave_count; fp@957: } fp@957: fp@957: /****************************************************************************/ fp@957: fp@957: void Master::getMaster(ec_ioctl_master_t *data) fp@957: { fp@957: if (ioctl(fd, EC_IOCTL_MASTER, data) < 0) { fp@957: stringstream err; fp@957: err << "Failed to get master information: " << strerror(errno); fp@957: throw MasterException(err.str()); fp@957: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@990: void Master::getConfig(ec_ioctl_config_t *data, unsigned int index) fp@990: { fp@990: data->config_index = index; fp@990: fp@990: if (ioctl(fd, EC_IOCTL_CONFIG, data) < 0) { fp@990: stringstream err; fp@990: err << "Failed to get slave configuration: " << strerror(errno); fp@990: throw MasterException(err.str()); fp@990: } fp@990: } fp@990: fp@990: /****************************************************************************/ fp@990: fp@990: void Master::getConfigPdo( fp@990: ec_ioctl_config_pdo_t *data, fp@990: unsigned int index, fp@990: unsigned int dir, fp@990: unsigned int pdo_pos fp@990: ) fp@990: { fp@990: data->config_index = index; fp@990: data->direction = dir; fp@990: data->pdo_pos = pdo_pos; fp@990: fp@990: if (ioctl(fd, EC_IOCTL_CONFIG_PDO, data) < 0) { fp@990: stringstream err; fp@990: err << "Failed to get slave config Pdo: " << strerror(errno); fp@990: throw MasterException(err.str()); fp@990: } fp@990: } fp@990: fp@990: /****************************************************************************/ fp@990: fp@990: void Master::getConfigPdoEntry( fp@990: ec_ioctl_config_pdo_entry_t *data, fp@990: unsigned int index, fp@990: unsigned int dir, fp@990: unsigned int pdo_pos, fp@990: unsigned int entry_pos fp@990: ) fp@990: { fp@990: data->config_index = index; fp@990: data->direction = dir; fp@990: data->pdo_pos = pdo_pos; fp@990: data->entry_pos = entry_pos; fp@990: fp@990: if (ioctl(fd, EC_IOCTL_CONFIG_PDO_ENTRY, data) < 0) { fp@990: stringstream err; fp@990: err << "Failed to get slave config Pdo entry: " << strerror(errno); fp@990: throw MasterException(err.str()); fp@990: } fp@990: } fp@990: fp@990: /****************************************************************************/ fp@990: fp@990: void Master::getConfigSdo( fp@990: ec_ioctl_config_sdo_t *data, fp@990: unsigned int index, fp@990: unsigned int sdo_pos fp@990: ) fp@990: { fp@990: data->config_index = index; fp@990: data->sdo_pos = sdo_pos; fp@990: fp@990: if (ioctl(fd, EC_IOCTL_CONFIG_SDO, data) < 0) { fp@990: stringstream err; fp@990: err << "Failed to get slave config Sdo: " << strerror(errno); fp@990: throw MasterException(err.str()); fp@990: } fp@990: } fp@990: fp@990: /****************************************************************************/ fp@990: fp@948: void Master::getDomain(ec_ioctl_domain_t *data, unsigned int index) fp@948: { fp@948: data->index = index; fp@948: fp@948: if (ioctl(fd, EC_IOCTL_DOMAIN, data)) { fp@948: stringstream err; fp@948: err << "Failed to get domain: "; fp@948: if (errno == EINVAL) fp@948: err << "Domain " << index << " does not exist!"; fp@948: else fp@948: err << strerror(errno); fp@948: throw MasterException(err.str()); fp@948: } fp@948: } fp@948: fp@948: /****************************************************************************/ fp@948: fp@950: void Master::getData(ec_ioctl_data_t *data, unsigned int domainIndex, fp@950: unsigned int dataSize, unsigned char *mem) fp@950: { fp@950: data->domain_index = domainIndex; fp@950: data->data_size = dataSize; fp@950: data->target = mem; fp@950: fp@950: if (ioctl(fd, EC_IOCTL_DATA, data) < 0) { fp@950: stringstream err; fp@950: err << "Failed to get domain data: " << strerror(errno); fp@950: throw MasterException(err.str()); fp@950: } fp@950: } fp@950: fp@950: /****************************************************************************/ fp@950: fp@935: void Master::getSlave(ec_ioctl_slave_t *slave, uint16_t slaveIndex) fp@935: { fp@935: slave->position = slaveIndex; fp@935: fp@935: if (ioctl(fd, EC_IOCTL_SLAVE, slave)) { fp@935: stringstream err; fp@935: err << "Failed to get slave: "; fp@935: if (errno == EINVAL) fp@935: err << "Slave " << slaveIndex << " does not exist!"; fp@935: else fp@935: err << strerror(errno); fp@935: throw MasterException(err.str()); fp@935: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@950: void Master::getFmmu( fp@950: ec_ioctl_domain_fmmu_t *fmmu, fp@950: unsigned int domainIndex, fp@950: unsigned int fmmuIndex fp@950: ) fp@950: { fp@950: fmmu->domain_index = domainIndex; fp@950: fmmu->fmmu_index = fmmuIndex; fp@950: fp@950: if (ioctl(fd, EC_IOCTL_DOMAIN_FMMU, fmmu)) { fp@950: stringstream err; fp@950: err << "Failed to get domain FMMU: "; fp@950: if (errno == EINVAL) fp@950: err << "Either domain " << domainIndex << " does not exist, " fp@950: << "or it contains less than " << (unsigned int) fmmuIndex + 1 fp@950: << " FMMus!"; fp@950: else fp@950: err << strerror(errno); fp@950: throw MasterException(err.str()); fp@950: } fp@950: } fp@950: fp@950: /****************************************************************************/ fp@950: fp@935: void Master::getSync( fp@935: ec_ioctl_sync_t *sync, fp@935: uint16_t slaveIndex, fp@935: uint8_t syncIndex fp@935: ) fp@935: { fp@935: sync->slave_position = slaveIndex; fp@935: sync->sync_index = syncIndex; fp@935: fp@935: if (ioctl(fd, EC_IOCTL_SYNC, sync)) { fp@935: stringstream err; fp@935: err << "Failed to get sync manager: "; fp@935: if (errno == EINVAL) fp@935: err << "Either slave " << slaveIndex << " does not exist, " fp@950: << "or it contains less than " << (unsigned int) syncIndex + 1 fp@935: << " sync managers!"; fp@935: else fp@935: err << strerror(errno); fp@935: throw MasterException(err.str()); fp@935: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@935: void Master::getPdo( fp@935: ec_ioctl_pdo_t *pdo, fp@935: uint16_t slaveIndex, fp@935: uint8_t syncIndex, fp@935: uint8_t pdoPos fp@935: ) fp@935: { fp@935: pdo->slave_position = slaveIndex; fp@935: pdo->sync_index = syncIndex; fp@935: pdo->pdo_pos = pdoPos; fp@935: fp@935: if (ioctl(fd, EC_IOCTL_PDO, pdo)) { fp@935: stringstream err; fp@935: err << "Failed to get Pdo: "; fp@935: if (errno == EINVAL) fp@935: err << "Either slave " << slaveIndex << " does not exist, " fp@950: << "or it contains less than " << (unsigned int) syncIndex + 1 fp@935: << " sync managers, or sync manager " fp@935: << (unsigned int) syncIndex << " contains less than " fp@935: << pdoPos + 1 << " Pdos!" << endl; fp@935: else fp@935: err << strerror(errno); fp@935: throw MasterException(err.str()); fp@935: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@935: void Master::getPdoEntry( fp@935: ec_ioctl_pdo_entry_t *entry, fp@935: uint16_t slaveIndex, fp@935: uint8_t syncIndex, fp@935: uint8_t pdoPos, fp@935: uint8_t entryPos fp@935: ) fp@935: { fp@935: entry->slave_position = slaveIndex; fp@935: entry->sync_index = syncIndex; fp@935: entry->pdo_pos = pdoPos; fp@935: entry->entry_pos = entryPos; fp@935: fp@935: if (ioctl(fd, EC_IOCTL_PDO_ENTRY, entry)) { fp@935: stringstream err; fp@935: err << "Failed to get Pdo entry: "; fp@935: if (errno == EINVAL) fp@935: err << "Either slave " << slaveIndex << " does not exist, " fp@950: << "or it contains less than " << (unsigned int) syncIndex + 1 fp@935: << " sync managers, or sync manager " fp@935: << (unsigned int) syncIndex << " contains less than " fp@935: << pdoPos + 1 << " Pdos, or the Pdo at position " << pdoPos fp@935: << " contains less than " << (unsigned int) entryPos + 1 fp@935: << " entries!" << endl; fp@935: else fp@935: err << strerror(errno); fp@935: throw MasterException(err.str()); fp@935: } fp@935: } fp@935: fp@935: /****************************************************************************/ fp@935: fp@965: void Master::getSdo( fp@965: ec_ioctl_sdo_t *sdo, fp@965: uint16_t slaveIndex, fp@965: uint16_t sdoPosition fp@965: ) fp@965: { fp@965: sdo->slave_position = slaveIndex; fp@965: sdo->sdo_position = sdoPosition; fp@965: fp@965: if (ioctl(fd, EC_IOCTL_SDO, sdo)) { fp@965: stringstream err; fp@965: err << "Failed to get Sdo: "; fp@965: if (errno == EINVAL) fp@965: err << "Either slave " << slaveIndex << " does not exist, " fp@965: << "or it contains less than " << sdoPosition + 1 << " Sdos!" fp@965: << endl; fp@965: else fp@965: err << strerror(errno); fp@965: throw MasterException(err.str()); fp@965: } fp@965: } fp@965: fp@965: /****************************************************************************/ fp@965: fp@965: void Master::getSdoEntry( fp@965: ec_ioctl_sdo_entry_t *entry, fp@965: uint16_t slaveIndex, fp@968: int sdoSpec, fp@965: uint8_t entrySubindex fp@965: ) fp@965: { fp@965: entry->slave_position = slaveIndex; fp@968: entry->sdo_spec = sdoSpec; fp@965: entry->sdo_entry_subindex = entrySubindex; fp@965: fp@965: if (ioctl(fd, EC_IOCTL_SDO_ENTRY, entry)) { fp@965: stringstream err; fp@965: err << "Failed to get Sdo entry: "; fp@968: err << strerror(errno); fp@965: throw MasterException(err.str()); fp@965: } fp@965: } fp@965: fp@965: /****************************************************************************/ fp@965: fp@960: void Master::requestState( fp@960: uint16_t slavePosition, fp@960: uint8_t state fp@960: ) fp@960: { fp@960: ec_ioctl_slave_state_t data; fp@960: fp@960: data.slave_position = slavePosition; fp@960: data.requested_state = state; fp@960: fp@960: if (ioctl(fd, EC_IOCTL_SLAVE_STATE, &data)) { fp@960: stringstream err; fp@960: err << "Failed to request slave state: "; fp@960: if (errno == EINVAL) fp@960: err << "Slave " << slavePosition << " does not exist!"; fp@960: else fp@960: err << strerror(errno); fp@960: throw MasterException(err.str()); fp@960: } fp@960: } fp@960: fp@960: /****************************************************************************/ fp@960: fp@935: string Master::slaveState(uint8_t state) fp@922: { fp@922: switch (state) { fp@922: case 1: return "INIT"; fp@922: case 2: return "PREOP"; fp@922: case 4: return "SAFEOP"; fp@922: case 8: return "OP"; fp@922: default: return "???"; fp@922: } fp@922: } fp@922: fp@922: /****************************************************************************/ fp@968: fp@968: void Master::printRawData( fp@968: const uint8_t *data, fp@968: unsigned int size) fp@968: { fp@968: cout << hex << setfill('0'); fp@968: while (size--) { fp@968: cout << "0x" << setw(2) << (unsigned int) *data++; fp@968: if (size) fp@968: cout << " "; fp@968: } fp@968: cout << endl; fp@968: } fp@968: fp@980: /*****************************************************************************/ fp@980: fp@980: /** fp@980: * Calculates the SII checksum field. fp@980: * fp@980: * The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an fp@980: * initial value of 0xff (see IEC 61158-6-12 ch. 5.4). fp@980: * fp@980: * The below code was originally generated with PYCRC fp@980: * http://www.tty1.net/pycrc fp@980: * fp@980: * ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff fp@980: * --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit fp@980: * fp@980: * \return CRC8 fp@980: */ fp@980: uint8_t Master::calcSiiCrc( fp@980: const uint8_t *data, /**< pointer to data */ fp@980: size_t length /**< number of bytes in \a data */ fp@980: ) fp@980: { fp@980: unsigned int i; fp@980: uint8_t bit, byte, crc = 0x48; fp@980: fp@980: while (length--) { fp@980: byte = *data++; fp@980: for (i = 0; i < 8; i++) { fp@980: bit = crc & 0x80; fp@980: crc = (crc << 1) | ((byte >> (7 - i)) & 0x01); fp@980: if (bit) crc ^= 0x07; fp@980: } fp@980: } fp@980: fp@980: for (i = 0; i < 8; i++) { fp@980: bit = crc & 0x80; fp@980: crc <<= 1; fp@980: if (bit) crc ^= 0x07; fp@980: } fp@980: fp@980: return crc; fp@980: } fp@980: fp@980: /*****************************************************************************/