fp@1142: /***************************************************************************** fp@1142: * fp@1363: * $Id$ fp@1363: * fp@1363: * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH fp@1363: * fp@1363: * This file is part of the IgH EtherCAT Master. fp@1363: * fp@1363: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1363: * modify it under the terms of the GNU General Public License version 2, as fp@1363: * published by the Free Software Foundation. fp@1363: * fp@1363: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1363: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1363: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1363: * Public License for more details. fp@1363: * fp@1363: * You should have received a copy of the GNU General Public License along fp@1363: * with the IgH EtherCAT Master; if not, write to the Free Software fp@1363: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@1363: * fp@1363: * --- fp@1363: * fp@1363: * The license mentioned above concerns the source code only. Using the fp@1363: * EtherCAT technology and brand is only permitted in compliance with the fp@1363: * industrial property and similar rights of Beckhoff Automation GmbH. fp@1142: * fp@1142: ****************************************************************************/ fp@1142: fp@1142: #include fp@1142: #include fp@1142: #include fp@1222: #include fp@1142: using namespace std; fp@1142: fp@1142: #include "CommandSlaves.h" fp@1826: #include "MasterDevice.h" fp@1142: fp@1142: /*****************************************************************************/ fp@1142: fp@1142: CommandSlaves::CommandSlaves(): fp@1142: Command("slaves", "Display slaves on the bus.") fp@1142: { fp@1142: } fp@1142: fp@1142: /*****************************************************************************/ fp@1142: fp@1968: string CommandSlaves::helpString(const string &binaryBaseName) const fp@1142: { fp@1142: stringstream str; fp@1142: fp@1968: str << binaryBaseName << " " << getName() << " [OPTIONS]" << endl fp@1142: << endl fp@1142: << getBriefDescription() << endl fp@1142: << endl fp@1142: << "If the --verbose option is not given, the slaves are" << endl fp@1142: << "displayed one-per-line. Example:" << endl fp@1142: << endl fp@1142: << "1 5555:0 PREOP + EL3162 2C. Ana. Input 0-10V" << endl fp@1142: << "| | | | | |" << endl fp@1144: << "| | | | | \\- Name from the SII if avaliable," << endl fp@1144: << "| | | | | otherwise vendor ID and product" << endl fp@1144: << "| | | | | code (both hexadecimal)." << endl fp@1142: << "| | | | \\- Error flag. '+' means no error," << endl fp@1144: << "| | | | 'E' means that scan or" << endl fp@1142: << "| | | | configuration failed." << endl fp@1144: << "| | | \\- Current application-layer state." << endl fp@1157: << "| | \\- Decimal relative position to the last" << endl fp@1142: << "| | slave with an alias address set." << endl fp@1157: << "| \\- Decimal alias address of this slave (if set)," << endl fp@1157: << "| otherwise of the last slave with an alias set," << endl fp@1157: << "| or zero, if no alias was encountered up to this" << endl fp@1157: << "| position." << endl fp@1157: << "\\- Absolute ring position in the bus." << endl fp@1142: << endl fp@1142: << "If the --verbose option is given, a detailed (multi-line)" << endl fp@1142: << "description is output for each slave." << endl fp@1142: << endl fp@1157: << "Slave selection:" << endl fp@1157: << " Slaves for this and other commands can be selected with" << endl fp@1157: << " the --alias and --position parameters as follows:" << endl fp@1157: << endl fp@1157: << " 1) If neither the --alias nor the --position option" << endl fp@1157: << " is given, all slaves are selected." << endl fp@1157: << " 2) If only the --position option is given, it is" << endl fp@1157: << " interpreted as an absolute ring position and" << endl fp@1157: << " a slave with this position is matched." << endl fp@1157: << " 3) If only the --alias option is given, all slaves" << endl fp@1157: << " with the given alias address and subsequent" << endl fp@1157: << " slaves before a slave with a different alias" << endl fp@1157: << " address match (use -p0 if only the slaves" << endl fp@1157: << " with the given alias are desired, see 4))." << endl fp@1157: << " 4) If both the --alias and the --position option are" << endl fp@1157: << " given, the latter is interpreted as relative" << endl fp@1157: << " position behind any slave with the given alias." << endl fp@1157: << endl fp@1142: << "Command-specific options:" << endl fp@1157: << " --alias -a Slave alias (see above)." << endl fp@1157: << " --position -p Slave position (see above)." << endl fp@1157: << " --verbose -v Show detailed slave information." << endl fp@1142: << endl fp@1142: << numericInfo(); fp@1142: fp@1142: return str.str(); fp@1142: } fp@1142: fp@1142: /****************************************************************************/ fp@1142: fp@1826: void CommandSlaves::execute(const StringVector &args) fp@1142: { fp@1869: MasterIndexList masterIndices; fp@1151: SlaveList slaves; fp@1826: bool doIndent; fp@1151: fp@1373: if (args.size()) { fp@1373: stringstream err; fp@1373: err << "'" << getName() << "' takes no arguments!"; fp@1373: throwInvalidUsageException(err); fp@1373: } fp@1373: fp@1869: masterIndices = getMasterIndices(); fp@1869: doIndent = masterIndices.size() > 1; fp@1826: MasterIndexList::const_iterator mi; fp@1869: for (mi = masterIndices.begin(); fp@1869: mi != masterIndices.end(); mi++) { fp@1826: MasterDevice m(*mi); fp@1826: m.open(MasterDevice::Read); fp@1826: slaves = selectedSlaves(m); fp@1826: fp@1826: if (getVerbosity() == Verbose) { fp@1826: showSlaves(m, slaves); fp@1826: } else { fp@1826: listSlaves(m, slaves, doIndent); fp@1826: } fp@1142: } fp@1142: } fp@1142: fp@1142: /****************************************************************************/ fp@1142: fp@1142: void CommandSlaves::listSlaves( fp@1142: MasterDevice &m, fp@1826: const SlaveList &slaves, fp@1826: bool doIndent fp@1142: ) fp@1142: { fp@1160: ec_ioctl_master_t master; fp@2374: unsigned int i, lastDevice; fp@1142: ec_ioctl_slave_t slave; fp@1142: uint16_t lastAlias, aliasIndex; fp@1142: Info info; fp@1142: typedef list InfoList; fp@1142: InfoList infoList; fp@1142: InfoList::const_iterator iter; fp@1142: stringstream str; fp@1142: unsigned int maxPosWidth = 0, maxAliasWidth = 0, fp@1142: maxRelPosWidth = 0, maxStateWidth = 0; fp@1826: string indent(doIndent ? " " : ""); fp@1142: fp@1160: m.getMaster(&master); fp@1142: fp@1142: lastAlias = 0; fp@1142: aliasIndex = 0; fp@1160: for (i = 0; i < master.slave_count; i++) { fp@1142: m.getSlave(&slave, i); fp@1142: fp@1142: if (slave.alias) { fp@1142: lastAlias = slave.alias; fp@1142: aliasIndex = 0; fp@1142: } fp@1142: fp@1151: if (slaveInList(slave, slaves)) { fp@1142: str << dec << i; fp@1142: info.pos = str.str(); fp@1142: str.clear(); fp@1142: str.str(""); fp@1142: fp@1142: str << lastAlias; fp@1142: info.alias = str.str(); fp@1142: str.str(""); fp@1142: fp@1142: str << aliasIndex; fp@1142: info.relPos = str.str(); fp@1142: str.str(""); fp@1142: fp@1148: info.state = alStateString(slave.al_state); fp@1142: info.flag = (slave.error_flag ? 'E' : '+'); fp@2374: info.device = slave.device_index; fp@1142: fp@1142: if (strlen(slave.name)) { fp@1142: info.name = slave.name; fp@1142: } else { fp@1142: str << "0x" << hex << setfill('0') fp@1142: << setw(8) << slave.vendor_id << ":0x" fp@1142: << setw(8) << slave.product_code; fp@1142: info.name = str.str(); fp@1142: str.str(""); fp@1142: } fp@1142: fp@1142: fp@1142: infoList.push_back(info); fp@1142: fp@1142: if (info.pos.length() > maxPosWidth) fp@1142: maxPosWidth = info.pos.length(); fp@1142: if (info.alias.length() > maxAliasWidth) fp@1142: maxAliasWidth = info.alias.length(); fp@1142: if (info.relPos.length() > maxRelPosWidth) fp@1142: maxRelPosWidth = info.relPos.length(); fp@1142: if (info.state.length() > maxStateWidth) fp@1142: maxStateWidth = info.state.length(); fp@1142: } fp@1142: fp@1142: aliasIndex++; fp@1142: } fp@1142: fp@1827: if (infoList.size() && doIndent) { fp@1827: cout << "Master" << dec << m.getIndex() << endl; fp@1827: } fp@1827: fp@2374: lastDevice = EC_DEVICE_MAIN; fp@1142: for (iter = infoList.begin(); iter != infoList.end(); iter++) { fp@2374: if (iter->device != lastDevice) { fp@2374: lastDevice = iter->device; fp@2374: cout << "xxx LINK FAILURE xxx" << endl; fp@2374: } fp@1826: cout << indent << setfill(' ') << right fp@1142: << setw(maxPosWidth) << iter->pos << " " fp@1142: << setw(maxAliasWidth) << iter->alias fp@1142: << ":" << left fp@1142: << setw(maxRelPosWidth) << iter->relPos << " " fp@1142: << setw(maxStateWidth) << iter->state << " " fp@1142: << iter->flag << " " fp@1142: << iter->name << endl; fp@1142: } fp@1142: } fp@1142: fp@1142: /****************************************************************************/ fp@1142: fp@1151: void CommandSlaves::showSlaves( fp@1142: MasterDevice &m, fp@1151: const SlaveList &slaves fp@1142: ) fp@1142: { fp@1151: SlaveList::const_iterator si; fp@1379: int i; fp@1151: fp@1151: for (si = slaves.begin(); si != slaves.end(); si++) { fp@1826: cout << "=== Master " << dec << m.getIndex() fp@1826: << ", Slave " << dec << si->position << " ===" << endl; fp@1151: fp@1151: if (si->alias) fp@1151: cout << "Alias: " << si->alias << endl; fp@1151: fp@1151: cout fp@2374: << "Device: " << (si->device_index ? "Backup" : "Main") << endl fp@1151: << "State: " << alStateString(si->al_state) << endl fp@1151: << "Flag: " << (si->error_flag ? 'E' : '+') << endl fp@1151: << "Identity:" << endl fp@1151: << " Vendor Id: 0x" fp@1151: << hex << setfill('0') fp@1151: << setw(8) << si->vendor_id << endl fp@1151: << " Product code: 0x" fp@1151: << setw(8) << si->product_code << endl fp@1151: << " Revision number: 0x" fp@1151: << setw(8) << si->revision_number << endl fp@1151: << " Serial number: 0x" fp@1151: << setw(8) << si->serial_number << endl; fp@1151: fp@1379: cout << "DL information:" << endl fp@1379: << " FMMU bit operation: " fp@1379: << (si->fmmu_bit ? "yes" : "no") << endl fp@1379: << " Distributed clocks: "; fp@1379: if (si->dc_supported) { fp@1419: if (si->has_dc_system_time) { fp@1419: cout << "yes, "; fp@1419: switch (si->dc_range) { fp@1419: case EC_DC_32: fp@1419: cout << "32 bit"; fp@1419: break; fp@1419: case EC_DC_64: fp@1419: cout << "64 bit"; fp@1419: break; fp@1419: default: fp@1419: cout << "???"; fp@1419: } fp@1420: cout << endl; fp@1419: } else { fp@1420: cout << "yes, delay measurement only" << endl; fp@1419: } fp@1426: cout << " DC system time transmission delay: " fp@1429: << dec << si->transmission_delay << " ns" << endl; fp@1379: } else { fp@1420: cout << "no" << endl; fp@1420: } fp@1420: fp@1421: cout << "Port Type Link Loop Signal NextSlave"; fp@1420: if (si->dc_supported) fp@1425: cout << " RxTime [ns] Diff [ns] NextDc [ns]"; fp@1379: cout << endl; fp@1420: fp@1420: for (i = 0; i < EC_MAX_PORTS; i++) { fp@1420: cout << " " << i << " " << setfill(' ') << left << setw(4); fp@1425: switch (si->ports[i].desc) { fp@1420: case EC_PORT_NOT_IMPLEMENTED: fp@1420: cout << "N/A"; fp@1420: break; fp@1420: case EC_PORT_NOT_CONFIGURED: fp@1420: cout << "N/C"; fp@1420: break; fp@1420: case EC_PORT_EBUS: fp@1420: cout << "EBUS"; fp@1420: break; fp@1420: case EC_PORT_MII: fp@1420: cout << "MII"; fp@1420: break; fp@1420: default: fp@1420: cout << "???"; fp@1420: } fp@1420: fp@1420: cout << " " << setw(4) fp@1425: << (si->ports[i].link.link_up ? "up" : "down") fp@1420: << " " << setw(6) fp@1425: << (si->ports[i].link.loop_closed ? "closed" : "open") fp@1421: << " " << setw(6) fp@1425: << (si->ports[i].link.signal_detected ? "yes" : "no") fp@1421: << " " << setw(9) << right; fp@1421: fp@1425: if (si->ports[i].next_slave != 0xffff) { fp@1425: cout << dec << si->ports[i].next_slave; fp@1421: } else { fp@1421: cout << "-"; fp@1421: } fp@1420: fp@1420: if (si->dc_supported) { fp@1425: cout << " " << setw(11) << right; fp@1425: if (!si->ports[i].link.loop_closed) { fp@1425: cout << dec << si->ports[i].receive_time; fp@1420: } else { fp@1420: cout << "-"; fp@1420: } fp@1420: cout << " " << setw(10); fp@1425: if (!si->ports[i].link.loop_closed) { fp@2374: cout << si->ports[i].receive_time - fp@2374: si->ports[0].receive_time; fp@1425: } else { fp@1425: cout << "-"; fp@1425: } fp@1425: cout << " " << setw(10); fp@1425: if (!si->ports[i].link.loop_closed) { fp@1425: cout << si->ports[i].delay_to_next_dc; fp@1420: } else { fp@1420: cout << "-"; fp@1420: } fp@1420: } fp@1420: fp@1420: cout << endl; fp@1420: } fp@1379: fp@1151: if (si->mailbox_protocols) { fp@1220: list protoList; fp@1220: list::const_iterator protoIter; fp@1220: fp@1151: cout << "Mailboxes:" << endl fp@1463: << " Bootstrap RX: 0x" << setfill('0') fp@1337: << hex << setw(4) << si->boot_rx_mailbox_offset << "/" fp@1337: << dec << si->boot_rx_mailbox_size fp@1151: << ", TX: 0x" fp@1337: << hex << setw(4) << si->boot_tx_mailbox_offset << "/" fp@1337: << dec << si->boot_tx_mailbox_size << endl fp@1337: << " Standard RX: 0x" fp@1337: << hex << setw(4) << si->std_rx_mailbox_offset << "/" fp@1337: << dec << si->std_rx_mailbox_size fp@1337: << ", TX: 0x" fp@1337: << hex << setw(4) << si->std_tx_mailbox_offset << "/" fp@1337: << dec << si->std_tx_mailbox_size << endl fp@1151: << " Supported protocols: "; fp@1151: fp@1151: if (si->mailbox_protocols & EC_MBOX_AOE) { fp@1151: protoList.push_back("AoE"); fp@1151: } fp@1151: if (si->mailbox_protocols & EC_MBOX_EOE) { fp@1151: protoList.push_back("EoE"); fp@1151: } fp@1151: if (si->mailbox_protocols & EC_MBOX_COE) { fp@1151: protoList.push_back("CoE"); fp@1151: } fp@1151: if (si->mailbox_protocols & EC_MBOX_FOE) { fp@1151: protoList.push_back("FoE"); fp@1151: } fp@1151: if (si->mailbox_protocols & EC_MBOX_SOE) { fp@1151: protoList.push_back("SoE"); fp@1151: } fp@1151: if (si->mailbox_protocols & EC_MBOX_VOE) { fp@1151: protoList.push_back("VoE"); fp@1151: } fp@1151: fp@1151: for (protoIter = protoList.begin(); protoIter != protoList.end(); fp@1151: protoIter++) { fp@1151: if (protoIter != protoList.begin()) fp@1151: cout << ", "; fp@1151: cout << *protoIter; fp@1151: } fp@1151: cout << endl; fp@1151: } fp@1151: fp@1151: if (si->has_general_category) { fp@1151: cout << "General:" << endl fp@1151: << " Group: " << si->group << endl fp@1151: << " Image name: " << si->image << endl fp@1151: << " Order number: " << si->order << endl fp@1151: << " Device name: " << si->name << endl; fp@1151: fp@1151: if (si->mailbox_protocols & EC_MBOX_COE) { fp@1151: cout << " CoE details:" << endl fp@1327: << " Enable SDO: " fp@1151: << (si->coe_details.enable_sdo ? "yes" : "no") << endl fp@1327: << " Enable SDO Info: " fp@2374: << (si->coe_details.enable_sdo_info ? "yes" : "no") fp@2374: << endl fp@1327: << " Enable PDO Assign: " fp@1151: << (si->coe_details.enable_pdo_assign fp@1151: ? "yes" : "no") << endl fp@1327: << " Enable PDO Configuration: " fp@1151: << (si->coe_details.enable_pdo_configuration fp@1151: ? "yes" : "no") << endl fp@1151: << " Enable Upload at startup: " fp@1151: << (si->coe_details.enable_upload_at_startup fp@1151: ? "yes" : "no") << endl fp@1327: << " Enable SDO complete access: " fp@1151: << (si->coe_details.enable_sdo_complete_access fp@1151: ? "yes" : "no") << endl; fp@1151: } fp@1151: fp@1151: cout << " Flags:" << endl fp@1151: << " Enable SafeOp: " fp@1151: << (si->general_flags.enable_safeop ? "yes" : "no") << endl fp@1151: << " Enable notLRW: " fp@1151: << (si->general_flags.enable_not_lrw ? "yes" : "no") << endl fp@1151: << " Current consumption: " fp@1151: << dec << si->current_on_ebus << " mA" << endl; fp@1151: } fp@1151: } fp@1151: } fp@1151: fp@1151: /****************************************************************************/ fp@1151: fp@1151: bool CommandSlaves::slaveInList( fp@1151: const ec_ioctl_slave_t &slave, fp@1151: const SlaveList &slaves fp@1151: ) fp@1151: { fp@1151: SlaveList::const_iterator si; fp@1151: fp@1151: for (si = slaves.begin(); si != slaves.end(); si++) { fp@1151: if (si->position == slave.position) { fp@1151: return true; fp@1151: } fp@1151: } fp@1151: fp@1151: return false; fp@1142: } fp@1142: fp@1142: /*****************************************************************************/