Skip to content
Snippets Groups Projects
Commit c4aebb4e authored by Florian Pose's avatar Florian Pose
Browse files

First step of moving to command list.

parent 25e7c75d
No related branches found
No related tags found
No related merge requests found
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
bin_PROGRAMS = ethercat bin_PROGRAMS = ethercat
ethercat_SOURCES = \ ethercat_SOURCES = \
Master.cpp Master.h \ MasterDevice.cpp MasterDevice.h \
cmd_alias.cpp \
cmd_config.cpp \
main.cpp main.cpp
ethercat_CXXFLAGS = -I../master -Wall ethercat_CXXFLAGS = -I../master -Wall
......
This diff is collapsed.
...@@ -18,72 +18,32 @@ using namespace std; ...@@ -18,72 +18,32 @@ using namespace std;
/****************************************************************************/ /****************************************************************************/
class MasterException: class MasterDeviceException:
public runtime_error public runtime_error
{ {
public: public:
/** Constructor with std::string parameter. */ /** Constructor with std::string parameter. */
MasterException( MasterDeviceException(
const string &s /**< Message. */ const string &s /**< Message. */
): runtime_error(s) {} ): runtime_error(s) {}
/** Constructor with const char pointer parameter. */
MasterException(
const char *s /**< Message. */
): runtime_error(s) {}
}; };
/****************************************************************************/ /****************************************************************************/
class Master class MasterDevice
{ {
public: public:
Master(); MasterDevice();
~Master(); ~MasterDevice();
void setIndex(unsigned int); void setIndex(unsigned int);
enum Verbosity {
Quiet,
Normal,
Verbose
};
void setVerbosity(Verbosity);
void writeAlias(int, bool, const vector<string> &);
void showConfigs();
void outputData(int);
void setDebug(const vector<string> &);
void showDomains(int);
void showMaster();
void listPdos(int);
void listSdos(int);
void sdoDownload(int, const string &, const vector<string> &);
void sdoUpload(int, const string &, const vector<string> &);
void showSlaves(int);
void siiRead(int);
void siiWrite(int, bool, const vector<string> &);
void requestStates(int, const vector<string> &);
void generateXml(int);
protected:
enum Permissions {Read, ReadWrite}; enum Permissions {Read, ReadWrite};
void open(Permissions); void open(Permissions);
void close(); void close();
void writeSlaveAlias(uint16_t, uint16_t);
typedef list<ec_ioctl_config_t> ConfigList;
void showDetailedConfigs(const ConfigList &);
void listConfigs(const ConfigList &);
void outputDomainData(unsigned int);
enum {BreakAfterBytes = 16};
void showDomain(unsigned int);
void listSlavePdos(uint16_t, bool = false);
void listSlaveSdos(uint16_t, bool = false);
void listSlaves(int);
void showSlave(uint16_t);
void generateSlaveXml(uint16_t);
unsigned int slaveCount(); unsigned int slaveCount();
void getMaster(ec_ioctl_master_t *); void getMaster(ec_ioctl_master_t *);
void getConfig(ec_ioctl_config_t *, unsigned int); void getConfig(ec_ioctl_config_t *, unsigned int);
void getConfigPdo(ec_ioctl_config_pdo_t *, unsigned int, uint8_t, void getConfigPdo(ec_ioctl_config_pdo_t *, unsigned int, uint8_t,
...@@ -102,17 +62,30 @@ class Master ...@@ -102,17 +62,30 @@ class Master
uint8_t, uint8_t); uint8_t, uint8_t);
void getSdo(ec_ioctl_slave_sdo_t *, uint16_t, uint16_t); void getSdo(ec_ioctl_slave_sdo_t *, uint16_t, uint16_t);
void getSdoEntry(ec_ioctl_slave_sdo_entry_t *, uint16_t, int, uint8_t); void getSdoEntry(ec_ioctl_slave_sdo_entry_t *, uint16_t, int, uint8_t);
void readSii(ec_ioctl_slave_sii_t *);
void writeSii(ec_ioctl_slave_sii_t *);
protected:
#if 0
void outputDomainData(unsigned int);
enum {BreakAfterBytes = 16};
void showDomain(unsigned int);
void listSlavePdos(uint16_t, bool = false);
void listSlaveSdos(uint16_t, bool = false);
void listSlaves(int);
void showSlave(uint16_t);
void generateSlaveXml(uint16_t);
void requestState(uint16_t, uint8_t); void requestState(uint16_t, uint8_t);
static string slaveState(uint8_t); static string slaveState(uint8_t);
static void printRawData(const uint8_t *, unsigned int); static void printRawData(const uint8_t *, unsigned int);
static uint8_t calcSiiCrc(const uint8_t *, unsigned int); static uint8_t calcSiiCrc(const uint8_t *, unsigned int);
#endif
private: private:
enum {DefaultBufferSize = 1024}; //enum {DefaultBufferSize = 1024};
unsigned int index; unsigned int index;
Verbosity verbosity;
int fd; int fd;
}; };
......
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
#include "globals.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 a 16 bit unsigned integer, specified\n"
" either in decimal (no prefix), octal (prefix '0')\n"
" or hexadecimal (prefix '0x').\n"
"\n"
"Command-specific options:\n"
" -s <SLAVE> Write the alias of the slave with the given\n"
" ring position. If this option is not\n"
" specified, the alias of all slaves is set.\n"
" The --force option is required in this\n"
" case.\n";
/*****************************************************************************/
void writeSlaveAlias(uint16_t, uint16_t);
/*****************************************************************************/
/** Writes the Secondary slave address (alias) to the slave's SII.
*/
void command_alias(void)
{
uint16_t alias;
stringstream err, strAlias;
int number;
unsigned int numSlaves, i;
if (commandArgs.size() != 1) {
err << "'" << command << "' takes exactly one argument!";
throw InvalidUsageException(err);
}
strAlias << commandArgs[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);
}
alias = number;
if (slavePosition == -1) {
if (!force) {
err << "This will write the alias addresses of all slaves to "
<< alias << "! Please specify --force to proceed.";
throw ExecutionFailureException(err);
}
masterDev.open(MasterDevice::ReadWrite);
numSlaves = masterDev.slaveCount();
for (i = 0; i < numSlaves; i++) {
writeSlaveAlias(i, alias);
}
} else {
masterDev.open(MasterDevice::ReadWrite);
writeSlaveAlias(slavePosition, alias);
}
}
/*****************************************************************************/
/** Calculates the SII checksum field.
*
* The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
* initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
*
* The below code was originally generated with PYCRC
* http://www.tty1.net/pycrc
*
* ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
* --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
*
* \return CRC8
*/
uint8_t calcSiiCrc(
const uint8_t *data, /**< pointer to data */
size_t length /**< number of bytes in \a data */
)
{
unsigned int i;
uint8_t bit, byte, crc = 0x48;
while (length--) {
byte = *data++;
for (i = 0; i < 8; i++) {
bit = crc & 0x80;
crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
if (bit) crc ^= 0x07;
}
}
for (i = 0; i < 8; i++) {
bit = crc & 0x80;
crc <<= 1;
if (bit) crc ^= 0x07;
}
return crc;
}
/*****************************************************************************/
/** Writes the Secondary slave address (alias) to the slave's SII.
*/
void writeSlaveAlias(
uint16_t slavePosition,
uint16_t alias
)
{
ec_ioctl_slave_sii_t data;
ec_ioctl_slave_t slave;
stringstream err;
uint8_t crc;
masterDev.getSlave(&slave, slavePosition);
if (slave.sii_nwords < 8) {
err << "Current SII contents are too small to set an alias "
<< "(" << slave.sii_nwords << " words)!";
throw ExecutionFailureException(err);
}
// read first 8 SII words
data.slave_position = slavePosition;
data.offset = 0;
data.nwords = 8;
data.words = new uint16_t[data.nwords];
try {
masterDev.readSii(&data);
} catch (MasterDeviceException &e) {
delete [] data.words;
err << "Failed to read SII: " << e.what();
throw ExecutionFailureException(err);
}
// write new alias address in word 4
data.words[4] = cputole16(alias);
// calculate checksum over words 0 to 6
crc = calcSiiCrc((const uint8_t *) data.words, 14);
// write new checksum into first byte of word 7
*(uint8_t *) (data.words + 7) = crc;
// write first 8 words with new alias and checksum
try {
masterDev.writeSii(&data);
} catch (MasterDeviceException &e) {
delete [] data.words;
err << "Failed to read SII: " << e.what();
throw ExecutionFailureException(err);
}
delete [] data.words;
}
/*****************************************************************************/
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <list>
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
#include "globals.h"
/*****************************************************************************/
const char *help_config =
"[OPTIONS]\n"
"\n"
"\n"
"Command-specific options:\n";
/*****************************************************************************/
struct ConfigInfo {
string alias;
string pos;
string ident;
string att;
string op;
};
typedef list<ec_ioctl_config_t> ConfigList;
void showDetailedConfigs(const ConfigList &configList);
void listConfigs(const ConfigList &configList);
/*****************************************************************************/
bool operator<(const ec_ioctl_config_t &a, const ec_ioctl_config_t &b)
{
return a.alias < b.alias
|| (a.alias == b.alias && a.position < b.position);
}
/*****************************************************************************/
/** Lists the bus configuration.
*/
void command_config(void)
{
ec_ioctl_master_t master;
unsigned int i;
ec_ioctl_config_t config;
ConfigList configList;
masterDev.open(MasterDevice::Read);
masterDev.getMaster(&master);
for (i = 0; i < master.config_count; i++) {
masterDev.getConfig(&config, i);
configList.push_back(config);
}
configList.sort();
if (verbosity == Verbose) {
showDetailedConfigs(configList);
} else {
listConfigs(configList);
}
}
/*****************************************************************************/
/** Lists the complete bus configuration.
*/
void showDetailedConfigs(const ConfigList &configList)
{
ConfigList::const_iterator configIter;
unsigned int j, k, l;
ec_ioctl_config_pdo_t pdo;
ec_ioctl_config_pdo_entry_t entry;
ec_ioctl_config_sdo_t sdo;
for (configIter = configList.begin();
configIter != configList.end();
configIter++) {
cout << "Alias: "
<< dec << configIter->alias << endl
<< "Position: " << configIter->position << endl
<< "Vendor Id: 0x"
<< hex << setfill('0')
<< setw(8) << configIter->vendor_id << endl
<< "Product code: 0x"
<< setw(8) << configIter->product_code << endl
<< "Attached: " << (configIter->attached ? "yes" : "no") << endl
<< "Operational: " << (configIter->operational ? "yes" : "no") << endl;
for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) {
if (configIter->syncs[j].pdo_count) {
cout << "SM" << dec << j << " ("
<< (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);
cout << " Pdo 0x" << hex
<< setw(4) << pdo.index
<< " \"" << pdo.name << "\"" << endl;
for (l = 0; l < pdo.entry_count; l++) {
masterDev.getConfigPdoEntry(&entry,
configIter->config_index, j, k, l);
cout << " Pdo entry 0x" << hex
<< setw(4) << entry.index << ":"
<< setw(2) << (unsigned int) entry.subindex
<< ", " << dec << (unsigned int) entry.bit_length
<< " bit, \"" << entry.name << "\"" << endl;
}
}
}
}
cout << "Sdo configuration:" << endl;
if (configIter->sdo_count) {
for (j = 0; j < configIter->sdo_count; j++) {
masterDev.getConfigSdo(&sdo, configIter->config_index, j);
cout << " 0x"
<< hex << setfill('0')
<< setw(4) << sdo.index << ":"
<< setw(2) << (unsigned int) sdo.subindex
<< ", " << dec << sdo.size << " byte: " << hex;
switch (sdo.size) {
case 1:
cout << "0x" << setw(2)
<< (unsigned int) *(uint8_t *) &sdo.data;
break;
case 2:
cout << "0x" << setw(4)
<< le16tocpu(*(uint16_t *) &sdo.data);
break;
case 4:
cout << "0x" << setw(8)
<< le32tocpu(*(uint32_t *) &sdo.data);
break;
default:
cout << "???";
}
cout << endl;
}
} else {
cout << " None." << endl;
}
cout << endl;
}
}
/*****************************************************************************/
/** Lists the bus configuration.
*/
void listConfigs(const ConfigList &configList)
{
ConfigList::const_iterator configIter;
stringstream str;
ConfigInfo info;
typedef list<ConfigInfo> ConfigInfoList;
ConfigInfoList list;
ConfigInfoList::const_iterator iter;
unsigned int maxAliasWidth = 0, maxPosWidth = 0,
maxAttWidth = 0, maxOpWidth = 0;
for (configIter = configList.begin();
configIter != configList.end();
configIter++) {
str << dec << configIter->alias;
info.alias = str.str();
str.clear();
str.str("");
str << configIter->position;
info.pos = str.str();
str.clear();
str.str("");
str << hex << setfill('0')
<< "0x" << setw(8) << configIter->vendor_id
<< "/0x" << setw(8) << configIter->product_code;
info.ident = str.str();
str.clear();
str.str("");
str << (configIter->attached ? "attached" : "-");
info.att = str.str();
str.clear();
str.str("");
str << (configIter->operational ? "operational" : "-");
info.op = str.str();
str.clear();
str.str("");
list.push_back(info);
if (info.alias.length() > maxAliasWidth)
maxAliasWidth = info.alias.length();
if (info.pos.length() > maxPosWidth)
maxPosWidth = info.pos.length();
if (info.att.length() > maxAttWidth)
maxAttWidth = info.att.length();
if (info.op.length() > maxOpWidth)
maxOpWidth = info.op.length();
}
for (iter = list.begin(); iter != list.end(); iter++) {
cout << setfill(' ') << right
<< setw(maxAliasWidth) << iter->alias
<< ":" << left
<< setw(maxPosWidth) << iter->pos
<< " "
<< iter->ident
<< " "
<< setw(maxAttWidth) << iter->att << " "
<< setw(maxOpWidth) << iter->op << " "
<< endl;
}
}
/*****************************************************************************/
/*****************************************************************************
*
* $Id$
*
****************************************************************************/
#include <sys/types.h>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#include "MasterDevice.h"
/*****************************************************************************/
enum Verbosity {
Quiet,
Normal,
Verbose
};
extern string command;
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 ExecutionFailureException:
public runtime_error
{
public:
/** Constructor with std::string parameter. */
ExecutionFailureException(
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
/****************************************************************************/
...@@ -12,29 +12,93 @@ ...@@ -12,29 +12,93 @@
#include <vector> #include <vector>
using namespace std; using namespace std;
#include "Master.h" #include "globals.h"
/*****************************************************************************/ /*****************************************************************************/
#define DEFAULT_MASTER 0 string binaryBaseName;
unsigned int masterIndex = 0;
static string cmdName; int slavePosition = -1;
static unsigned int masterIndex = DEFAULT_MASTER; int domainIndex = -1;
static int slavePosition = -1; string command;
static int domainIndex = -1;
static string command;
vector<string> commandArgs; vector<string> commandArgs;
static Master::Verbosity verbosity = Master::Normal; Verbosity verbosity = Normal;
string dataTypeStr; string dataTypeStr;
bool force = false; bool force = false;
bool helpRequested = false; bool helpRequested = false;
MasterDevice masterDev;
/*****************************************************************************/
struct Command {
void (*func)(void);
const char *helpString;
int execute(void) const;
void displayHelp(void) const;
};
struct CommandAlias {
const char *name;
const Command *command;
};
/*****************************************************************************/
#define COMMAND(name) \
void command_##name(void); \
extern const char *help_##name; \
const Command cmd_##name = {command_##name, help_##name};
COMMAND(alias);
COMMAND(config);
const CommandAlias commandAliases[] = {
{"alias", &cmd_alias},
{"config", &cmd_config},
{"conf", &cmd_config},
{"cf", &cmd_config},
};
#if 0
} else if (command == "data") {
master.outputData(domainIndex);
} else if (command == "debug") {
master.setDebug(commandArgs);
} else if (command == "domain") {
master.showDomains(domainIndex);
} else if (command == "master") {
master.showMaster();
} else if (command == "pdos") {
master.listPdos(slavePosition);
} else if (command == "sdos") {
master.listSdos(slavePosition);
} else if (command == "sdo_download" || command == "sd") {
master.sdoDownload(slavePosition, dataTypeStr, commandArgs);
} else if (command == "sdo_upload" || command == "su") {
master.sdoUpload(slavePosition, dataTypeStr, commandArgs);
} else if (command == "slave" || command == "slaves"
|| command == "list" || command == "ls") {
master.showSlaves(slavePosition);
} else if (command == "sii_read" || command == "sr") {
master.siiRead(slavePosition);
} else if (command == "sii_write" || command == "sw") {
master.siiWrite(slavePosition, force, commandArgs);
} else if (command == "state") {
master.requestStates(slavePosition, commandArgs);
} else if (command == "xml") {
master.generateXml(slavePosition);
#endif
/*****************************************************************************/ /*****************************************************************************/
void printUsage() void printUsage()
{ {
cerr cerr
<< "Usage: " << cmdName << " <COMMAND> [OPTIONS]" << endl << "Usage: " << binaryBaseName << " <COMMAND> [OPTIONS]" << endl
<< "Commands:" << endl << "Commands:" << endl
<< " alias Write alias addresses." << endl << " alias Write alias addresses." << endl
<< " config Show bus configuration." << endl << " config Show bus configuration." << endl
...@@ -52,8 +116,8 @@ void printUsage() ...@@ -52,8 +116,8 @@ void printUsage()
<< " state Request slave states." << endl << " state Request slave states." << endl
<< " xml Generate slave information xmls." << endl << " xml Generate slave information xmls." << endl
<< "Global options:" << endl << "Global options:" << endl
<< " --master -m <master> Index of the master to use. Default: " << " --master -m <master> Index of the master to use. Default: 0"
<< DEFAULT_MASTER << endl << endl
<< " --slave -s <index> Positive numerical ring position," << " --slave -s <index> Positive numerical ring position,"
<< endl << endl
<< " or 'all' for all slaves (default)." << " or 'all' for all slaves (default)."
...@@ -67,8 +131,8 @@ void printUsage() ...@@ -67,8 +131,8 @@ void printUsage()
<< " --quiet -q Output less information." << endl << " --quiet -q Output less information." << endl
<< " --verbose -v Output more information." << endl << " --verbose -v Output more information." << endl
<< " --help -h Show this help." << endl << " --help -h Show this help." << endl
<< "Call '" << cmdName << " <COMMAND> --help' for command-specific " << "Call '" << binaryBaseName
<< "help." << endl << " <COMMAND> --help' for command-specific help." << endl
<< "Send bug reports to " << PACKAGE_BUGREPORT << "." << endl; << "Send bug reports to " << PACKAGE_BUGREPORT << "." << endl;
} }
...@@ -146,11 +210,11 @@ void getOptions(int argc, char **argv) ...@@ -146,11 +210,11 @@ void getOptions(int argc, char **argv)
break; break;
case 'q': case 'q':
verbosity = Master::Quiet; verbosity = Quiet;
break; break;
case 'v': case 'v':
verbosity = Master::Verbose; verbosity = Verbose;
break; break;
case 'h': case 'h':
...@@ -184,60 +248,64 @@ void getOptions(int argc, char **argv) ...@@ -184,60 +248,64 @@ void getOptions(int argc, char **argv)
/****************************************************************************/ /****************************************************************************/
int Command::execute() const
{
try {
func();
} catch (InvalidUsageException &e) {
cerr << e.what() << endl << endl;
displayHelp();
return 1;
} catch (ExecutionFailureException &e) {
cerr << e.what() << endl;
return 1;
} catch (MasterDeviceException &e) {
cerr << e.what() << endl;
return 1;
}
return 0;
}
/****************************************************************************/
void Command::displayHelp() const
{
cerr << binaryBaseName << " " << command << " " << helpString;
}
/****************************************************************************/
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
Master master; int retval = 0;
const CommandAlias *alias;
const CommandAlias *endAlias =
commandAliases + sizeof(commandAliases) / sizeof(CommandAlias);
cmdName = basename(argv[0]); binaryBaseName = basename(argv[0]);
getOptions(argc, argv); getOptions(argc, argv);
master.setIndex(masterIndex); // search command alias in alias map
master.setVerbosity(verbosity); for (alias = commandAliases; alias < endAlias; alias++) {
if (command == alias->name)
break;
}
try { if (alias < endAlias) { // command alias found
if (command == "alias") { if (!helpRequested) {
master.writeAlias(slavePosition, force, commandArgs); masterDev.setIndex(masterIndex);
} else if (command == "config") { retval = alias->command->execute();
master.showConfigs();
} else if (command == "data") {
master.outputData(domainIndex);
} else if (command == "debug") {
master.setDebug(commandArgs);
} else if (command == "domain") {
master.showDomains(domainIndex);
} else if (command == "master") {
master.showMaster();
} else if (command == "pdos") {
master.listPdos(slavePosition);
} else if (command == "sdos") {
master.listSdos(slavePosition);
} else if (command == "sdo_download" || command == "sd") {
master.sdoDownload(slavePosition, dataTypeStr, commandArgs);
} else if (command == "sdo_upload" || command == "su") {
master.sdoUpload(slavePosition, dataTypeStr, commandArgs);
} else if (command == "slave" || command == "slaves"
|| command == "list" || command == "ls") {
master.showSlaves(slavePosition);
} else if (command == "sii_read" || command == "sr") {
master.siiRead(slavePosition);
} else if (command == "sii_write" || command == "sw") {
master.siiWrite(slavePosition, force, commandArgs);
} else if (command == "state") {
master.requestStates(slavePosition, commandArgs);
} else if (command == "xml") {
master.generateXml(slavePosition);
} else { } else {
cerr << "Unknown command " << command << "!" << endl; alias->command->displayHelp();
printUsage();
exit(1);
} }
} catch (MasterException &e) { } else { // command not found
cerr << e.what() << endl; cerr << "Unknown command " << command << "!" << endl << endl;
exit(1); printUsage();
retval = 1;
} }
return 0; return retval;
} }
/****************************************************************************/ /****************************************************************************/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment