Redesigned command interface.

This commit is contained in:
Florian Pose
2008-07-24 13:27:06 +00:00
parent 338bb8fb41
commit b83e94400e
39 changed files with 1812 additions and 1103 deletions

81
tool/Command.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include "Command.h"
/*****************************************************************************/
Command::Command(const string &name, const string &briefDesc):
name(name),
briefDesc(briefDesc),
verbosity(Normal)
{
}
/*****************************************************************************/
Command::~Command()
{
}
/*****************************************************************************/
void Command::setVerbosity(Verbosity v)
{
verbosity = v;
};
/****************************************************************************/
bool Command::matchesSubstr(const string &cmd) const
{
return name.substr(0, cmd.length()) == cmd;
}
/****************************************************************************/
bool Command::matchesAbbrev(const string &abb) const
{
unsigned int i;
size_t pos = 0;
for (i = 0; i < abb.length(); i++) {
pos = name.find(abb[i], pos);
if (pos == string::npos)
return false;
}
return true;
}
/*****************************************************************************/
void Command::throwInvalidUsageException(const stringstream &s)
{
throw InvalidUsageException(s);
}
/*****************************************************************************/
void Command::throwCommandException(const stringstream &s)
{
throw CommandException(s);
}
/*****************************************************************************/
string Command::numericInfo()
{
stringstream str;
str << "Numerical values can be specified either with decimal (no" << endl
<< "prefix), octal (prefix '0') or hexadecimal (prefix '0x') base."
<< endl;
return str.str();
}
/****************************************************************************/

117
tool/Command.h Normal file
View File

@@ -0,0 +1,117 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMAND_H__
#define __COMMAND_H__
#include <stdexcept>
#include <vector>
using namespace std;
#include "MasterDevice.h"
/*****************************************************************************/
extern unsigned int masterIndex;
extern int slavePosition;
extern int domainIndex;
extern string dataTypeStr;
extern bool force;
/****************************************************************************/
class InvalidUsageException:
public runtime_error
{
friend class Command;
protected:
/** Constructor with stringstream parameter. */
InvalidUsageException(
const stringstream &s /**< Message. */
): runtime_error(s.str()) {}
};
/****************************************************************************/
class CommandException:
public runtime_error
{
friend class Command;
protected:
/** Constructor with stringstream parameter. */
CommandException(
const stringstream &s /**< Message. */
): runtime_error(s.str()) {}
};
/****************************************************************************/
class Command
{
public:
Command(const string &, const string &);
virtual ~Command();
enum Verbosity {
Quiet,
Normal,
Verbose
};
void setVerbosity(Verbosity);
const string &getName() const;
const string &getBriefDescription() const;
Verbosity getVerbosity() const;
bool matchesSubstr(const string &) const;
bool matchesAbbrev(const string &) const;
virtual string helpString() const = 0;
typedef vector<string> StringVector;
virtual void execute(MasterDevice &, const StringVector &) = 0;
protected:
void throwInvalidUsageException(const stringstream &);
void throwCommandException(const stringstream &);
enum {BreakAfterBytes = 16};
static string numericInfo();
private:
string name;
string briefDesc;
Verbosity verbosity;
Command();
};
/****************************************************************************/
inline const string &Command::getName() const
{
return name;
}
/****************************************************************************/
inline const string &Command::getBriefDescription() const
{
return briefDesc;
}
/****************************************************************************/
inline Command::Verbosity Command::getVerbosity() const
{
return verbosity;
}
/****************************************************************************/
#endif

View File

@@ -9,56 +9,67 @@
#include <sstream>
using namespace std;
#include "globals.h"
#include "CommandAlias.h"
#include "sii_crc.h"
#include "byteorder.h"
/*****************************************************************************/
const char *help_alias =
"[OPTIONS] <ALIAS>\n"
"\n"
"Write the secondary slave address (alias) for either\n"
"one or for multiple slaves.\n"
"\n"
"Arguments:\n"
" ALIAS must be an unsigned 16 bit number. Zero means no alias.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default). The --force option is\n"
" required in this case.\n"
" --force Acknowledge writing aliases of all slaves.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
CommandAlias::CommandAlias():
Command("alias", "Write alias addresses.")
{
}
/*****************************************************************************/
void writeSlaveAlias(uint16_t, uint16_t);
string CommandAlias::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS] <ALIAS>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Arguments:" << endl
<< " ALIAS must be an unsigned 16 bit number. Zero means no alias."
<< endl << endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position, or 'all'"
<< endl
<< " for all slaves (default). The --force"
<< endl
<< " option is required in this case." << endl
<< " --force -f Acknowledge writing aliases of all" << endl
<< " slaves." << endl
<< endl
<< numericInfo();
return str.str();
}
/*****************************************************************************/
/** Writes the Secondary slave address (alias) to the slave's SII.
*/
void command_alias(void)
void CommandAlias::execute(MasterDevice &m, const StringVector &args)
{
uint16_t alias;
stringstream err, strAlias;
int number;
unsigned int numSlaves, i;
if (commandArgs.size() != 1) {
err << "'" << commandName << "' takes exactly one argument!";
throw InvalidUsageException(err);
if (args.size() != 1) {
err << "'" << getName() << "' takes exactly one argument!";
throwInvalidUsageException(err);
}
strAlias << commandArgs[0];
strAlias << args[0];
strAlias
>> resetiosflags(ios::basefield) // guess base from prefix
>> number;
if (strAlias.fail() || number < 0x0000 || number > 0xffff) {
err << "Invalid alias '" << commandArgs[0] << "'!";
throw InvalidUsageException(err);
err << "Invalid alias '" << args[0] << "'!";
throwInvalidUsageException(err);
}
alias = number;
@@ -66,18 +77,18 @@ void command_alias(void)
if (!force) {
err << "This will write the alias addresses of all slaves to "
<< alias << "! Please specify --force to proceed.";
throw CommandException(err);
throwCommandException(err);
}
masterDev.open(MasterDevice::ReadWrite);
numSlaves = masterDev.slaveCount();
m.open(MasterDevice::ReadWrite);
numSlaves = m.slaveCount();
for (i = 0; i < numSlaves; i++) {
writeSlaveAlias(i, alias);
writeSlaveAlias(m, i, alias);
}
} else {
masterDev.open(MasterDevice::ReadWrite);
writeSlaveAlias(slavePosition, alias);
m.open(MasterDevice::ReadWrite);
writeSlaveAlias(m, slavePosition, alias);
}
}
@@ -85,7 +96,8 @@ void command_alias(void)
/** Writes the Secondary slave address (alias) to the slave's SII.
*/
void writeSlaveAlias(
void CommandAlias::writeSlaveAlias(
MasterDevice &m,
uint16_t slavePosition,
uint16_t alias
)
@@ -95,12 +107,12 @@ void writeSlaveAlias(
stringstream err;
uint8_t crc;
masterDev.getSlave(&slave, slavePosition);
m.getSlave(&slave, slavePosition);
if (slave.sii_nwords < 8) {
err << "Current SII contents are too small to set an alias "
<< "(" << slave.sii_nwords << " words)!";
throw CommandException(err);
throwCommandException(err);
}
// read first 8 SII words
@@ -110,11 +122,11 @@ void writeSlaveAlias(
data.words = new uint16_t[data.nwords];
try {
masterDev.readSii(&data);
m.readSii(&data);
} catch (MasterDeviceException &e) {
delete [] data.words;
err << "Failed to read SII: " << e.what();
throw CommandException(err);
throwCommandException(err);
}
// write new alias address in word 4
@@ -128,11 +140,11 @@ void writeSlaveAlias(
// write first 8 words with new alias and checksum
try {
masterDev.writeSii(&data);
m.writeSii(&data);
} catch (MasterDeviceException &e) {
delete [] data.words;
err << "Failed to read SII: " << e.what();
throw CommandException(err);
throwCommandException(err);
}
delete [] data.words;

29
tool/CommandAlias.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDALIAS_H__
#define __COMMANDALIAS_H__
#include "Command.h"
/****************************************************************************/
class CommandAlias:
public Command
{
public:
CommandAlias();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void writeSlaveAlias(MasterDevice &, uint16_t, uint16_t);
};
/****************************************************************************/
#endif

View File

@@ -10,47 +10,50 @@
#include <sstream>
using namespace std;
#include "globals.h"
#include "CommandConfig.h"
#include "byteorder.h"
/*****************************************************************************/
const char *help_config =
"[OPTIONS]\n"
"\n"
"Output information about the slave configurations supplied by the\n"
"application.\n"
"\n"
"Without the --verbose option, each line of output shows one slave\n"
"configuration. Example:\n"
"\n"
"1001:0 0x0000003b/0x02010000 - -\n"
"| | | |\n"
"| | | \\- Slave is operational.\n"
"| | \\- Slave has been found.\n"
"| \\- Hexadecimal vendor ID and product code, separated by a\n"
"| slash.\n"
"\\- Decimal alias and position, separated by a colon.\n"
"\n"
"With the --verbose option given, the configured Pdos and Sdos are\n"
"additionally printed.\n"
"\n"
"Command-specific options:\n"
" --verbose -v Show detailed configurations.\n";
CommandConfig::CommandConfig():
Command("config", "Show slave configurations.")
{
}
/*****************************************************************************/
struct ConfigInfo {
string alias;
string pos;
string ident;
string att;
string op;
};
string CommandConfig::helpString() const
{
stringstream str;
typedef list<ec_ioctl_config_t> ConfigList;
str << "[OPTIONS]" << endl
<< endl
<< "Output information about the slave configurations" << endl
<< "supplied by the application." << endl
<< endl
<< "Without the --verbose option, slave configurations are" << endl
<< "output one-per-line. Example:" << endl
<< endl
<< "1001:0 0x0000003b/0x02010000 - -" << endl
<< "| | | |" << endl
<< "| | | \\- Slave is operational."
<< endl
<< "| | \\- Slave has been found." << endl
<< "| \\- Hexadecimal vendor ID and product code, separated"
<< endl
<< "| by a slash." << endl
<< "\\- Decimal alias and position, separated by a colon." << endl
<< endl
<< "With the --verbose option given, the configured Pdos and" << endl
<< "Sdos are additionally printed." << endl
<< endl
<< "Command-specific options:" << endl
<< " --verbose -v Show detailed configurations." << endl;
void showDetailedConfigs(const ConfigList &configList);
void listConfigs(const ConfigList &configList);
return str.str();
}
/*****************************************************************************/
/*****************************************************************************/
@@ -64,25 +67,25 @@ bool operator<(const ec_ioctl_config_t &a, const ec_ioctl_config_t &b)
/** Lists the bus configuration.
*/
void command_config(void)
void CommandConfig::execute(MasterDevice &m, const StringVector &args)
{
ec_ioctl_master_t master;
unsigned int i;
ec_ioctl_config_t config;
ConfigList configList;
masterDev.open(MasterDevice::Read);
masterDev.getMaster(&master);
m.open(MasterDevice::Read);
m.getMaster(&master);
for (i = 0; i < master.config_count; i++) {
masterDev.getConfig(&config, i);
m.getConfig(&config, i);
configList.push_back(config);
}
configList.sort();
if (verbosity == Verbose) {
showDetailedConfigs(configList);
if (getVerbosity() == Verbose) {
showDetailedConfigs(m, configList);
} else {
listConfigs(configList);
}
@@ -92,7 +95,10 @@ void command_config(void)
/** Lists the complete bus configuration.
*/
void showDetailedConfigs(const ConfigList &configList)
void CommandConfig::showDetailedConfigs(
MasterDevice &m,
const ConfigList &configList
)
{
ConfigList::const_iterator configIter;
unsigned int j, k, l;
@@ -121,14 +127,14 @@ void showDetailedConfigs(const ConfigList &configList)
<< (configIter->syncs[j].dir == EC_DIR_INPUT
? "Input" : "Output") << ")" << endl;
for (k = 0; k < configIter->syncs[j].pdo_count; k++) {
masterDev.getConfigPdo(&pdo, configIter->config_index, j, k);
m.getConfigPdo(&pdo, configIter->config_index, j, k);
cout << " Pdo 0x" << hex
<< setw(4) << pdo.index
<< " \"" << pdo.name << "\"" << endl;
for (l = 0; l < pdo.entry_count; l++) {
masterDev.getConfigPdoEntry(&entry,
m.getConfigPdoEntry(&entry,
configIter->config_index, j, k, l);
cout << " Pdo entry 0x" << hex
@@ -144,7 +150,7 @@ void showDetailedConfigs(const ConfigList &configList)
cout << "Sdo configuration:" << endl;
if (configIter->sdo_count) {
for (j = 0; j < configIter->sdo_count; j++) {
masterDev.getConfigSdo(&sdo, configIter->config_index, j);
m.getConfigSdo(&sdo, configIter->config_index, j);
cout << " 0x"
<< hex << setfill('0')
@@ -183,14 +189,14 @@ void showDetailedConfigs(const ConfigList &configList)
/** Lists the bus configuration.
*/
void listConfigs(const ConfigList &configList)
void CommandConfig::listConfigs(const ConfigList &configList)
{
ConfigList::const_iterator configIter;
stringstream str;
ConfigInfo info;
typedef list<ConfigInfo> ConfigInfoList;
ConfigInfoList list;
ConfigInfoList::const_iterator iter;
Info info;
typedef list<Info> InfoList;
InfoList list;
InfoList::const_iterator iter;
unsigned int maxAliasWidth = 0, maxPosWidth = 0,
maxAttWidth = 0, maxOpWidth = 0;

43
tool/CommandConfig.h Normal file
View File

@@ -0,0 +1,43 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDCONFIG_H__
#define __COMMANDCONFIG_H__
#include <list>
using namespace std;
#include "Command.h"
/****************************************************************************/
class CommandConfig:
public Command
{
public:
CommandConfig();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
struct Info {
string alias;
string pos;
string ident;
string att;
string op;
};
typedef list<ec_ioctl_config_t> ConfigList;
void showDetailedConfigs(MasterDevice &, const ConfigList &);
void listConfigs(const ConfigList &);
};
/****************************************************************************/
#endif

View File

@@ -7,57 +7,66 @@
#include <iostream>
using namespace std;
#include "globals.h"
#include "CommandData.h"
/*****************************************************************************/
const char *help_data =
"[OPTIONS]\n"
"\n"
"Output binary domain data.\n"
"\n"
"Command-specific options:\n"
" --domain -d <index> Positive numerical domain index, or 'all' for\n"
" all domains (default). In this case, data of all\n"
" domains are concatenated.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void outputDomainData(unsigned int);
/****************************************************************************/
void command_data()
CommandData::CommandData():
Command("data", "Output binary domain process data.")
{
masterDev.open(MasterDevice::Read);
}
/*****************************************************************************/
string CommandData::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Command-specific options:" << endl
<< " --domain -d <index> Positive numerical domain index, or" << endl
<< " 'all' for all domains (default). In" << endl
<< " this case, data of all domains are" << endl
<< " concatenated." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandData::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (domainIndex == -1) {
unsigned int i;
ec_ioctl_master_t master;
masterDev.getMaster(&master);
m.getMaster(&master);
for (i = 0; i < master.domain_count; i++) {
outputDomainData(i);
outputDomainData(m, i);
}
} else {
outputDomainData(domainIndex);
outputDomainData(m, domainIndex);
}
}
/****************************************************************************/
void outputDomainData(unsigned int domainIndex)
void CommandData::outputDomainData(MasterDevice &m, unsigned int domainIndex)
{
ec_ioctl_domain_t domain;
ec_ioctl_domain_data_t data;
unsigned char *processData;
unsigned int i;
masterDev.getDomain(&domain, domainIndex);
m.getDomain(&domain, domainIndex);
if (!domain.data_size)
return;
@@ -65,7 +74,7 @@ void outputDomainData(unsigned int domainIndex)
processData = new unsigned char[domain.data_size];
try {
masterDev.getData(&data, domainIndex, domain.data_size, processData);
m.getData(&data, domainIndex, domain.data_size, processData);
} catch (MasterDeviceException &e) {
delete [] processData;
throw e;

29
tool/CommandData.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDDATA_H__
#define __COMMANDDATA_H__
#include "Command.h"
/****************************************************************************/
class CommandData:
public Command
{
public:
CommandData();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void outputDomainData(MasterDevice &, unsigned int);
};
/****************************************************************************/
#endif

70
tool/CommandDebug.cpp Normal file
View File

@@ -0,0 +1,70 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <sstream>
#include <iomanip>
using namespace std;
#include "CommandDebug.h"
/*****************************************************************************/
CommandDebug::CommandDebug():
Command("debug", "Set the master's debug level.")
{
}
/*****************************************************************************/
string CommandDebug::helpString() const
{
stringstream str;
str << getName() << " <LEVEL>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Debug messages are printed to syslog." << endl
<< endl
<< "Arguments:" << endl
<< " LEVEL can have one of the following values:" << endl
<< " 0 for no debugging output," << endl
<< " 1 for some debug messages, or" << endl
<< " 2 for printing all frame contents (use with caution!)."
<< endl << endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandDebug::execute(MasterDevice &m, const StringVector &args)
{
stringstream str;
int debugLevel;
if (args.size() != 1) {
stringstream err;
err << "'" << getName() << "' takes exactly one argument!";
throwInvalidUsageException(err);
}
str << args[0];
str >> resetiosflags(ios::basefield) // guess base from prefix
>> debugLevel;
if (str.fail()) {
stringstream err;
err << "Invalid debug level '" << args[0] << "'!";
throwInvalidUsageException(err);
}
m.open(MasterDevice::ReadWrite);
m.setDebug(debugLevel);
}
/*****************************************************************************/

26
tool/CommandDebug.h Normal file
View File

@@ -0,0 +1,26 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDDEBUG_H__
#define __COMMANDDEBUG_H__
#include "Command.h"
/****************************************************************************/
class CommandDebug:
public Command
{
public:
CommandDebug();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
};
/****************************************************************************/
#endif

View File

@@ -8,71 +8,83 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandDomains.h"
/*****************************************************************************/
const char *help_domains =
"[OPTIONS]\n"
"\n"
"Show information about the application's configured domains.\n"
"\n"
"Without the --verbose option, the domains are displayed one-per-line.\n"
"Example:\n"
"\n"
"Domain0: LogBaseAddr 0x00000000, Size 6, WorkingCounter 0/1\n"
"\n"
"The domain's base address for the logical datagram (LRD/LWR/LRW)\n"
"is displayed followed by the domain's process data size in byte.\n"
"The last values are the current datagram working counter sum and\n"
"the expected working counter sum. If the values are equal, all\n"
"Pdos are exchanged.\n"
"\n"
"If the --verbose option is given, the participating slave\n"
"configurations/FMMUs and the current process data are additionally\n"
"displayed:\n"
"\n"
"Domain1: LogBaseAddr 0x00000006, Size 6, WorkingCounter 0/1\n"
" SlaveConfig 1001:0, SM3 ( Input), LogAddr 0x00000006, Size 6\n"
" 00 00 00 00 00 00\n"
"\n"
"The process data are displayed as hexadecimal bytes.\n"
"\n"
"Command-specific options:\n"
" --domain -d <index> Positive numerical domain index, or 'all'\n"
" for all domains (default).\n"
" --verbose -v Show FMMUs and process data additionally.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void showDomain(unsigned int);
/****************************************************************************/
void command_domains(void)
CommandDomains::CommandDomains():
Command("domains", "Show configured domains.")
{
masterDev.open(MasterDevice::Read);
}
/*****************************************************************************/
string CommandDomains::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]"
<< endl
<< getBriefDescription() << endl
<< endl
<< "Without the --verbose option, the domains are displayed" << endl
<< "one-per-line. Example:" << endl
<< endl
<< "Domain0: LogBaseAddr 0x00000000, Size 6, WorkingCounter 0/1"
<< endl << endl
<< "The domain's base address for the logical datagram" << endl
<< "(LRD/LWR/LRW) is displayed followed by the domain's" << endl
<< "process data size in byte. The last values are the current" << endl
<< "datagram working counter sum and the expected working" << endl
<< "counter sum. If the values are equal, all Pdos are exchanged."
<< endl << endl
<< "If the --verbose option is given, the participating slave" << endl
<< "configurations/FMMUs and the current process data are" << endl
<< "additionally displayed:" << endl
<< endl
<< "Domain1: LogBaseAddr 0x00000006, Size 6, WorkingCounter 0/1"
<< endl
<< " SlaveConfig 1001:0, SM3 ( Input), LogAddr 0x00000006, Size 6"
<< endl
<< " 00 00 00 00 00 00" << endl
<< endl
<< "The process data are displayed as hexadecimal bytes." << endl
<< endl
<< "Command-specific options:" << endl
<< " --domain -d <index> Positive numerical domain index," << endl
<< " or 'all' for all domains (default)."
<< endl
<< " --verbose -v Show FMMUs and process data" << endl
<< " additionally." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandDomains::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (domainIndex == -1) {
unsigned int i;
ec_ioctl_master_t master;
masterDev.getMaster(&master);
m.getMaster(&master);
for (i = 0; i < master.domain_count; i++) {
showDomain(i);
showDomain(m, i);
}
} else {
showDomain(domainIndex);
showDomain(m, domainIndex);
}
}
/****************************************************************************/
void showDomain(unsigned int domainIndex)
void CommandDomains::showDomain(MasterDevice &m, unsigned int domainIndex)
{
ec_ioctl_domain_t domain;
unsigned char *processData;
@@ -81,7 +93,7 @@ void showDomain(unsigned int domainIndex)
ec_ioctl_domain_fmmu_t fmmu;
unsigned int dataOffset;
masterDev.getDomain(&domain, domainIndex);
m.getDomain(&domain, domainIndex);
cout << "Domain" << dec << domainIndex << ":"
<< " LogBaseAddr 0x"
@@ -93,20 +105,20 @@ void showDomain(unsigned int domainIndex)
<< domain.working_counter << "/"
<< domain.expected_working_counter << endl;
if (!domain.data_size || verbosity != Verbose)
if (!domain.data_size || getVerbosity() != Verbose)
return;
processData = new unsigned char[domain.data_size];
try {
masterDev.getData(&data, domainIndex, domain.data_size, processData);
m.getData(&data, domainIndex, domain.data_size, processData);
} catch (MasterDeviceException &e) {
delete [] processData;
throw e;
}
for (i = 0; i < domain.fmmu_count; i++) {
masterDev.getFmmu(&fmmu, domainIndex, i);
m.getFmmu(&fmmu, domainIndex, i);
cout << " SlaveConfig "
<< dec << fmmu.slave_config_alias
@@ -124,7 +136,7 @@ void showDomain(unsigned int domainIndex)
stringstream err;
delete [] processData;
err << "Fmmu information corrupted!";
throw CommandException(err);
throwCommandException(err);
}
cout << " " << hex << setfill('0');

29
tool/CommandDomains.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDDOMAINS_H__
#define __COMMANDDOMAINS_H__
#include "Command.h"
/****************************************************************************/
class CommandDomains:
public Command
{
public:
CommandDomains();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void showDomain(MasterDevice &, unsigned int);
};
/****************************************************************************/
#endif

View File

@@ -8,42 +8,58 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandDownload.h"
#include "coe_datatypes.h"
#include "byteorder.h"
/*****************************************************************************/
CommandDownload::CommandDownload():
Command("download", "Write an Sdo entry to a slave.")
{
}
/*****************************************************************************/
string CommandDownload::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS] <INDEX> <SUBINDEX> <VALUE>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "The data type of the Sdo entry is taken from the Sdo" << endl
<< "dictionary by default. It can be overridden with the" << endl
<< "--type option. If the slave does not support the Sdo" << endl
<< "information service or the Sdo is not in the dictionary," << endl
<< "the --type option is mandatory." << endl
<< endl
<< "These are the valid Sdo entry data types:" << endl
<< " int8, int16, int32, uint8, uint16, uint32, string." << endl
<< endl
<< "Arguments:"
<< " INDEX is the Sdo index and must be an unsigned" << endl
<< " 16 bit number." << endl
<< " SUBINDEX is the Sdo entry subindex and must be an" << endl
<< " unsigned 8 bit number." << endl
<< " VALUE is the value to download and must correspond" << endl
<< " to the Sdo entry datatype (see above)." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position" << endl
<< " (mandatory)." << endl
<< " --type -t <type> Forced Sdo entry data type (see" << endl
<< " above)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
const char *help_download =
"[OPTIONS] <INDEX> <SUBINDEX> <VALUE>\n"
"\n"
"Download an Sdo entry to a slave.\n"
"\n"
"The data type of the Sdo entry is taken from the Sdo dictionary by\n"
"default. It can be overridden with the --type option. If the slave\n"
"does not support the Sdo information service or the Sdo is not in the\n"
"dictionary, the --type option is mandatory.\n"
"\n"
"These are the valid Sdo entry data types:\n"
" int8, int16, int32, uint8, uint16, uint32, string.\n"
"\n"
"Arguments:\n"
" INDEX is the Sdo index and must be an unsigned 16 bit number.\n"
" SUBINDEX is the Sdo entry subindex and must be an unsigned 8 bit\n"
" number.\n"
" VALUE is the value to download and must correspond to the Sdo\n"
" entry datatype (see above).\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position (mandatory).\n"
" --type -t <type> Forced Sdo entry data type (see above).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void command_download(void)
void CommandDownload::execute(MasterDevice &m, const StringVector &args)
{
stringstream strIndex, strSubIndex, strValue, err;
ec_ioctl_slave_sdo_download_t data;
@@ -51,59 +67,59 @@ void command_download(void)
const CoEDataType *dataType = NULL;
if (slavePosition < 0) {
err << "'" << commandName << "' requires a slave! "
err << "'" << getName() << "' requires a slave! "
<< "Please specify --slave.";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
data.slave_position = slavePosition;
if (commandArgs.size() != 3) {
err << "'" << commandName << "' takes 3 arguments!";
throw InvalidUsageException(err);
if (args.size() != 3) {
err << "'" << getName() << "' takes 3 arguments!";
throwInvalidUsageException(err);
}
strIndex << commandArgs[0];
strIndex << args[0];
strIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> data.sdo_index;
if (strIndex.fail()) {
err << "Invalid Sdo index '" << commandArgs[0] << "'!";
throw InvalidUsageException(err);
err << "Invalid Sdo index '" << args[0] << "'!";
throwInvalidUsageException(err);
}
strSubIndex << commandArgs[1];
strSubIndex << args[1];
strSubIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> number;
if (strSubIndex.fail() || number > 0xff) {
err << "Invalid Sdo subindex '" << commandArgs[1] << "'!";
throw InvalidUsageException(err);
err << "Invalid Sdo subindex '" << args[1] << "'!";
throwInvalidUsageException(err);
}
data.sdo_entry_subindex = number;
if (dataTypeStr != "") { // data type specified
if (!(dataType = findDataType(dataTypeStr))) {
err << "Invalid data type '" << dataTypeStr << "'!";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
} else { // no data type specified: fetch from dictionary
ec_ioctl_slave_sdo_entry_t entry;
masterDev.open(MasterDevice::ReadWrite);
m.open(MasterDevice::ReadWrite);
try {
masterDev.getSdoEntry(&entry, slavePosition,
m.getSdoEntry(&entry, slavePosition,
data.sdo_index, data.sdo_entry_subindex);
} catch (MasterDeviceException &e) {
err << "Failed to determine Sdo entry data type. "
<< "Please specify --type.";
throw CommandException(err);
throwCommandException(err);
}
if (!(dataType = findDataType(entry.data_type))) {
err << "Pdo entry has unknown data type 0x"
<< hex << setfill('0') << setw(4) << entry.data_type << "!"
<< " Please specify --type.";
throw CommandException(err);
throwCommandException(err);
}
}
@@ -115,7 +131,7 @@ void command_download(void)
data.data = new uint8_t[data.data_size + 1];
strValue << commandArgs[2];
strValue << args[2];
strValue >> resetiosflags(ios::basefield); // guess base from prefix
strValue.exceptions(ios::failbit);
@@ -170,7 +186,7 @@ void command_download(void)
case 0x0009: // string
if (strValue.str().size() >= data.data_size) {
err << "String too large";
throw CommandException(err);
throwCommandException(err);
}
data.data_size = strValue.str().size();
strValue >> (char *) data.data;
@@ -179,19 +195,19 @@ void command_download(void)
default:
delete [] data.data;
err << "Unknown data type 0x" << hex << dataType->coeCode;
throw CommandException(err);
throwCommandException(err);
}
} catch (ios::failure &e) {
delete [] data.data;
err << "Invalid value argument '" << commandArgs[2]
err << "Invalid value argument '" << args[2]
<< "' for type '" << dataType->name << "'!";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
masterDev.open(MasterDevice::ReadWrite);
m.open(MasterDevice::ReadWrite);
try {
masterDev.sdoDownload(&data);
m.sdoDownload(&data);
} catch(MasterDeviceException &e) {
delete [] data.data;
throw e;

29
tool/CommandDownload.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDDOWNLOAD_H__
#define __COMMANDDOWNLOAD_H__
#include "Command.h"
/****************************************************************************/
class CommandDownload:
public Command
{
public:
CommandDownload();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
enum {DefaultBufferSize = 1024};
};
/****************************************************************************/
#endif

View File

@@ -8,31 +8,43 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandMaster.h"
/*****************************************************************************/
CommandMaster::CommandMaster():
Command("alias", "Show master and Ethernet device information.")
{
}
/****************************************************************************/
const char *help_master =
"[OPTIONS]\n"
"\n"
"Show master and Ethernet device information.\n"
"\n"
"Command-specific options:\n"
" --master -m <index> Index of the master to use. Default: 0.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
string CommandMaster::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Command-specific options:" << endl
<< " --master -m <index> Index of the master to use. Default: 0."
<< endl << endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void command_master(void)
void CommandMaster::execute(MasterDevice &m, const StringVector &args)
{
ec_ioctl_master_t data;
stringstream err;
unsigned int i;
masterDev.open(MasterDevice::Read);
masterDev.getMaster(&data);
m.open(MasterDevice::Read);
m.getMaster(&data);
cout
<< "Master" << masterIndex << endl

26
tool/CommandMaster.h Normal file
View File

@@ -0,0 +1,26 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDMASTER_H__
#define __COMMANDMASTER_H__
#include "Command.h"
/****************************************************************************/
class CommandMaster:
public Command
{
public:
CommandMaster();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
};
/****************************************************************************/
#endif

142
tool/CommandPdos.cpp Normal file
View File

@@ -0,0 +1,142 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <iostream>
#include <iomanip>
using namespace std;
#include "CommandPdos.h"
/*****************************************************************************/
CommandPdos::CommandPdos():
Command("pdos", "List Sync managers, Pdo assignment and mapping.")
{
}
/*****************************************************************************/
string CommandPdos::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "The information is displayed in three layers, which are" << endl
<< "indented accordingly:" << endl
<< endl
<< "1) Sync managers - Contains the sync manager information" << endl
<< " from the SII: Index, physical start address, default" << endl
<< " size (value from the SII), control register and enable" << endl
<< " word. Example:" << endl
<< endl
<< " SM3: PhysAddr 0x1100, DefaultSize 0, ControlRegister 0x20,"
<< "Enable 1" << endl
<< endl
<< "2) Assigned Pdos - Pdo direction, hexadecimal index and" << endl
<< " -if available- the Pdo name. Example:" << endl
<< endl
<< " TxPdo 0x1a00 \"Channel1\"" << endl
<< endl
<< "3) Mapped Pdo entries - Pdo entry index and subindex (both" << endl
<< " hexadecimal), the length in bit and -if available- the" << endl
<< " description. Example:" << endl
<< endl
<< " Pdo entry 0x3101:01, 8 bit, \"Status\"" << endl
<< endl
<< "Note, that the displayed Pdo assignment and Pdo mapping" << endl
<< "information can either originate from the SII or from the" << endl
<< "CoE communication area." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position," << endl
<< " or 'all' forall slaves (default)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandPdos::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (slavePosition == -1) {
unsigned int numSlaves = m.slaveCount(), i;
for (i = 0; i < numSlaves; i++) {
listSlavePdos(m, i, true);
}
} else {
listSlavePdos(m, slavePosition, false);
}
}
/****************************************************************************/
void CommandPdos::listSlavePdos(
MasterDevice &m,
uint16_t slavePosition,
bool withHeader
)
{
ec_ioctl_slave_t slave;
ec_ioctl_slave_sync_t sync;
ec_ioctl_slave_sync_pdo_t pdo;
ec_ioctl_slave_sync_pdo_entry_t entry;
unsigned int i, j, k;
m.getSlave(&slave, slavePosition);
if (withHeader)
cout << "=== Slave " << slavePosition << " ===" << endl;
for (i = 0; i < slave.sync_count; i++) {
m.getSync(&sync, slavePosition, i);
cout << "SM" << i << ":"
<< " PhysAddr 0x"
<< hex << setfill('0')
<< setw(4) << sync.physical_start_address
<< ", DefaultSize "
<< dec << setfill(' ') << setw(4) << sync.default_size
<< ", ControlRegister 0x"
<< hex << setfill('0') << setw(2)
<< (unsigned int) sync.control_register
<< ", Enable " << dec << (unsigned int) sync.enable
<< endl;
for (j = 0; j < sync.pdo_count; j++) {
m.getPdo(&pdo, slavePosition, i, j);
cout << " " << (sync.control_register & 0x04 ? "R" : "T")
<< "xPdo 0x"
<< hex << setfill('0')
<< setw(4) << pdo.index
<< " \"" << pdo.name << "\"" << endl;
if (getVerbosity() == Quiet)
continue;
for (k = 0; k < pdo.entry_count; k++) {
m.getPdoEntry(&entry, slavePosition, i, j, k);
cout << " Pdo entry 0x"
<< hex << setfill('0')
<< setw(4) << entry.index
<< ":" << setw(2) << (unsigned int) entry.subindex
<< ", " << dec << (unsigned int) entry.bit_length
<< " bit, \"" << entry.name << "\"" << endl;
}
}
}
}
/*****************************************************************************/

29
tool/CommandPdos.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDPDOS_H__
#define __COMMANDPDOS_H__
#include "Command.h"
/****************************************************************************/
class CommandPdos:
public Command
{
public:
CommandPdos();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void listSlavePdos(MasterDevice &, uint16_t, bool);
};
/****************************************************************************/
#endif

View File

@@ -8,63 +8,73 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandSdos.h"
#include "coe_datatypes.h"
/****************************************************************************/
/*****************************************************************************/
const char *help_sdos =
"[OPTIONS]\n"
"\n"
"Displays the Sdo dictionary with Sdos and Sdo entries.\n"
"\n"
"Sdo dictionary information is displayed in two layers, with are\n"
"indented accordingly:\n"
"\n"
"1) Sdos - Hexadecimal Sdo index and the name. Example:\n"
"\n"
" Sdo 0x1018, \"Identity object\"\n"
"\n"
"2) Sdo entries - Sdo index and Sdo entry subindex (both hexadecimal)\n"
" followed by the data type, the length in bit, and the description.\n"
" Example:\n"
"\n"
" 0x1018:01, uint32, 32 bit, \"Vendor id\"\n"
"\n"
"If the --quiet option is given, only the Sdos are printed.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default).\n"
" --quiet -q Print only Sdos (without Sdo entries).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void listSlaveSdos(uint16_t, bool);
/****************************************************************************/
void command_sdos(void)
CommandSdos::CommandSdos():
Command("sdos", "List Sdo dictionaries.")
{
masterDev.open(MasterDevice::Read);
}
/*****************************************************************************/
string CommandSdos::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Sdo dictionary information is displayed in two layers," << endl
<< "which are indented accordingly:" << endl
<< endl
<< "1) Sdos - Hexadecimal Sdo index and the name. Example:" << endl
<< endl
<< " Sdo 0x1018, \"Identity object\"" << endl
<< endl
<< "2) Sdo entries - Sdo index and Sdo entry subindex (both" << endl
<< " hexadecimal) followed by the data type, the length in" << endl
<< " bit, and the description. Example:" << endl
<< endl
<< " 0x1018:01, uint32, 32 bit, \"Vendor id\"" << endl
<< endl
<< "If the --quiet option is given, only the Sdos are printed."
<< endl << endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position," << endl
<< " 'all' for all slaves (default)." << endl
<< " --quiet -q Print only Sdos (without Sdo" << endl
<< " entries)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandSdos::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (slavePosition == -1) {
unsigned int numSlaves = masterDev.slaveCount(), i;
unsigned int numSlaves = m.slaveCount(), i;
for (i = 0; i < numSlaves; i++) {
listSlaveSdos(i, true);
listSlaveSdos(m, i, true);
}
} else {
listSlaveSdos(slavePosition, false);
listSlaveSdos(m, slavePosition, false);
}
}
/****************************************************************************/
void listSlaveSdos(
void CommandSdos::listSlaveSdos(
MasterDevice &m,
uint16_t slavePosition,
bool withHeader
)
@@ -75,24 +85,24 @@ void listSlaveSdos(
unsigned int i, j;
const CoEDataType *d;
masterDev.getSlave(&slave, slavePosition);
m.getSlave(&slave, slavePosition);
if (withHeader)
cout << "=== Slave " << slavePosition << " ===" << endl;
for (i = 0; i < slave.sdo_count; i++) {
masterDev.getSdo(&sdo, slavePosition, i);
m.getSdo(&sdo, slavePosition, i);
cout << "Sdo 0x"
<< hex << setfill('0')
<< setw(4) << sdo.sdo_index
<< ", \"" << sdo.name << "\"" << endl;
if (verbosity == Quiet)
if (getVerbosity() == Quiet)
continue;
for (j = 0; j <= sdo.max_subindex; j++) {
masterDev.getSdoEntry(&entry, slavePosition, -i, j);
m.getSdoEntry(&entry, slavePosition, -i, j);
cout << " 0x" << hex << setfill('0')
<< setw(4) << sdo.sdo_index << ":"

29
tool/CommandSdos.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDSDOS_H__
#define __COMMANDSDOS_H__
#include "Command.h"
/****************************************************************************/
class CommandSdos:
public Command
{
public:
CommandSdos();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void listSlaveSdos(MasterDevice &, uint16_t, bool);
};
/****************************************************************************/
#endif

View File

@@ -8,68 +8,47 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandSiiRead.h"
#include "byteorder.h"
/****************************************************************************/
/*****************************************************************************/
const char *help_sii_read =
"[OPTIONS]\n"
"\n"
"Outputs the SII (EEPROM) contents of a slave.\n"
"\n"
"Without the --verbose option, binary SII contents are output. They can\n"
"be piped to a tool like hexdump, for example:\n"
"\n"
" ethercat sii_read -s2 | hexdump -C\n"
"\n"
"With the --verbose option given, a textual representation of the data\n"
"is output, that is separated by SII category names.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position (mandatory).\n"
" --verbose -v Output textual data with category names.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
struct CategoryName {
uint16_t type;
const char *name;
};
static const CategoryName categoryNames[] = {
{0x000a, "STRINGS"},
{0x0014, "DataTypes"},
{0x001e, "General"},
{0x0028, "FMMU"},
{0x0029, "SyncM"},
{0x0032, "TXPDO"},
{0x0033, "RXPDO"},
{0x003c, "DC"},
{}
};
/****************************************************************************/
const char *getCategoryName(uint16_t type)
CommandSiiRead::CommandSiiRead():
Command("sii_read", "Output a slave's SII contents.")
{
const CategoryName *cn = categoryNames;
}
while (cn->type) {
if (cn->type == type) {
return cn->name;
}
cn++;
}
/*****************************************************************************/
return "unknown";
string CommandSiiRead::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Without the --verbose option, binary SII contents are" << endl
<< "output." << endl
<< endl
<< "With the --verbose option given, a textual representation" << endl
<< "of the data is output, that is separated by SII category" << endl
<< "names." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position" << endl
<< " (mandatory)." << endl
<< " --verbose -v Output textual data with" << endl
<< " category names." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void command_sii_read(void)
void CommandSiiRead::execute(MasterDevice &m, const StringVector &args)
{
ec_ioctl_slave_sii_t data;
ec_ioctl_slave_t slave;
@@ -79,15 +58,15 @@ void command_sii_read(void)
stringstream err;
if (slavePosition < 0) {
err << "'" << commandName << "' requires a slave! "
err << "'" << getName() << "' requires a slave! "
<< "Please specify --slave.";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
data.slave_position = slavePosition;
masterDev.open(MasterDevice::Read);
m.open(MasterDevice::Read);
masterDev.getSlave(&slave, slavePosition);
m.getSlave(&slave, slavePosition);
if (!slave.sii_nwords)
return;
@@ -97,13 +76,13 @@ void command_sii_read(void)
data.words = new uint16_t[data.nwords];
try {
masterDev.readSii(&data);
m.readSii(&data);
} catch (MasterDeviceException &e) {
delete [] data.words;
throw e;
}
if (verbosity == Verbose) {
if (getVerbosity() == Verbose) {
cout << "SII Area:" << hex << setfill('0');
for (i = 0; i < min(data.nwords, 0x0040U) * 2; i++) {
if (i % BreakAfterBytes) {
@@ -126,7 +105,7 @@ void command_sii_read(void)
if (categoryHeader + 1 > data.words + data.nwords) {
err << "SII data seem to be corrupted!";
throw CommandException(err);
throwCommandException(err);
}
categorySize = le16tocpu(*(categoryHeader + 1));
cout << ", " << dec << categorySize << " words" << flush;
@@ -134,7 +113,7 @@ void command_sii_read(void)
if (categoryHeader + 2 + categorySize
> data.words + data.nwords) {
err << "SII data seem to be corrupted!";
throw CommandException(err);
throwCommandException(err);
}
cout << hex;
@@ -152,7 +131,7 @@ void command_sii_read(void)
if (categoryHeader + 2 + categorySize + 1
> data.words + data.nwords) {
err << "SII data seem to be corrupted!";
throw CommandException(err);
throwCommandException(err);
}
categoryHeader += 2 + categorySize;
categoryType = le16tocpu(*categoryHeader);
@@ -168,4 +147,34 @@ void command_sii_read(void)
delete [] data.words;
}
/****************************************************************************/
const CommandSiiRead::CategoryName CommandSiiRead::categoryNames[] = {
{0x000a, "STRINGS"},
{0x0014, "DataTypes"},
{0x001e, "General"},
{0x0028, "FMMU"},
{0x0029, "SyncM"},
{0x0032, "TXPDO"},
{0x0033, "RXPDO"},
{0x003c, "DC"},
{}
};
/****************************************************************************/
const char *CommandSiiRead::getCategoryName(uint16_t type)
{
const CategoryName *cn = categoryNames;
while (cn->type) {
if (cn->type == type) {
return cn->name;
}
cn++;
}
return "unknown";
}
/*****************************************************************************/

34
tool/CommandSiiRead.h Normal file
View File

@@ -0,0 +1,34 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDSIIREAD_H__
#define __COMMANDSIIREAD_H__
#include "Command.h"
/****************************************************************************/
class CommandSiiRead:
public Command
{
public:
CommandSiiRead();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
struct CategoryName {
uint16_t type;
const char *name;
};
static const CategoryName categoryNames[];
static const char *getCategoryName(uint16_t);
};
/****************************************************************************/
#endif

View File

@@ -9,33 +9,47 @@
#include <fstream>
using namespace std;
#include "globals.h"
#include "CommandSiiWrite.h"
#include "sii_crc.h"
#include "byteorder.h"
/*****************************************************************************/
CommandSiiWrite::CommandSiiWrite():
Command("sii_write", "Write SII contents to a slave.")
{
}
/*****************************************************************************/
string CommandSiiWrite::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS] <FILENAME>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "The file contents are checked for validity and integrity." << endl
<< "These checks can be overridden with the --force option." << endl
<< endl
<< "Arguments:" << endl
<< " FILENAME must be a path to a file that contains a" << endl
<< " positive number of words." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position" << endl
<< " (mandatory)." << endl
<< " --force -f Override validity checks." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
const char *help_sii_write =
"[OPTIONS] <FILENAME>\n"
"\n"
"Writes SII contents from a local file to a slave.\n"
"\n"
"The file contents are checked for validity and integrity. These checks\n"
"can be overridden with the --force option.\n"
"\n"
"Arguments:\n"
" FILENAME must be a path to a file that contains a positive number\n"
" of words.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position (mandatory).\n"
" --force Override validity checks.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void command_sii_write(void)
void CommandSiiWrite::execute(MasterDevice &m, const StringVector &args)
{
stringstream err;
ec_ioctl_slave_sii_t data;
@@ -46,21 +60,21 @@ void command_sii_write(void)
uint8_t crc;
if (slavePosition < 0) {
err << "'" << commandName << "' requires a slave! "
err << "'" << getName() << "' requires a slave! "
<< "Please specify --slave.";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
data.slave_position = slavePosition;
if (commandArgs.size() != 1) {
err << "'" << commandName << "' takes exactly one argument!";
throw InvalidUsageException(err);
if (args.size() != 1) {
err << "'" << getName() << "' takes exactly one argument!";
throwInvalidUsageException(err);
}
file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary);
file.open(args[0].c_str(), ifstream::in | ifstream::binary);
if (file.fail()) {
err << "Failed to open '" << commandArgs[0] << "'!";
throw CommandException(err);
err << "Failed to open '" << args[0] << "'!";
throwCommandException(err);
}
// get length of file
@@ -70,14 +84,14 @@ void command_sii_write(void)
if (!byte_size || byte_size % 2) {
err << "Invalid file size! Must be non-zero and even.";
throw CommandException(err);
throwCommandException(err);
}
data.nwords = byte_size / 2;
if (data.nwords < 0x0041 && !force) {
err << "SII data too short (" << data.nwords << " words)! Mimimum is"
" 40 fixed words + 1 delimiter. Use --force to write anyway.";
throw CommandException(err);
throwCommandException(err);
}
// allocate buffer and read file into buffer
@@ -92,7 +106,7 @@ void command_sii_write(void)
err << "CRC incorrect. Must be 0x"
<< hex << setfill('0') << setw(2) << (unsigned int) crc
<< ". Use --force to write anyway.";
throw CommandException(err);
throwCommandException(err);
}
// cycle through categories to detect corruption
@@ -102,14 +116,14 @@ void command_sii_write(void)
if (categoryHeader + 1 > data.words + data.nwords) {
err << "SII data seem to be corrupted! "
<< "Use --force to write anyway.";
throw CommandException(err);
throwCommandException(err);
}
categorySize = le16tocpu(*(categoryHeader + 1));
if (categoryHeader + 2 + categorySize + 1
> data.words + data.nwords) {
err << "SII data seem to be corrupted! "
"Use --force to write anyway.";
throw CommandException(err);
throwCommandException(err);
}
categoryHeader += 2 + categorySize;
categoryType = le16tocpu(*categoryHeader);
@@ -117,9 +131,9 @@ void command_sii_write(void)
}
// send data to master
masterDev.open(MasterDevice::ReadWrite);
m.open(MasterDevice::ReadWrite);
data.offset = 0;
masterDev.writeSii(&data);
m.writeSii(&data);
}
/*****************************************************************************/

26
tool/CommandSiiWrite.h Normal file
View File

@@ -0,0 +1,26 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDSIIWRITE_H__
#define __COMMANDSIIWRITE_H__
#include "Command.h"
/****************************************************************************/
class CommandSiiWrite:
public Command
{
public:
CommandSiiWrite();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
};
/****************************************************************************/
#endif

View File

@@ -9,112 +9,103 @@
#include <list>
using namespace std;
#include "globals.h"
#include "CommandSlaves.h"
/****************************************************************************/
/*****************************************************************************/
const char *help_slaves =
"[OPTIONS]\n"
"\n"
"Display slaves on the bus.\n"
"\n"
"If the --verbose option is not given, the slaves are displayed\n"
"one-per-line. Example:\n"
"\n"
"1 5555:0 PREOP + EL3162 2C. Ana. Input 0-10V\n"
"| | | | | |\n"
"| | | | | \\- Name from SII if avaliable, otherwise\n"
"| | | | | hexadecimal vendor ID and product code\n"
"| | | | | separated by a colon.\n"
"| | | | \\- Error flag. '+' means no error, 'E' means,\n"
"| | | | that scanning or configuration failed.\n"
"| | | \\- Current slave state.\n"
"| | \\- Relative position (decimal) after the last slave with an\n"
"| | alias address set.\n"
"| \\- Alias address of the slave (if set to non-zero), or the alias\n"
"| of the last slave with an alias set, or zero if there is none.\n"
"\\- Ring position (use this with any --slave option).\n"
"\n"
"If the --verbose option is given, a detailed (multi-line) description\n"
"is output for each slave.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default).\n"
" --verbose -v Show detailed slave information.\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void listSlaves(int);
void showSlave(uint16_t);
/****************************************************************************/
void command_slaves()
CommandSlaves::CommandSlaves():
Command("slaves", "Display slaves on the bus.")
{
masterDev.open(MasterDevice::Read);
}
if (verbosity == Verbose) {
/*****************************************************************************/
string CommandSlaves::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "If the --verbose option is not given, the slaves are" << endl
<< "displayed one-per-line. Example:" << endl
<< endl
<< "1 5555:0 PREOP + EL3162 2C. Ana. Input 0-10V" << endl
<< "| | | | | |" << endl
<< "| | | | | \\- Name from SII if avaliable," << endl
<< "| | | | | otherwise hexadecimal vendor ID" << endl
<< "| | | | | and product code separated by a" << endl
<< "| | | | | colon." << endl
<< "| | | | \\- Error flag. '+' means no error," << endl
<< "| | | | 'E' means that scanning or" << endl
<< "| | | | configuration failed." << endl
<< "| | | \\- Current slave state." << endl
<< "| | \\- Relative position (decimal) after the last" << endl
<< "| | slave with an alias address set." << endl
<< "| \\- Alias address of the slave (if set to non-zero)," << endl
<< "| or the alias of the last slave with an alias set," << endl
<< "| or zero if there is none." << endl
<< "\\- Ring position (use this with any --slave option)." << endl
<< endl
<< "If the --verbose option is given, a detailed (multi-line)" << endl
<< "description is output for each slave." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position," << endl
<< " or 'all' for all slaves (default)." << endl
<< " --verbose -v Show detailed slave information." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandSlaves::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (getVerbosity() == Verbose) {
if (slavePosition == -1) {
unsigned int numSlaves = masterDev.slaveCount(), i;
unsigned int numSlaves = m.slaveCount(), i;
for (i = 0; i < numSlaves; i++) {
showSlave(i);
showSlave(m, i);
}
} else {
showSlave(slavePosition);
showSlave(m, slavePosition);
}
} else {
listSlaves(slavePosition);
listSlaves(m, slavePosition);
}
}
/****************************************************************************/
string slaveState(uint8_t state)
{
switch (state) {
case 1: return "INIT";
case 2: return "PREOP";
case 4: return "SAFEOP";
case 8: return "OP";
default: return "???";
}
}
/****************************************************************************/
struct SlaveInfo {
string pos;
string alias;
string relPos;
string state;
string flag;
string name;
};
void listSlaves(int slavePosition)
void CommandSlaves::listSlaves(
MasterDevice &m,
int slavePosition
)
{
unsigned int numSlaves, i;
ec_ioctl_slave_t slave;
uint16_t lastAlias, aliasIndex;
SlaveInfo slaveInfo;
typedef list<SlaveInfo> SlaveInfoList;
SlaveInfoList slaveInfoList;
SlaveInfoList::const_iterator iter;
Info info;
typedef list<Info> InfoList;
InfoList infoList;
InfoList::const_iterator iter;
stringstream str;
unsigned int maxPosWidth = 0, maxAliasWidth = 0,
maxRelPosWidth = 0, maxStateWidth = 0;
numSlaves = masterDev.slaveCount();
numSlaves = m.slaveCount();
lastAlias = 0;
aliasIndex = 0;
for (i = 0; i < numSlaves; i++) {
masterDev.getSlave(&slave, i);
m.getSlave(&slave, i);
if (slave.alias) {
lastAlias = slave.alias;
@@ -123,48 +114,48 @@ void listSlaves(int slavePosition)
if (slavePosition == -1 || i == (unsigned int) slavePosition) {
str << dec << i;
slaveInfo.pos = str.str();
info.pos = str.str();
str.clear();
str.str("");
str << lastAlias;
slaveInfo.alias = str.str();
info.alias = str.str();
str.str("");
str << aliasIndex;
slaveInfo.relPos = str.str();
info.relPos = str.str();
str.str("");
slaveInfo.state = slaveState(slave.state);
slaveInfo.flag = (slave.error_flag ? 'E' : '+');
info.state = slaveState(slave.state);
info.flag = (slave.error_flag ? 'E' : '+');
if (strlen(slave.name)) {
slaveInfo.name = slave.name;
info.name = slave.name;
} else {
str << "0x" << hex << setfill('0')
<< setw(8) << slave.vendor_id << ":0x"
<< setw(8) << slave.product_code;
slaveInfo.name = str.str();
info.name = str.str();
str.str("");
}
slaveInfoList.push_back(slaveInfo);
infoList.push_back(info);
if (slaveInfo.pos.length() > maxPosWidth)
maxPosWidth = slaveInfo.pos.length();
if (slaveInfo.alias.length() > maxAliasWidth)
maxAliasWidth = slaveInfo.alias.length();
if (slaveInfo.relPos.length() > maxRelPosWidth)
maxRelPosWidth = slaveInfo.relPos.length();
if (slaveInfo.state.length() > maxStateWidth)
maxStateWidth = slaveInfo.state.length();
if (info.pos.length() > maxPosWidth)
maxPosWidth = info.pos.length();
if (info.alias.length() > maxAliasWidth)
maxAliasWidth = info.alias.length();
if (info.relPos.length() > maxRelPosWidth)
maxRelPosWidth = info.relPos.length();
if (info.state.length() > maxStateWidth)
maxStateWidth = info.state.length();
}
aliasIndex++;
}
for (iter = slaveInfoList.begin(); iter != slaveInfoList.end(); iter++) {
for (iter = infoList.begin(); iter != infoList.end(); iter++) {
cout << setfill(' ') << right
<< setw(maxPosWidth) << iter->pos << " "
<< setw(maxAliasWidth) << iter->alias
@@ -178,13 +169,16 @@ void listSlaves(int slavePosition)
/****************************************************************************/
void showSlave(uint16_t slavePosition)
void CommandSlaves::showSlave(
MasterDevice &m,
uint16_t slavePosition
)
{
ec_ioctl_slave_t slave;
list<string> protoList;
list<string>::const_iterator protoIter;
masterDev.getSlave(&slave, slavePosition);
m.getSlave(&slave, slavePosition);
cout << "=== Slave " << dec << slavePosition << " ===" << endl;
@@ -280,4 +274,17 @@ void showSlave(uint16_t slavePosition)
}
}
/****************************************************************************/
string CommandSlaves::slaveState(uint8_t state)
{
switch (state) {
case 1: return "INIT";
case 2: return "PREOP";
case 4: return "SAFEOP";
case 8: return "OP";
default: return "???";
}
}
/*****************************************************************************/

41
tool/CommandSlaves.h Normal file
View File

@@ -0,0 +1,41 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDSLAVES_H__
#define __COMMANDSLAVES_H__
#include "Command.h"
/****************************************************************************/
class CommandSlaves:
public Command
{
public:
CommandSlaves();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
struct Info {
string pos;
string alias;
string relPos;
string state;
string flag;
string name;
};
void listSlaves(MasterDevice &, int);
void showSlave(MasterDevice &, uint16_t);
static string slaveState(uint8_t);
};
/****************************************************************************/
#endif

82
tool/CommandStates.cpp Normal file
View File

@@ -0,0 +1,82 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <iostream>
using namespace std;
#include "CommandStates.h"
/*****************************************************************************/
CommandStates::CommandStates():
Command("states", "Request application-layer states.")
{
}
/*****************************************************************************/
string CommandStates::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS] <STATE>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "Arguments:" << endl
<< " STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'" << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position," << endl
<< " or 'all' for all slaves (default)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandStates::execute(MasterDevice &m, const StringVector &args)
{
stringstream err;
string stateStr;
uint8_t state = 0x00;
if (args.size() != 1) {
err << "'" << getName() << "' takes exactly one argument!";
throwInvalidUsageException(err);
}
stateStr = args[0];
transform(stateStr.begin(), stateStr.end(),
stateStr.begin(), (int (*) (int)) std::toupper);
if (stateStr == "INIT") {
state = 0x01;
} else if (stateStr == "PREOP") {
state = 0x02;
} else if (stateStr == "SAFEOP") {
state = 0x04;
} else if (stateStr == "OP") {
state = 0x08;
} else {
err << "Invalid state '" << args[0] << "'!";
throwInvalidUsageException(err);
}
m.open(MasterDevice::ReadWrite);
if (slavePosition == -1) {
unsigned int i, numSlaves = m.slaveCount();
for (i = 0; i < numSlaves; i++)
m.requestState(i, state);
} else {
m.requestState(slavePosition, state);
}
}
/*****************************************************************************/

28
tool/CommandStates.h Normal file
View File

@@ -0,0 +1,28 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDSTATES_H__
#define __COMMANDSTATES_H__
#include "Command.h"
/****************************************************************************/
class CommandStates:
public Command
{
public:
CommandStates();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
};
/****************************************************************************/
#endif

View File

@@ -8,39 +8,56 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandUpload.h"
#include "coe_datatypes.h"
#include "byteorder.h"
/*****************************************************************************/
CommandUpload::CommandUpload():
Command("upload", "Read an Sdo entry from a slave.")
{
}
/*****************************************************************************/
string CommandUpload::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS] <INDEX> <SUBINDEX>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
<< "The data type of the Sdo entry is taken from the Sdo" << endl
<< "dictionary by default. It can be overridden with the" << endl
<< "--type option. If the slave does not support the Sdo" << endl
<< "information service or the Sdo is not in the dictionary," << endl
<< "the --type option is mandatory." << endl
<< endl
<< "These are the valid Sdo entry data types:" << endl
<< " int8, int16, int32, uint8, uint16, uint32, string." << endl
<< endl
<< "Arguments:" << endl
<< " INDEX is the Sdo index and must be an unsigned" << endl
<< " 16 bit number." << endl
<< " SUBINDEX is the Sdo entry subindex and must be an" << endl
<< " unsigned 8 bit number." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position" << endl
<< " (mandatory)." << endl
<< " --type -t <type> Forced Sdo entry data type (see" << endl
<< " above)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
const char *help_upload =
"[OPTIONS] <INDEX> <SUBINDEX>\n"
"\n"
"Upload an Sdo entry from a slave.\n"
"\n"
"The data type of the Sdo entry is taken from the Sdo dictionary by\n"
"default. It can be overridden with the --type option. If the slave\n"
"does not support the Sdo information service or the Sdo is not in the\n"
"dictionary, the --type option is mandatory.\n"
"\n"
"These are the valid Sdo entry data types:\n"
" int8, int16, int32, uint8, uint16, uint32, string.\n"
"\n"
"Arguments:\n"
" INDEX is the Sdo index and must be an unsigned 16 bit number.\n"
" SUBINDEX is the Sdo entry subindex and must be an unsigned 8 bit\n"
" number.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position (mandatory).\n"
" --type -t <type> Forced Sdo entry data type (see above).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void command_upload(void)
void CommandUpload::execute(MasterDevice &m, const StringVector &args)
{
stringstream err, strIndex, strSubIndex;
int sval;
@@ -49,59 +66,59 @@ void command_upload(void)
const CoEDataType *dataType = NULL;
if (slavePosition < 0) {
err << "'" << commandName << "' requires a slave! "
err << "'" << getName() << "' requires a slave! "
<< "Please specify --slave.";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
data.slave_position = slavePosition;
if (commandArgs.size() != 2) {
err << "'" << commandName << "' takes two arguments!";
throw InvalidUsageException(err);
if (args.size() != 2) {
err << "'" << getName() << "' takes two arguments!";
throwInvalidUsageException(err);
}
strIndex << commandArgs[0];
strIndex << args[0];
strIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> data.sdo_index;
if (strIndex.fail()) {
err << "Invalid Sdo index '" << commandArgs[0] << "'!";
throw InvalidUsageException(err);
err << "Invalid Sdo index '" << args[0] << "'!";
throwInvalidUsageException(err);
}
strSubIndex << commandArgs[1];
strSubIndex << args[1];
strSubIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> uval;
if (strSubIndex.fail() || uval > 0xff) {
err << "Invalid Sdo subindex '" << commandArgs[1] << "'!";
throw InvalidUsageException(err);
err << "Invalid Sdo subindex '" << args[1] << "'!";
throwInvalidUsageException(err);
}
data.sdo_entry_subindex = uval;
if (dataTypeStr != "") { // data type specified
if (!(dataType = findDataType(dataTypeStr))) {
err << "Invalid data type '" << dataTypeStr << "'!";
throw InvalidUsageException(err);
throwInvalidUsageException(err);
}
} else { // no data type specified: fetch from dictionary
ec_ioctl_slave_sdo_entry_t entry;
masterDev.open(MasterDevice::Read);
m.open(MasterDevice::Read);
try {
masterDev.getSdoEntry(&entry, slavePosition,
m.getSdoEntry(&entry, slavePosition,
data.sdo_index, data.sdo_entry_subindex);
} catch (MasterDeviceException &e) {
err << "Failed to determine Sdo entry data type. "
<< "Please specify --type.";
throw CommandException(err);
throwCommandException(err);
}
if (!(dataType = findDataType(entry.data_type))) {
err << "Pdo entry has unknown data type 0x"
<< hex << setfill('0') << setw(4) << entry.data_type << "!"
<< " Please specify --type.";
throw CommandException(err);
throwCommandException(err);
}
}
@@ -113,22 +130,22 @@ void command_upload(void)
data.target = new uint8_t[data.target_size + 1];
masterDev.open(MasterDevice::Read);
m.open(MasterDevice::Read);
try {
masterDev.sdoUpload(&data);
m.sdoUpload(&data);
} catch (MasterDeviceException &e) {
delete [] data.target;
throw e;
}
masterDev.close();
m.close();
if (dataType->byteSize && data.data_size != dataType->byteSize) {
err << "Data type mismatch. Expected " << dataType->name
<< " with " << dataType->byteSize << " byte, but got "
<< data.data_size << " byte.";
throw CommandException(err);
throwCommandException(err);
}
cout << setfill('0');
@@ -162,11 +179,27 @@ void command_upload(void)
<< endl;
break;
default:
printRawData(data.target, data.data_size);
printRawData(data.target, data.data_size); // FIXME
break;
}
delete [] data.target;
}
/****************************************************************************/
void CommandUpload::printRawData(
const uint8_t *data,
unsigned int size
)
{
cout << hex << setfill('0');
while (size--) {
cout << "0x" << setw(2) << (unsigned int) *data++;
if (size)
cout << " ";
}
cout << endl;
}
/*****************************************************************************/

31
tool/CommandUpload.h Normal file
View File

@@ -0,0 +1,31 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDUPLOAD_H__
#define __COMMANDUPLOAD_H__
#include "Command.h"
/****************************************************************************/
class CommandUpload:
public Command
{
public:
CommandUpload();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
enum {DefaultBufferSize = 1024};
static void printRawData(const uint8_t *, unsigned int);
};
/****************************************************************************/
#endif

View File

@@ -8,50 +8,59 @@
#include <iomanip>
using namespace std;
#include "globals.h"
#include "CommandXml.h"
/****************************************************************************/
/*****************************************************************************/
const char *help_xml =
"[OPTIONS]\n"
"\n"
"Generate slave description XMLs from the master's slave information.\n"
"\n"
"Note that the Pdo information can either originate from the SII or\n"
"from the CoE communication area. For some slaves, this is dependant on\n"
"the last slave configuration.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void generateSlaveXml(uint16_t);
/****************************************************************************/
void command_xml(void)
CommandXml::CommandXml():
Command("xml", "Generate slave information XML.")
{
masterDev.open(MasterDevice::Read);
}
/*****************************************************************************/
string CommandXml::helpString() const
{
stringstream str;
str << getName() << " [OPTIONS]"
<< endl
<< getBriefDescription() << endl
<< endl
<< "Note that the Pdo information can either originate" << endl
<< "from the SII or from the CoE communication area. For" << endl
<< "some slaves, this is dependant on the last slave" << endl
<< "configuration." << endl
<< endl
<< "Command-specific options:" << endl
<< " --slave -s <index> Positive numerical ring position," << endl
<< " or 'all' for all slaves (default)." << endl
<< endl
<< numericInfo();
return str.str();
}
/****************************************************************************/
void CommandXml::execute(MasterDevice &m, const StringVector &args)
{
m.open(MasterDevice::Read);
if (slavePosition == -1) {
unsigned int numSlaves = masterDev.slaveCount(), i;
unsigned int numSlaves = m.slaveCount(), i;
for (i = 0; i < numSlaves; i++) {
generateSlaveXml(i);
generateSlaveXml(m, i);
}
} else {
generateSlaveXml(slavePosition);
generateSlaveXml(m, slavePosition);
}
}
/****************************************************************************/
void generateSlaveXml(uint16_t slavePosition)
void CommandXml::generateSlaveXml(MasterDevice &m, uint16_t slavePosition)
{
ec_ioctl_slave_t slave;
ec_ioctl_slave_sync_t sync;
@@ -60,7 +69,7 @@ void generateSlaveXml(uint16_t slavePosition)
ec_ioctl_slave_sync_pdo_entry_t entry;
unsigned int i, j, k;
masterDev.getSlave(&slave, slavePosition);
m.getSlave(&slave, slavePosition);
cout
<< "<?xml version=\"1.0\" ?>" << endl
@@ -86,7 +95,7 @@ void generateSlaveXml(uint16_t slavePosition)
}
for (i = 0; i < slave.sync_count; i++) {
masterDev.getSync(&sync, slavePosition, i);
m.getSync(&sync, slavePosition, i);
cout
<< " <Sm Enable=\"" << dec << (unsigned int) sync.enable
@@ -97,10 +106,10 @@ void generateSlaveXml(uint16_t slavePosition)
}
for (i = 0; i < slave.sync_count; i++) {
masterDev.getSync(&sync, slavePosition, i);
m.getSync(&sync, slavePosition, i);
for (j = 0; j < sync.pdo_count; j++) {
masterDev.getPdo(&pdo, slavePosition, i, j);
m.getPdo(&pdo, slavePosition, i, j);
pdoType = (sync.control_register & 0x04 ? "R" : "T");
pdoType += "xPdo";
@@ -113,7 +122,7 @@ void generateSlaveXml(uint16_t slavePosition)
<< " <Name>" << pdo.name << "</Name>" << endl;
for (k = 0; k < pdo.entry_count; k++) {
masterDev.getPdoEntry(&entry, slavePosition, i, j, k);
m.getPdoEntry(&entry, slavePosition, i, j, k);
cout
<< " <Entry>" << endl

29
tool/CommandXml.h Normal file
View File

@@ -0,0 +1,29 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#ifndef __COMMANDXML_H__
#define __COMMANDXML_H__
#include "Command.h"
/****************************************************************************/
class CommandXml:
public Command
{
public:
CommandXml();
string helpString() const;
void execute(MasterDevice &, const StringVector &);
protected:
void generateSlaveXml(MasterDevice &, uint16_t);
};
/****************************************************************************/
#endif

View File

@@ -29,30 +29,33 @@
# standard) as the (only) precondition to have the right to use EtherCAT
# Technology, IP and trade marks.
#
# vim: syntax=make
#
#------------------------------------------------------------------------------
bin_PROGRAMS = ethercat
ethercat_SOURCES = \
MasterDevice.cpp MasterDevice.h \
MasterDevice.cpp MasterDevice.h \
Command.cpp \
CommandAlias.cpp \
CommandConfig.cpp \
CommandData.cpp \
CommandDebug.cpp \
CommandDomains.cpp \
CommandDownload.cpp \
CommandMaster.cpp \
CommandPdos.cpp \
CommandSdos.cpp \
CommandSiiRead.cpp \
CommandSiiWrite.cpp \
CommandSlaves.cpp \
CommandStates.cpp \
CommandUpload.cpp \
CommandXml.cpp \
coe_datatypes.cpp \
sii_crc.cpp \
cmd_alias.cpp \
cmd_config.cpp \
cmd_data.cpp \
cmd_debug.cpp \
cmd_domain.cpp \
cmd_master.cpp \
cmd_pdos.cpp \
cmd_sdos.cpp \
cmd_download.cpp \
cmd_upload.cpp \
cmd_slaves.cpp \
cmd_sii_read.cpp \
cmd_sii_write.cpp \
cmd_states.cpp \
cmd_xml.cpp \
main.cpp
main.cpp
ethercat_CXXFLAGS = -I../master -Wall

40
tool/byteorder.h Normal file
View File

@@ -0,0 +1,40 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <sys/types.h>
/*****************************************************************************/
#define swap16(x) \
((uint16_t)( \
(((uint16_t)(x) & 0x00ffU) << 8) | \
(((uint16_t)(x) & 0xff00U) >> 8) ))
#define swap32(x) \
((uint32_t)( \
(((uint32_t)(x) & 0x000000ffUL) << 24) | \
(((uint32_t)(x) & 0x0000ff00UL) << 8) | \
(((uint32_t)(x) & 0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & 0xff000000UL) >> 24) ))
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le16tocpu(x) x
#define le32tocpu(x) x
#define cputole16(x) x
#define cputole32(x) x
#elif __BYTE_ORDER == __BIG_ENDIAN
#define le16tocpu(x) swap16(x)
#define le32tocpu(x) swap32(x)
#define cputole16(x) swap16(x)
#define cputole32(x) swap32(x)
#endif
/****************************************************************************/

View File

@@ -1,58 +0,0 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <sstream>
#include <iomanip>
using namespace std;
#include "globals.h"
/*****************************************************************************/
const char *help_debug =
"<LEVEL>\n"
"\n"
"Set the master debug level.\n"
"\n"
"Debug messages are printed to syslog.\n"
"\n"
"Arguments:\n"
" LEVEL can have one of the following values:\n"
" 0 for no debugging output,\n"
" 1 for some debug messages, or\n"
" 2 for printing all frame contents (use with caution!).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void command_debug(void)
{
stringstream str;
int debugLevel;
if (commandArgs.size() != 1) {
stringstream err;
err << "'" << commandName << "' takes exactly one argument!";
throw InvalidUsageException(err);
}
str << commandArgs[0];
str >> resetiosflags(ios::basefield) // guess base from prefix
>> debugLevel;
if (str.fail()) {
stringstream err;
err << "Invalid debug level '" << commandArgs[0] << "'!";
throw InvalidUsageException(err);
}
masterDev.open(MasterDevice::ReadWrite);
masterDev.setDebug(debugLevel);
}
/*****************************************************************************/

View File

@@ -1,127 +0,0 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <iostream>
#include <iomanip>
using namespace std;
#include "globals.h"
/****************************************************************************/
const char *help_pdos =
"[OPTIONS]\n"
"\n"
"Displays sync managers, assigned Pdos and mapped Pdo entries.\n"
"\n"
"The information is displayed in three layers, which are indented\n"
"accordingly:\n"
"\n"
"1) Sync managers - Contains the sync manager information from the\n"
" SII: Index, physical start address, default size (raw value from\n"
" the SII), control register and enable word. Example:\n"
"\n"
" SM3: PhysAddr 0x1100, DefaultSize 0, ControlRegister 0x20, Enable 1\n"
"\n"
"2) Assigned Pdos - Pdo direction, hexadecimal index and -if available-\n"
" the Pdo name. Example:\n"
"\n"
" TxPdo 0x1a00 \"Channel1\"\n"
"\n"
"3) Mapped Pdo entries - Pdo entry index and subindex (both\n"
" hexadecimal), the length in bit and -if available- the\n"
" description. Example:\n"
"\n"
" Pdo entry 0x3101:01, 8 bit, \"Status\"\n"
"\n"
"Note, that the displayed Pdo assignment and Pdo mapping information\n"
"can either originate from the SII or from the CoE communication area.\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void listSlavePdos(uint16_t, bool);
/****************************************************************************/
void command_pdos(void)
{
masterDev.open(MasterDevice::Read);
if (slavePosition == -1) {
unsigned int numSlaves = masterDev.slaveCount(), i;
for (i = 0; i < numSlaves; i++) {
listSlavePdos(i, true);
}
} else {
listSlavePdos(slavePosition, false);
}
}
/****************************************************************************/
void listSlavePdos(uint16_t slavePosition, bool withHeader)
{
ec_ioctl_slave_t slave;
ec_ioctl_slave_sync_t sync;
ec_ioctl_slave_sync_pdo_t pdo;
ec_ioctl_slave_sync_pdo_entry_t entry;
unsigned int i, j, k;
masterDev.getSlave(&slave, slavePosition);
if (withHeader)
cout << "=== Slave " << slavePosition << " ===" << endl;
for (i = 0; i < slave.sync_count; i++) {
masterDev.getSync(&sync, slavePosition, i);
cout << "SM" << i << ":"
<< " PhysAddr 0x"
<< hex << setfill('0')
<< setw(4) << sync.physical_start_address
<< ", DefaultSize "
<< dec << setfill(' ') << setw(4) << sync.default_size
<< ", ControlRegister 0x"
<< hex << setfill('0') << setw(2)
<< (unsigned int) sync.control_register
<< ", Enable " << dec << (unsigned int) sync.enable
<< endl;
for (j = 0; j < sync.pdo_count; j++) {
masterDev.getPdo(&pdo, slavePosition, i, j);
cout << " " << (sync.control_register & 0x04 ? "R" : "T")
<< "xPdo 0x"
<< hex << setfill('0')
<< setw(4) << pdo.index
<< " \"" << pdo.name << "\"" << endl;
if (verbosity == Quiet)
continue;
for (k = 0; k < pdo.entry_count; k++) {
masterDev.getPdoEntry(&entry, slavePosition, i, j, k);
cout << " Pdo entry 0x"
<< hex << setfill('0')
<< setw(4) << entry.index
<< ":" << setw(2) << (unsigned int) entry.subindex
<< ", " << dec << (unsigned int) entry.bit_length
<< " bit, \"" << entry.name << "\"" << endl;
}
}
}
}
/*****************************************************************************/

View File

@@ -1,70 +0,0 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <iostream>
using namespace std;
#include "globals.h"
/****************************************************************************/
const char *help_states =
"[OPTIONS] <STATE>\n"
"\n"
"Request an application-layer state change for the specified slaves.\n"
"\n"
"Arguments:\n"
" STATE can be 'INIT', 'PREOP', 'SAFEOP', or 'OP'\n"
"\n"
"Command-specific options:\n"
" --slave -s <index> Positive numerical ring position, or 'all' for\n"
" all slaves (default).\n"
"\n"
"Numerical values can be specified either with decimal (no prefix),\n"
"octal (prefix '0') or hexadecimal (prefix '0x') base.\n";
/****************************************************************************/
void command_states(void)
{
stringstream err;
string stateStr;
uint8_t state;
if (commandArgs.size() != 1) {
err << "'" << commandName << "' takes exactly one argument!";
throw InvalidUsageException(err);
}
stateStr = commandArgs[0];
transform(stateStr.begin(), stateStr.end(),
stateStr.begin(), (int (*) (int)) std::toupper);
if (stateStr == "INIT") {
state = 0x01;
} else if (stateStr == "PREOP") {
state = 0x02;
} else if (stateStr == "SAFEOP") {
state = 0x04;
} else if (stateStr == "OP") {
state = 0x08;
} else {
err << "Invalid state '" << commandArgs[0] << "'!";
throw InvalidUsageException(err);
}
masterDev.open(MasterDevice::ReadWrite);
if (slavePosition == -1) {
unsigned int i, numSlaves = masterDev.slaveCount();
for (i = 0; i < numSlaves; i++)
masterDev.requestState(i, state);
} else {
masterDev.requestState(slavePosition, state);
}
}
/*****************************************************************************/

View File

@@ -1,97 +0,0 @@
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <sys/types.h>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#include "MasterDevice.h"
/*****************************************************************************/
enum Verbosity {
Quiet,
Normal,
Verbose
};
extern string commandName;
extern unsigned int masterIndex;
extern int slavePosition;
extern int domainIndex;
extern vector<string> commandArgs;
extern Verbosity verbosity;
extern string dataTypeStr;
extern bool force;
extern MasterDevice masterDev;
/****************************************************************************/
class InvalidUsageException:
public runtime_error
{
public:
/** Constructor with std::string parameter. */
InvalidUsageException(
const stringstream &s /**< Message. */
): runtime_error(s.str()) {}
};
/****************************************************************************/
class CommandException:
public runtime_error
{
public:
/** Constructor with std::string parameter. */
CommandException(
const stringstream &s /**< Message. */
): runtime_error(s.str()) {}
};
/*****************************************************************************/
#define swap16(x) \
((uint16_t)( \
(((uint16_t)(x) & 0x00ffU) << 8) | \
(((uint16_t)(x) & 0xff00U) >> 8) ))
#define swap32(x) \
((uint32_t)( \
(((uint32_t)(x) & 0x000000ffUL) << 24) | \
(((uint32_t)(x) & 0x0000ff00UL) << 8) | \
(((uint32_t)(x) & 0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & 0xff000000UL) >> 24) ))
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le16tocpu(x) x
#define le32tocpu(x) x
#define cputole16(x) x
#define cputole32(x) x
#elif __BYTE_ORDER == __BIG_ENDIAN
#define le16tocpu(x) swap16(x)
#define le32tocpu(x) swap32(x)
#define cputole16(x) swap16(x)
#define cputole32(x) swap32(x)
#endif
/****************************************************************************/
enum {BreakAfterBytes = 16};
enum {DefaultBufferSize = 1024};
void printRawData(const uint8_t *, unsigned int);
/****************************************************************************/

View File

@@ -9,96 +9,54 @@
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <list>
using namespace std;
#include "globals.h"
#include "CommandAlias.h"
#include "CommandConfig.h"
#include "CommandData.h"
#include "CommandDebug.h"
#include "CommandDomains.h"
#include "CommandMaster.h"
#include "CommandPdos.h"
#include "CommandSdos.h"
#include "CommandDownload.h"
#include "CommandUpload.h"
#include "CommandSlaves.h"
#include "CommandSiiRead.h"
#include "CommandSiiWrite.h"
#include "CommandStates.h"
#include "CommandXml.h"
/*****************************************************************************/
string binaryBaseName;
unsigned int masterIndex = 0;
int slavePosition = -1;
int domainIndex = -1;
string commandName;
vector<string> commandArgs;
Verbosity verbosity = Normal;
string dataTypeStr;
bool force = false;
bool helpRequested = false;
typedef list<Command *> CommandList;
CommandList commandList;
MasterDevice masterDev;
/*****************************************************************************/
string binaryBaseName;
string commandName;
Command::StringVector commandArgs;
struct Command {
const char *name;
void (*func)(void);
const char *helpString;
const char *briefDesc;
int execute(void) const;
string getHelpString(void) const;
};
/*****************************************************************************/
#define DEFINE_EXTERN_COMMAND(name) \
void command_##name(void); \
extern const char *help_##name
#define INIT_COMMAND(name, desc) \
{#name, command_##name, help_##name, desc}
DEFINE_EXTERN_COMMAND(alias);
DEFINE_EXTERN_COMMAND(config);
DEFINE_EXTERN_COMMAND(data);
DEFINE_EXTERN_COMMAND(debug);
DEFINE_EXTERN_COMMAND(domains);
DEFINE_EXTERN_COMMAND(master);
DEFINE_EXTERN_COMMAND(pdos);
DEFINE_EXTERN_COMMAND(sdos);
DEFINE_EXTERN_COMMAND(download);
DEFINE_EXTERN_COMMAND(upload);
DEFINE_EXTERN_COMMAND(slaves);
DEFINE_EXTERN_COMMAND(sii_read);
DEFINE_EXTERN_COMMAND(sii_write);
DEFINE_EXTERN_COMMAND(states);
DEFINE_EXTERN_COMMAND(xml);
static const Command commands[] = {
INIT_COMMAND(alias, "Write alias addresses."),
INIT_COMMAND(config, "Show bus configuration."),
INIT_COMMAND(data, "Output binary domain process data."),
INIT_COMMAND(debug, "Set the master's debug level."),
INIT_COMMAND(domains, "Show domain information."),
INIT_COMMAND(master, "Show master information."),
INIT_COMMAND(pdos, "List Pdo assignment/mapping."),
INIT_COMMAND(sdos, "List Sdo dictionaries."),
INIT_COMMAND(download, "Write an Sdo entry."),
INIT_COMMAND(upload, "Read an Sdo entry."),
INIT_COMMAND(slaves, "Show slaves."),
INIT_COMMAND(sii_read, "Output a slave's SII contents."),
INIT_COMMAND(sii_write, "Write slave's SII contents."),
INIT_COMMAND(states, "Request slave states."),
INIT_COMMAND(xml, "Generate slave information XML."),
};
static const Command *cmdEnd = commands + sizeof(commands) / sizeof(Command);
// option variables
unsigned int masterIndex = 0;
int slavePosition = -1;
int domainIndex = -1;
string dataTypeStr;
Command::Verbosity verbosity = Command::Normal;
bool force = false;
bool helpRequested = false;
/*****************************************************************************/
void printUsage()
{
const Command *cmd;
CommandList::const_iterator ci;
size_t maxWidth = 0;
for (cmd = commands; cmd < cmdEnd; cmd++) {
if (strlen(cmd->name) > maxWidth) {
maxWidth = strlen(cmd->name);
for (ci = commandList.begin(); ci != commandList.end(); ci++) {
if ((*ci)->getName().length() > maxWidth) {
maxWidth = (*ci)->getName().length();
}
}
@@ -108,9 +66,9 @@ void printUsage()
<< "Commands (can be abbreviated):" << endl;
cerr << left;
for (cmd = commands; cmd < cmdEnd; cmd++) {
cerr << " " << setw(maxWidth) << cmd->name
<< " " << cmd->briefDesc << endl;
for (ci = commandList.begin(); ci != commandList.end(); ci++) {
cerr << " " << setw(maxWidth) << (*ci)->getName()
<< " " << (*ci)->getBriefDescription() << endl;
}
cerr
@@ -207,11 +165,11 @@ void getOptions(int argc, char **argv)
break;
case 'q':
verbosity = Quiet;
verbosity = Command::Quiet;
break;
case 'v':
verbosity = Verbose;
verbosity = Command::Verbose;
break;
case 'h':
@@ -245,76 +203,23 @@ void getOptions(int argc, char **argv)
/****************************************************************************/
int Command::execute() const
list<Command *> getMatchingCommands(const string &cmdStr)
{
try {
func();
} catch (InvalidUsageException &e) {
cerr << e.what() << endl << endl;
cerr << getHelpString();
return 1;
} catch (CommandException &e) {
cerr << e.what() << endl;
return 1;
} catch (MasterDeviceException &e) {
cerr << e.what() << endl;
return 1;
}
return 0;
}
/****************************************************************************/
string Command::getHelpString() const
{
stringstream help;
help << binaryBaseName << " " << commandName << " " << helpString;
return help.str();
}
/****************************************************************************/
bool substrMatch(const string &abb, const string &full)
{
return full.substr(0, abb.length()) == abb;
}
/****************************************************************************/
bool abbrevMatch(const string &abb, const string &full)
{
unsigned int abbIndex;
size_t fullPos = 0;
for (abbIndex = 0; abbIndex < abb.length(); abbIndex++) {
fullPos = full.find(abb[abbIndex], fullPos);
if (fullPos == string::npos)
return false;
}
return true;
}
/****************************************************************************/
list<const Command *> getMatchingCommands(const string &cmdStr)
{
const Command *cmd;
list<const Command *> res;
CommandList::iterator ci;
list<Command *> res;
// find matching commands from beginning of the string
for (cmd = commands; cmd < cmdEnd; cmd++) {
if (substrMatch(cmdStr, cmd->name)) {
res.push_back(cmd);
for (ci = commandList.begin(); ci != commandList.end(); ci++) {
if ((*ci)->matchesSubstr(cmdStr)) {
res.push_back(*ci);
}
}
if (!res.size()) { // nothing found
// find /any/ matching commands
for (cmd = commands; cmd < cmdEnd; cmd++) {
if (abbrevMatch(cmdStr, cmd->name)) {
res.push_back(cmd);
for (ci = commandList.begin(); ci != commandList.end(); ci++) {
if ((*ci)->matchesAbbrev(cmdStr)) {
res.push_back(*ci);
}
}
}
@@ -327,29 +232,59 @@ list<const Command *> getMatchingCommands(const string &cmdStr)
int main(int argc, char **argv)
{
int retval = 0;
list<const Command *> commands;
list<const Command *>::const_iterator ci;
const Command *cmd;
list<Command *> matchingCommands;
list<Command *>::const_iterator ci;
Command *cmd;
binaryBaseName = basename(argv[0]);
commandList.push_back(new CommandAlias());
commandList.push_back(new CommandConfig());
commandList.push_back(new CommandData());
commandList.push_back(new CommandDebug());
commandList.push_back(new CommandDomains());
commandList.push_back(new CommandDownload());
commandList.push_back(new CommandMaster());
commandList.push_back(new CommandPdos());
commandList.push_back(new CommandSdos());
commandList.push_back(new CommandSiiRead());
commandList.push_back(new CommandSiiWrite());
commandList.push_back(new CommandSlaves());
commandList.push_back(new CommandStates());
commandList.push_back(new CommandUpload());
commandList.push_back(new CommandXml());
getOptions(argc, argv);
commands = getMatchingCommands(commandName);
matchingCommands = getMatchingCommands(commandName);
masterDev.setIndex(masterIndex);
if (commands.size()) {
if (commands.size() == 1) {
cmd = commands.front();
commandName = cmd->name;
if (matchingCommands.size()) {
if (matchingCommands.size() == 1) {
cmd = matchingCommands.front();
if (!helpRequested) {
masterDev.setIndex(masterIndex);
retval = cmd->execute();
try {
cmd->execute(masterDev, commandArgs);
} catch (InvalidUsageException &e) {
cerr << e.what() << endl << endl;
cerr << cmd->helpString();
retval = 1;
} catch (CommandException &e) {
cerr << e.what() << endl;
retval = 1;
} catch (MasterDeviceException &e) {
cerr << e.what() << endl;
retval = 1;
}
} else {
cout << cmd->getHelpString();
cout << cmd->helpString();
}
} else {
cerr << "Ambiguous command abbreviation! Matching:" << endl;
for (ci = commands.begin(); ci != commands.end(); ci++) {
cerr << (*ci)->name << endl;
for (ci = matchingCommands.begin();
ci != matchingCommands.end();
ci++) {
cerr << (*ci)->getName() << endl;
}
cerr << endl;
printUsage();
@@ -365,19 +300,3 @@ int main(int argc, char **argv)
}
/****************************************************************************/
void printRawData(
const uint8_t *data,
unsigned int size
)
{
cout << hex << setfill('0');
while (size--) {
cout << "0x" << setw(2) << (unsigned int) *data++;
if (size)
cout << " ";
}
cout << endl;
}
/****************************************************************************/