mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-06 03:41:52 +08:00
Redesigned command interface.
This commit is contained in:
81
tool/Command.cpp
Normal file
81
tool/Command.cpp
Normal 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
117
tool/Command.h
Normal 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
|
||||
@@ -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
29
tool/CommandAlias.h
Normal 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
|
||||
@@ -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
43
tool/CommandConfig.h
Normal 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
|
||||
@@ -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
29
tool/CommandData.h
Normal 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
70
tool/CommandDebug.cpp
Normal 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
26
tool/CommandDebug.h
Normal 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
|
||||
@@ -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
29
tool/CommandDomains.h
Normal 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
|
||||
@@ -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
29
tool/CommandDownload.h
Normal 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
|
||||
@@ -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
26
tool/CommandMaster.h
Normal 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
142
tool/CommandPdos.cpp
Normal 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
29
tool/CommandPdos.h
Normal 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
|
||||
@@ -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
29
tool/CommandSdos.h
Normal 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
|
||||
@@ -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
34
tool/CommandSiiRead.h
Normal 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
|
||||
@@ -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
26
tool/CommandSiiWrite.h
Normal 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
|
||||
@@ -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
41
tool/CommandSlaves.h
Normal 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
82
tool/CommandStates.cpp
Normal 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
28
tool/CommandStates.h
Normal 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
|
||||
@@ -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
31
tool/CommandUpload.h
Normal 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
|
||||
@@ -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
29
tool/CommandXml.h
Normal 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
|
||||
@@ -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
40
tool/byteorder.h
Normal 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
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -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);
|
||||
|
||||
/****************************************************************************/
|
||||
259
tool/main.cpp
259
tool/main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user