diff --git a/NEWS b/NEWS index e3380734..d9cda749 100644 --- a/NEWS +++ b/NEWS @@ -65,6 +65,8 @@ Changes since 1.4.0: * Significantly improved EoE bandwidth by running EoE processing in a kthread. * Switched version control from Subversion to Mercurial. * Implemented CompleteAccess for SDO downloads. +* ethercat tool is now able to handle multiple masters. The --masters option + supports ranges like '0,3,8-10'. Changes in 1.4.0: diff --git a/TODO b/TODO index 4b204182..82acde4a 100644 --- a/TODO +++ b/TODO @@ -38,7 +38,6 @@ Future issues: * Remove default buffer size in SDO upload. * Improve application-triggered SDO transfers by moving the state machine into the SDO handlers. -* Check for ioctl() interface version. * Remove allow_scanning flag. * Override sync manager size? * Show Record / Array / List type of SDOs. @@ -71,6 +70,7 @@ Future issues: - Data type abbreviations. - Add a -n (numeric) switch. - Check for unwanted options. + - Implement ranges for slaves, domains, etc. * Simplify master fsm by introducing a common request state to handle external requests (replace write_sii, sdo_request, etc). diff --git a/lib/common.c b/lib/common.c index a64788b2..f9f6a771 100644 --- a/lib/common.c +++ b/lib/common.c @@ -71,7 +71,8 @@ ec_master_t *ecrt_request_master(unsigned int master_index) ec_master_t *ecrt_open_master(unsigned int master_index) { char path[MAX_PATH_LEN]; - ec_master_t *master; + ec_master_t *master = NULL; + ec_ioctl_module_t module_data; master = malloc(sizeof(ec_master_t)); if (!master) { @@ -87,11 +88,30 @@ ec_master_t *ecrt_open_master(unsigned int master_index) master->fd = open(path, O_RDWR); if (master->fd == -1) { fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); - free(master); - return 0; + goto out_free; + } + + if (ioctl(master->fd, EC_IOCTL_MODULE, &module_data) < 0) { + fprintf(stderr, "Failed to get module information from %s: %s\n", + path, strerror(errno)); + goto out_close; + } + + if (module_data.ioctl_version_magic != EC_IOCTL_VERSION_MAGIC) { + fprintf(stderr, "ioctl() version magic is differing:" + " %s: %u, libethercat: %u.\n", + path, module_data.ioctl_version_magic, + EC_IOCTL_VERSION_MAGIC); + goto out_close; } return master; + +out_close: + close(master->fd); +out_free: + free(master); + return 0; } /*****************************************************************************/ diff --git a/master/cdev.c b/master/cdev.c index 76e192ce..5748c698 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -157,6 +157,25 @@ void ec_cdev_strcpy( /*****************************************************************************/ +/** Get module information. + */ +int ec_cdev_ioctl_module( + unsigned long arg /**< Userspace address to store the results. */ + ) +{ + ec_ioctl_module_t data; + + data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC; + data.master_count = ec_master_count(); + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + +/*****************************************************************************/ + /** Get master information. */ int ec_cdev_ioctl_master( @@ -3281,6 +3300,8 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) #endif switch (cmd) { + case EC_IOCTL_MODULE: + return ec_cdev_ioctl_module(arg); case EC_IOCTL_MASTER: return ec_cdev_ioctl_master(master, arg); case EC_IOCTL_SLAVE: diff --git a/master/globals.h b/master/globals.h index aee3e6a7..fdb34f67 100644 --- a/master/globals.h +++ b/master/globals.h @@ -263,6 +263,7 @@ extern char *ec_master_version_str; /*****************************************************************************/ +unsigned int ec_master_count(void); void ec_print_data(const uint8_t *, size_t); void ec_print_data_diff(const uint8_t *, const uint8_t *, size_t); size_t ec_state_string(uint8_t, char *, uint8_t); diff --git a/master/ioctl.h b/master/ioctl.h index 5fb21f99..5704eb96 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -52,78 +52,85 @@ #define EC_IOW(nr, type) _IOW(EC_IOCTL_TYPE, nr, type) #define EC_IOWR(nr, type) _IOWR(EC_IOCTL_TYPE, nr, type) +/** EtherCAT master ioctl() version magic. + * + * Increment this when changing the ioctl interface! + */ +#define EC_IOCTL_VERSION_MAGIC 1 + // Command-line tool -#define EC_IOCTL_MASTER EC_IOR(0x00, ec_ioctl_master_t) -#define EC_IOCTL_SLAVE EC_IOWR(0x01, ec_ioctl_slave_t) -#define EC_IOCTL_SLAVE_SYNC EC_IOWR(0x02, ec_ioctl_slave_sync_t) -#define EC_IOCTL_SLAVE_SYNC_PDO EC_IOWR(0x03, ec_ioctl_slave_sync_pdo_t) -#define EC_IOCTL_SLAVE_SYNC_PDO_ENTRY EC_IOWR(0x04, ec_ioctl_slave_sync_pdo_entry_t) -#define EC_IOCTL_DOMAIN EC_IOWR(0x05, ec_ioctl_domain_t) -#define EC_IOCTL_DOMAIN_FMMU EC_IOWR(0x06, ec_ioctl_domain_fmmu_t) -#define EC_IOCTL_DOMAIN_DATA EC_IOWR(0x07, ec_ioctl_domain_data_t) -#define EC_IOCTL_MASTER_DEBUG EC_IO(0x08) -#define EC_IOCTL_SLAVE_STATE EC_IOW(0x09, ec_ioctl_slave_state_t) -#define EC_IOCTL_SLAVE_SDO EC_IOWR(0x0a, ec_ioctl_slave_sdo_t) -#define EC_IOCTL_SLAVE_SDO_ENTRY EC_IOWR(0x0b, ec_ioctl_slave_sdo_entry_t) -#define EC_IOCTL_SLAVE_SDO_UPLOAD EC_IOWR(0x0c, ec_ioctl_slave_sdo_upload_t) -#define EC_IOCTL_SLAVE_SDO_DOWNLOAD EC_IOWR(0x0d, ec_ioctl_slave_sdo_download_t) -#define EC_IOCTL_SLAVE_SII_READ EC_IOWR(0x0e, ec_ioctl_slave_sii_t) -#define EC_IOCTL_SLAVE_SII_WRITE EC_IOW(0x0f, ec_ioctl_slave_sii_t) -#define EC_IOCTL_SLAVE_REG_READ EC_IOWR(0x10, ec_ioctl_slave_reg_t) -#define EC_IOCTL_SLAVE_REG_WRITE EC_IOW(0x11, ec_ioctl_slave_reg_t) -#define EC_IOCTL_SLAVE_FOE_READ EC_IOWR(0x12, ec_ioctl_slave_foe_t) -#define EC_IOCTL_SLAVE_FOE_WRITE EC_IOW(0x13, ec_ioctl_slave_foe_t) -#define EC_IOCTL_CONFIG EC_IOWR(0x14, ec_ioctl_config_t) -#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x15, ec_ioctl_config_pdo_t) -#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x16, ec_ioctl_config_pdo_entry_t) -#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x17, ec_ioctl_config_sdo_t) +#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) +#define EC_IOCTL_MASTER EC_IOR(0x01, ec_ioctl_master_t) +#define EC_IOCTL_SLAVE EC_IOWR(0x02, ec_ioctl_slave_t) +#define EC_IOCTL_SLAVE_SYNC EC_IOWR(0x03, ec_ioctl_slave_sync_t) +#define EC_IOCTL_SLAVE_SYNC_PDO EC_IOWR(0x04, ec_ioctl_slave_sync_pdo_t) +#define EC_IOCTL_SLAVE_SYNC_PDO_ENTRY EC_IOWR(0x05, ec_ioctl_slave_sync_pdo_entry_t) +#define EC_IOCTL_DOMAIN EC_IOWR(0x06, ec_ioctl_domain_t) +#define EC_IOCTL_DOMAIN_FMMU EC_IOWR(0x07, ec_ioctl_domain_fmmu_t) +#define EC_IOCTL_DOMAIN_DATA EC_IOWR(0x08, ec_ioctl_domain_data_t) +#define EC_IOCTL_MASTER_DEBUG EC_IO(0x09) +#define EC_IOCTL_SLAVE_STATE EC_IOW(0x0a, ec_ioctl_slave_state_t) +#define EC_IOCTL_SLAVE_SDO EC_IOWR(0x0b, ec_ioctl_slave_sdo_t) +#define EC_IOCTL_SLAVE_SDO_ENTRY EC_IOWR(0x0c, ec_ioctl_slave_sdo_entry_t) +#define EC_IOCTL_SLAVE_SDO_UPLOAD EC_IOWR(0x0d, ec_ioctl_slave_sdo_upload_t) +#define EC_IOCTL_SLAVE_SDO_DOWNLOAD EC_IOWR(0x0e, ec_ioctl_slave_sdo_download_t) +#define EC_IOCTL_SLAVE_SII_READ EC_IOWR(0x0f, ec_ioctl_slave_sii_t) +#define EC_IOCTL_SLAVE_SII_WRITE EC_IOW(0x10, ec_ioctl_slave_sii_t) +#define EC_IOCTL_SLAVE_REG_READ EC_IOWR(0x11, ec_ioctl_slave_reg_t) +#define EC_IOCTL_SLAVE_REG_WRITE EC_IOW(0x12, ec_ioctl_slave_reg_t) +#define EC_IOCTL_SLAVE_FOE_READ EC_IOWR(0x13, ec_ioctl_slave_foe_t) +#define EC_IOCTL_SLAVE_FOE_WRITE EC_IOW(0x14, ec_ioctl_slave_foe_t) +#define EC_IOCTL_CONFIG EC_IOWR(0x15, ec_ioctl_config_t) +#define EC_IOCTL_CONFIG_PDO EC_IOWR(0x16, ec_ioctl_config_pdo_t) +#define EC_IOCTL_CONFIG_PDO_ENTRY EC_IOWR(0x17, ec_ioctl_config_pdo_entry_t) +#define EC_IOCTL_CONFIG_SDO EC_IOWR(0x18, ec_ioctl_config_sdo_t) #ifdef EC_EOE -#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x18, ec_ioctl_eoe_handler_t) +#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x19, ec_ioctl_eoe_handler_t) #endif // Application interface -#define EC_IOCTL_REQUEST EC_IO(0x19) -#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1a) -#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x1b, ec_ioctl_config_t) -#define EC_IOCTL_ACTIVATE EC_IOR(0x1c, size_t) -#define EC_IOCTL_DEACTIVATE EC_IO(0x1d) -#define EC_IOCTL_SEND EC_IO(0x1e) -#define EC_IOCTL_RECEIVE EC_IO(0x1f) -#define EC_IOCTL_MASTER_STATE EC_IOR(0x20, ec_master_state_t) -#define EC_IOCTL_APP_TIME EC_IOW(0x21, ec_ioctl_app_time_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x22) -#define EC_IOCTL_SYNC_SLAVES EC_IO(0x23) -#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x24) -#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x25, uint32_t) -#define EC_IOCTL_SC_SYNC EC_IOW(0x26, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x27, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x28, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x29, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x2a, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x2b, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x2c, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_DC EC_IOW(0x2d, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x2e, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x2f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x20, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x31, ec_ioctl_sc_state_t) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x32) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x33) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x34) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x35, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x36, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x37, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x38, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x39, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x3a, ec_ioctl_sdo_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x3b, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x3c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x3d, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3e, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x3f, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x40, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x41, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x42, size_t) +#define EC_IOCTL_REQUEST EC_IO(0x1a) +#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x1b) +#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x1c, ec_ioctl_config_t) +#define EC_IOCTL_ACTIVATE EC_IOR(0x1d, size_t) +#define EC_IOCTL_DEACTIVATE EC_IO(0x1e) +#define EC_IOCTL_SEND EC_IO(0x1f) +#define EC_IOCTL_RECEIVE EC_IO(0x20) +#define EC_IOCTL_MASTER_STATE EC_IOR(0x21, ec_master_state_t) +#define EC_IOCTL_APP_TIME EC_IOW(0x22, ec_ioctl_app_time_t) +#define EC_IOCTL_SYNC_REF EC_IO(0x23) +#define EC_IOCTL_SYNC_SLAVES EC_IO(0x24) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x25) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x26, uint32_t) +#define EC_IOCTL_SC_SYNC EC_IOW(0x27, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x28, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x29, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x2a, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x2b, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x2c, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x2d, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_DC EC_IOW(0x2e, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x2f, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x20, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x31, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x32, ec_ioctl_sc_state_t) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x33) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x34) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x35) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x36, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x37, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x38, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x39, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x3a, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x3b, ec_ioctl_sdo_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x3c, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x3d, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x3e, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x3f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x40, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x41, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x42, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x43, size_t) /*****************************************************************************/ @@ -131,6 +138,13 @@ /*****************************************************************************/ +typedef struct { + uint32_t ioctl_version_magic; + uint32_t master_count; +} ec_ioctl_module_t; + +/*****************************************************************************/ + typedef struct { uint32_t slave_count; uint32_t config_count; diff --git a/master/module.c b/master/module.c index 90e777a1..bc38a1fa 100644 --- a/master/module.c +++ b/master/module.c @@ -195,6 +195,15 @@ void __exit ec_cleanup_module(void) EC_INFO("Master module cleaned up.\n"); } +/*****************************************************************************/ + +/** Get the number of masters. + */ +unsigned int ec_master_count(void) +{ + return master_count; +} + /***************************************************************************** * MAC address functions ****************************************************************************/ diff --git a/tool/Command.cpp b/tool/Command.cpp index fdf43fd3..c51ad312 100644 --- a/tool/Command.cpp +++ b/tool/Command.cpp @@ -28,6 +28,7 @@ ****************************************************************************/ #include "Command.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -46,6 +47,13 @@ Command::~Command() /*****************************************************************************/ +void Command::setMasterIndices(const MasterIndexList &indices) +{ + masterIndices = indices; +}; + +/*****************************************************************************/ + void Command::setVerbosity(Verbosity v) { verbosity = v; diff --git a/tool/Command.h b/tool/Command.h index 66731d94..275cb8e3 100644 --- a/tool/Command.h +++ b/tool/Command.h @@ -33,9 +33,12 @@ #include #include #include +#include using namespace std; -#include "MasterDevice.h" +#include "../master/ioctl.h" + +class MasterDevice; /****************************************************************************/ @@ -76,6 +79,9 @@ class Command const string &getName() const; const string &getBriefDescription() const; + typedef list MasterIndexList; + void setMasterIndices(const MasterIndexList &); + const MasterIndexList &getMasterIndices() const; enum Verbosity { Quiet, Normal, @@ -102,7 +108,7 @@ class Command virtual string helpString() const = 0; typedef vector StringVector; - virtual void execute(MasterDevice &, const StringVector &) = 0; + virtual void execute(const StringVector &) = 0; static string numericInfo(); @@ -125,6 +131,7 @@ class Command private: string name; string briefDesc; + MasterIndexList masterIndices; Verbosity verbosity; int alias; int position; @@ -152,6 +159,13 @@ inline const string &Command::getBriefDescription() const /****************************************************************************/ +inline const Command::MasterIndexList &Command::getMasterIndices() const +{ + return masterIndices; +} + +/****************************************************************************/ + inline Command::Verbosity Command::getVerbosity() const { return verbosity; diff --git a/tool/CommandAlias.cpp b/tool/CommandAlias.cpp index 287bc847..cd7fd8bd 100644 --- a/tool/CommandAlias.cpp +++ b/tool/CommandAlias.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandAlias.h" #include "sii_crc.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -75,7 +76,7 @@ string CommandAlias::helpString() const /** Writes the Secondary slave address (alias) to the slave's SII. */ -void CommandAlias::execute(MasterDevice &m, const StringVector &args) +void CommandAlias::execute(const StringVector &args) { uint16_t alias; stringstream err, strAlias; @@ -98,6 +99,11 @@ void CommandAlias::execute(MasterDevice &m, const StringVector &args) } alias = number; + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::ReadWrite); slaves = selectedSlaves(m); diff --git a/tool/CommandAlias.h b/tool/CommandAlias.h index 7fa73081..755d344e 100644 --- a/tool/CommandAlias.h +++ b/tool/CommandAlias.h @@ -41,7 +41,7 @@ class CommandAlias: CommandAlias(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void writeSlaveAlias(MasterDevice &, const ec_ioctl_slave_t &, diff --git a/tool/CommandCStruct.cpp b/tool/CommandCStruct.cpp index 7ffc5191..d3d8fc75 100644 --- a/tool/CommandCStruct.cpp +++ b/tool/CommandCStruct.cpp @@ -33,6 +33,7 @@ using namespace std; #include "CommandCStruct.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -67,7 +68,7 @@ string CommandCStruct::helpString() const /****************************************************************************/ -void CommandCStruct::execute(MasterDevice &m, const StringVector &args) +void CommandCStruct::execute(const StringVector &args) { SlaveList slaves; SlaveList::const_iterator si; @@ -78,11 +79,16 @@ void CommandCStruct::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - slaves = selectedSlaves(m); + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); - for (si = slaves.begin(); si != slaves.end(); si++) { - generateSlaveCStruct(m, *si); + for (si = slaves.begin(); si != slaves.end(); si++) { + generateSlaveCStruct(m, *si); + } } } diff --git a/tool/CommandCStruct.h b/tool/CommandCStruct.h index 481c2c17..82ab3129 100644 --- a/tool/CommandCStruct.h +++ b/tool/CommandCStruct.h @@ -41,7 +41,7 @@ class CommandCStruct: CommandCStruct(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void generateSlaveCStruct(MasterDevice &, const ec_ioctl_slave_t &); diff --git a/tool/CommandConfig.cpp b/tool/CommandConfig.cpp index 81b0f25c..32e371b9 100644 --- a/tool/CommandConfig.cpp +++ b/tool/CommandConfig.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandConfig.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -101,9 +102,10 @@ string CommandConfig::helpString() const /** Lists the bus configuration. */ -void CommandConfig::execute(MasterDevice &m, const StringVector &args) +void CommandConfig::execute(const StringVector &args) { ConfigList configs; + bool doIndent; if (args.size()) { stringstream err; @@ -111,13 +113,23 @@ void CommandConfig::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - configs = selectedConfigs(m); + doIndent = getMasterIndices().size() > 1; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + configs = selectedConfigs(m); - if (getVerbosity() == Verbose) { - showDetailedConfigs(m, configs); - } else { - listConfigs(m, configs); + if (doIndent) { + cout << "Master" << dec << *mi << endl; + } + + if (getVerbosity() == Verbose) { + showDetailedConfigs(m, configs, doIndent); + } else { + listConfigs(m, configs, doIndent); + } } } @@ -127,7 +139,8 @@ void CommandConfig::execute(MasterDevice &m, const StringVector &args) */ void CommandConfig::showDetailedConfigs( MasterDevice &m, - const ConfigList &configList + const ConfigList &configList, + bool doIndent ) { ConfigList::const_iterator configIter; @@ -136,19 +149,21 @@ void CommandConfig::showDetailedConfigs( ec_ioctl_config_pdo_t pdo; ec_ioctl_config_pdo_entry_t entry; ec_ioctl_config_sdo_t sdo; + string indent(doIndent ? " " : ""); for (configIter = configList.begin(); configIter != configList.end(); configIter++) { - cout << "Alias: " - << dec << configIter->alias << endl - << "Position: " << configIter->position << endl + cout << indent + << "Alias: " + << dec << configIter->alias << endl << indent + << "Position: " << configIter->position << endl << indent << "Vendor Id: 0x" << hex << setfill('0') - << setw(8) << configIter->vendor_id << endl + << setw(8) << configIter->vendor_id << endl << indent << "Product code: 0x" - << setw(8) << configIter->product_code << endl + << setw(8) << configIter->product_code << endl << indent << "Attached slave: "; if (configIter->slave_position != -1) { @@ -159,13 +174,13 @@ void CommandConfig::showDetailedConfigs( cout << "none" << endl; } - cout << "Watchdog divider: "; + cout << indent << "Watchdog divider: "; if (configIter->watchdog_divider) { cout << dec << configIter->watchdog_divider; } else { cout << "(Default)"; } - cout << endl + cout << endl << indent << "Watchdog intervals: "; if (configIter->watchdog_intervals) { cout << dec << configIter->watchdog_intervals; @@ -176,7 +191,7 @@ void CommandConfig::showDetailedConfigs( for (j = 0; j < EC_MAX_SYNC_MANAGERS; j++) { if (configIter->syncs[j].pdo_count) { - cout << "SM" << dec << j << ", Dir: " + cout << indent << "SM" << dec << j << ", Dir: " << (configIter->syncs[j].dir == EC_DIR_INPUT ? "Input" : "Output") << ", Watchdog: "; switch (configIter->syncs[j].watchdog_mode) { @@ -190,14 +205,15 @@ void CommandConfig::showDetailedConfigs( for (k = 0; k < configIter->syncs[j].pdo_count; k++) { m.getConfigPdo(&pdo, configIter->config_index, j, k); - cout << " PDO 0x" << hex << setfill('0') + cout << indent << " PDO 0x" << hex << setfill('0') << setw(4) << pdo.index << endl; for (l = 0; l < pdo.entry_count; l++) { m.getConfigPdoEntry(&entry, configIter->config_index, j, k, l); - cout << " PDO entry 0x" << hex << setfill('0') + cout << indent << " PDO entry 0x" + << hex << setfill('0') << setw(4) << entry.index << ":" << setw(2) << (unsigned int) entry.subindex << ", " << dec << setfill(' ') @@ -208,23 +224,23 @@ void CommandConfig::showDetailedConfigs( } } - cout << "SDO configuration:" << endl; + cout << indent << "SDO configuration:" << endl; if (configIter->sdo_count) { for (j = 0; j < configIter->sdo_count; j++) { m.getConfigSdo(&sdo, configIter->config_index, j); - cout << " 0x" + cout << indent << " 0x" << hex << setfill('0') << setw(4) << sdo.index << ":" << setw(2) << (unsigned int) sdo.subindex << ", " << dec << sdo.size << " byte" << endl; - cout << " " << hex; + cout << indent << " " << hex; for (i = 0; i < min((uint32_t) sdo.size, (uint32_t) EC_MAX_SDO_DATA_SIZE); i++) { cout << setw(2) << (unsigned int) sdo.data[i]; if ((i + 1) % 16 == 0 && i < sdo.size - 1) { - cout << endl << " "; + cout << endl << indent << " "; } else { cout << " "; } @@ -232,23 +248,23 @@ void CommandConfig::showDetailedConfigs( cout << endl; if (sdo.size > EC_MAX_SDO_DATA_SIZE) { - cout << " ..." << endl; + cout << indent << " ..." << endl; } } } else { - cout << " None." << endl; + cout << indent << " None." << endl; } if (configIter->dc_assign_activate) { int i; - cout << "DC configuration:" << endl - << " AssignActivate: 0x" << hex << setfill('0') + cout << indent << "DC configuration:" << endl + << indent << " AssignActivate: 0x" << hex << setfill('0') << setw(4) << configIter->dc_assign_activate << endl; - cout << " Cycle [ns] Shift [ns]" << endl; + cout << indent << " Cycle [ns] Shift [ns]" << endl; for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) { - cout << " SYNC" << dec << i << " " + cout << indent << " SYNC" << dec << i << " " << setfill(' ') << right << setw(11) << configIter->dc_sync[i].cycle_time << " " @@ -266,7 +282,8 @@ void CommandConfig::showDetailedConfigs( */ void CommandConfig::listConfigs( MasterDevice &m, - const ConfigList &configList + const ConfigList &configList, + bool doIndent ) { ConfigList::const_iterator configIter; @@ -278,6 +295,7 @@ void CommandConfig::listConfigs( unsigned int maxAliasWidth = 0, maxPosWidth = 0, maxSlavePosWidth = 0, maxStateWidth = 0; ec_ioctl_slave_t slave; + string indent(doIndent ? " " : ""); for (configIter = configList.begin(); configIter != configList.end(); @@ -337,7 +355,7 @@ void CommandConfig::listConfigs( } for (iter = list.begin(); iter != list.end(); iter++) { - cout << setfill(' ') << right + cout << indent << setfill(' ') << right << setw(maxAliasWidth) << iter->alias << ":" << left << setw(maxPosWidth) << iter->pos diff --git a/tool/CommandConfig.h b/tool/CommandConfig.h index c520fbb2..63214dfd 100644 --- a/tool/CommandConfig.h +++ b/tool/CommandConfig.h @@ -44,7 +44,7 @@ class CommandConfig: CommandConfig(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: struct Info { @@ -55,8 +55,8 @@ class CommandConfig: string state; }; - void showDetailedConfigs(MasterDevice &, const ConfigList &); - void listConfigs(MasterDevice &m, const ConfigList &); + void showDetailedConfigs(MasterDevice &, const ConfigList &, bool); + void listConfigs(MasterDevice &m, const ConfigList &, bool); }; /****************************************************************************/ diff --git a/tool/CommandData.cpp b/tool/CommandData.cpp index 88815b71..d2a2fe6e 100644 --- a/tool/CommandData.cpp +++ b/tool/CommandData.cpp @@ -31,6 +31,7 @@ using namespace std; #include "CommandData.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -63,7 +64,7 @@ string CommandData::helpString() const /****************************************************************************/ -void CommandData::execute(MasterDevice &m, const StringVector &args) +void CommandData::execute(const StringVector &args) { DomainList domains; DomainList::const_iterator di; @@ -74,6 +75,12 @@ void CommandData::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + stringstream err; + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); domains = selectedDomains(m); diff --git a/tool/CommandData.h b/tool/CommandData.h index 50eb06d5..b48631b2 100644 --- a/tool/CommandData.h +++ b/tool/CommandData.h @@ -41,7 +41,7 @@ class CommandData: CommandData(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void outputDomainData(MasterDevice &, const ec_ioctl_domain_t &); diff --git a/tool/CommandDebug.cpp b/tool/CommandDebug.cpp index 533c5e58..ea0582cf 100644 --- a/tool/CommandDebug.cpp +++ b/tool/CommandDebug.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandDebug.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -65,7 +66,7 @@ string CommandDebug::helpString() const /****************************************************************************/ -void CommandDebug::execute(MasterDevice &m, const StringVector &args) +void CommandDebug::execute(const StringVector &args) { stringstream str; int debugLevel; @@ -86,8 +87,13 @@ void CommandDebug::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::ReadWrite); - m.setDebug(debugLevel); + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::ReadWrite); + m.setDebug(debugLevel); + } } /*****************************************************************************/ diff --git a/tool/CommandDebug.h b/tool/CommandDebug.h index 7fbe0ffe..a9e28438 100644 --- a/tool/CommandDebug.h +++ b/tool/CommandDebug.h @@ -41,7 +41,7 @@ class CommandDebug: CommandDebug(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandDomains.cpp b/tool/CommandDomains.cpp index bc7ea6b7..959305c0 100644 --- a/tool/CommandDomains.cpp +++ b/tool/CommandDomains.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandDomains.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -89,10 +90,11 @@ string CommandDomains::helpString() const /****************************************************************************/ -void CommandDomains::execute(MasterDevice &m, const StringVector &args) +void CommandDomains::execute(const StringVector &args) { DomainList domains; DomainList::const_iterator di; + bool doIndent; if (args.size()) { stringstream err; @@ -100,11 +102,21 @@ void CommandDomains::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - domains = selectedDomains(m); + doIndent = getMasterIndices().size() > 1; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + domains = selectedDomains(m); - for (di = domains.begin(); di != domains.end(); di++) { - showDomain(m, *di); + if (doIndent) { + cout << "Master" << dec << *mi << endl; + } + + for (di = domains.begin(); di != domains.end(); di++) { + showDomain(m, *di, doIndent); + } } } @@ -112,7 +124,8 @@ void CommandDomains::execute(MasterDevice &m, const StringVector &args) void CommandDomains::showDomain( MasterDevice &m, - const ec_ioctl_domain_t &domain + const ec_ioctl_domain_t &domain, + bool doIndent ) { unsigned char *processData; @@ -120,8 +133,9 @@ void CommandDomains::showDomain( unsigned int i, j; ec_ioctl_domain_fmmu_t fmmu; unsigned int dataOffset; + string indent(doIndent ? " " : ""); - cout << "Domain" << dec << domain.index << ":" + cout << indent << "Domain" << dec << domain.index << ":" << " LogBaseAddr 0x" << hex << setfill('0') << setw(8) << domain.logical_base_address @@ -146,7 +160,7 @@ void CommandDomains::showDomain( for (i = 0; i < domain.fmmu_count; i++) { m.getFmmu(&fmmu, domain.index, i); - cout << " SlaveConfig " + cout << indent << " SlaveConfig " << dec << fmmu.slave_config_alias << ":" << fmmu.slave_config_position << ", SM" << (unsigned int) fmmu.sync_index << " (" @@ -165,10 +179,10 @@ void CommandDomains::showDomain( throwCommandException(err); } - cout << " " << hex << setfill('0'); + cout << indent << " " << hex << setfill('0'); for (j = 0; j < fmmu.data_size; j++) { if (j && !(j % BreakAfterBytes)) - cout << endl << " "; + cout << endl << indent << " "; cout << "0x" << setw(2) << (unsigned int) *(processData + dataOffset + j) << " "; } diff --git a/tool/CommandDomains.h b/tool/CommandDomains.h index adb981bf..2b471445 100644 --- a/tool/CommandDomains.h +++ b/tool/CommandDomains.h @@ -41,10 +41,10 @@ class CommandDomains: CommandDomains(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: - void showDomain(MasterDevice &, const ec_ioctl_domain_t &); + void showDomain(MasterDevice &, const ec_ioctl_domain_t &, bool); }; /****************************************************************************/ diff --git a/tool/CommandDownload.cpp b/tool/CommandDownload.cpp index 0ad1d650..0f2078c3 100644 --- a/tool/CommandDownload.cpp +++ b/tool/CommandDownload.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandDownload.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -83,7 +84,7 @@ string CommandDownload::helpString() const /****************************************************************************/ -void CommandDownload::execute(MasterDevice &m, const StringVector &args) +void CommandDownload::execute(const StringVector &args) { stringstream strIndex, strSubIndex, strValue, err; ec_ioctl_slave_sdo_download_t data; @@ -115,6 +116,11 @@ void CommandDownload::execute(MasterDevice &m, const StringVector &args) } data.sdo_entry_subindex = number; + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::ReadWrite); slaves = selectedSlaves(m); if (slaves.size() != 1) { diff --git a/tool/CommandDownload.h b/tool/CommandDownload.h index c2907bd8..48217877 100644 --- a/tool/CommandDownload.h +++ b/tool/CommandDownload.h @@ -41,7 +41,7 @@ class CommandDownload: CommandDownload(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: enum {DefaultBufferSize = 1024}; diff --git a/tool/CommandEoe.cpp b/tool/CommandEoe.cpp index 0d496d7e..5474ad39 100644 --- a/tool/CommandEoe.cpp +++ b/tool/CommandEoe.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandEoe.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -60,11 +61,13 @@ string CommandEoe::helpString() const /****************************************************************************/ -void CommandEoe::execute(MasterDevice &m, const StringVector &args) +void CommandEoe::execute(const StringVector &args) { ec_ioctl_master_t master; unsigned int i; ec_ioctl_eoe_handler_t eoe; + bool doIndent; + string indent; if (args.size()) { stringstream err; @@ -72,31 +75,42 @@ void CommandEoe::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - m.getMaster(&master); + doIndent = getMasterIndices().size(); + indent = doIndent ? " " : ""; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + m.getMaster(&master); - cout << "Interface Slave State " - << "RxBytes RxRate " - << "TxBytes TxRate TxQueue" - << endl; + if (doIndent) { + cout << "Master" << dec << *mi << endl; + } - for (i = 0; i < master.eoe_handler_count; i++) { - stringstream queue; - - m.getEoeHandler(&eoe, i); - - queue << eoe.tx_queued_frames << "/" << eoe.tx_queue_size; - - cout - << setw(9) << eoe.name << " " - << setw(5) << dec << eoe.slave_position << " " - << setw(5) << (eoe.open ? "up" : "down") << " " - << setw(7) << eoe.rx_bytes << " " - << setw(6) << eoe.rx_rate << " " - << setw(7) << eoe.tx_bytes << " " - << setw(6) << eoe.tx_rate << " " - << setw(7) << queue.str() + cout << indent << "Interface Slave State " + << "RxBytes RxRate " + << "TxBytes TxRate TxQueue" << endl; + + for (i = 0; i < master.eoe_handler_count; i++) { + stringstream queue; + + m.getEoeHandler(&eoe, i); + + queue << eoe.tx_queued_frames << "/" << eoe.tx_queue_size; + + cout << indent + << setw(9) << eoe.name << " " + << setw(5) << dec << eoe.slave_position << " " + << setw(5) << (eoe.open ? "up" : "down") << " " + << setw(7) << eoe.rx_bytes << " " + << setw(6) << eoe.rx_rate << " " + << setw(7) << eoe.tx_bytes << " " + << setw(6) << eoe.tx_rate << " " + << setw(7) << queue.str() + << endl; + } } } diff --git a/tool/CommandEoe.h b/tool/CommandEoe.h index d6eb8a51..479ddacd 100644 --- a/tool/CommandEoe.h +++ b/tool/CommandEoe.h @@ -41,7 +41,7 @@ class CommandEoe: CommandEoe(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandFoeRead.cpp b/tool/CommandFoeRead.cpp index 4913c95f..ab4b5041 100644 --- a/tool/CommandFoeRead.cpp +++ b/tool/CommandFoeRead.cpp @@ -35,6 +35,7 @@ using namespace std; #include "CommandFoeRead.h" #include "foe.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -73,7 +74,7 @@ string CommandFoeRead::helpString() const /****************************************************************************/ -void CommandFoeRead::execute(MasterDevice &m, const StringVector &args) +void CommandFoeRead::execute(const StringVector &args) { SlaveList slaves; ec_ioctl_slave_t *slave; @@ -86,6 +87,11 @@ void CommandFoeRead::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); slaves = selectedSlaves(m); diff --git a/tool/CommandFoeRead.h b/tool/CommandFoeRead.h index 66c0a360..1410a8ad 100644 --- a/tool/CommandFoeRead.h +++ b/tool/CommandFoeRead.h @@ -41,7 +41,7 @@ class CommandFoeRead: CommandFoeRead(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandFoeWrite.cpp b/tool/CommandFoeWrite.cpp index 421348d7..11f0fedb 100644 --- a/tool/CommandFoeWrite.cpp +++ b/tool/CommandFoeWrite.cpp @@ -37,6 +37,7 @@ using namespace std; #include "CommandFoeWrite.h" #include "foe.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -79,7 +80,7 @@ string CommandFoeWrite::helpString() const /****************************************************************************/ -void CommandFoeWrite::execute(MasterDevice &m, const StringVector &args) +void CommandFoeWrite::execute(const StringVector &args) { stringstream err; ec_ioctl_slave_foe_t data; @@ -92,6 +93,12 @@ void CommandFoeWrite::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); + if (args[0] == "-") { loadFoeData(&data, cin); if (getOutputFile().empty()) { diff --git a/tool/CommandFoeWrite.h b/tool/CommandFoeWrite.h index 4e495aac..138eb0a7 100644 --- a/tool/CommandFoeWrite.h +++ b/tool/CommandFoeWrite.h @@ -41,7 +41,7 @@ class CommandFoeWrite: CommandFoeWrite(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void loadFoeData(ec_ioctl_slave_foe_t *, const istream &); diff --git a/tool/CommandGraph.cpp b/tool/CommandGraph.cpp index 408ebe4e..639c4dd6 100644 --- a/tool/CommandGraph.cpp +++ b/tool/CommandGraph.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandGraph.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -64,7 +65,7 @@ string CommandGraph::helpString() const /****************************************************************************/ -void CommandGraph::execute(MasterDevice &m, const StringVector &args) +void CommandGraph::execute(const StringVector &args) { ec_ioctl_master_t master; unsigned int i; @@ -89,6 +90,12 @@ void CommandGraph::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + stringstream err; + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); m.getMaster(&master); diff --git a/tool/CommandGraph.h b/tool/CommandGraph.h index 49436b33..a6e8e5ff 100644 --- a/tool/CommandGraph.h +++ b/tool/CommandGraph.h @@ -41,7 +41,7 @@ class CommandGraph: CommandGraph(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandMaster.cpp b/tool/CommandMaster.cpp index 4e252dc4..c8ed9825 100644 --- a/tool/CommandMaster.cpp +++ b/tool/CommandMaster.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandMaster.h" +#include "MasterDevice.h" #define MAX_TIME_STR_SIZE 50 @@ -53,7 +54,9 @@ string CommandMaster::helpString() const << getBriefDescription() << endl << endl << "Command-specific options:" << endl - << " --master -m Index of the master to use. Default: 0." + << " --master -m Master indices. A comma-separated" << endl + << " list with ranges is supported." << endl + << " Example: 1,4,5,7-9. Default: - (all)." << endl << endl << numericInfo(); @@ -62,7 +65,7 @@ string CommandMaster::helpString() const /****************************************************************************/ -void CommandMaster::execute(MasterDevice &m, const StringVector &args) +void CommandMaster::execute(const StringVector &args) { ec_ioctl_master_t data; stringstream err; @@ -76,67 +79,79 @@ void CommandMaster::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - m.getMaster(&data); + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + m.getMaster(&data); - cout - << "Master" << m.getIndex() << endl - << " Phase: "; + cout + << "Master" << m.getIndex() << endl + << " Phase: "; - switch (data.phase) { - case 0: cout << "Waiting for device..."; break; - case 1: cout << "Idle"; break; - case 2: cout << "Operation"; break; - default: cout << "???"; - } - - cout << endl - << " Active: " << (data.active ? "yes" : "no") << endl - << " Slaves: " << data.slave_count << endl - << " Ethernet devices:" << endl; - - for (i = 0; i < 2; i++) { - cout << " " << (i == 0 ? "Main" : "Backup") << ": "; - if (data.devices[i].address[0] == 0x00 - && data.devices[i].address[1] == 0x00 - && data.devices[i].address[2] == 0x00 - && data.devices[i].address[3] == 0x00 - && data.devices[i].address[4] == 0x00 - && data.devices[i].address[5] == 0x00) { - cout << "None."; - } else { - cout << hex << setfill('0') - << setw(2) << (unsigned int) data.devices[i].address[0] << ":" - << setw(2) << (unsigned int) data.devices[i].address[1] << ":" - << setw(2) << (unsigned int) data.devices[i].address[2] << ":" - << setw(2) << (unsigned int) data.devices[i].address[3] << ":" - << setw(2) << (unsigned int) data.devices[i].address[4] << ":" - << setw(2) << (unsigned int) data.devices[i].address[5] << " (" - << (data.devices[i].attached ? "attached" : "waiting...") - << ")" << endl << dec - << " Link: " << (data.devices[i].link_state ? "UP" : "DOWN") << endl - << " Tx count: " << data.devices[i].tx_count << endl - << " Rx count: " << data.devices[i].rx_count; + switch (data.phase) { + case 0: cout << "Waiting for device..."; break; + case 1: cout << "Idle"; break; + case 2: cout << "Operation"; break; + default: cout << "???"; } - cout << endl; - } - cout << " Distributed clocks:" << endl - << " Reference clock: "; - if (data.ref_clock != 0xffff) { - cout << "Slave " << dec << data.ref_clock; - } else { - cout << "None"; - } - cout << endl - << " Application time: " << data.app_time << endl - << " "; + cout << endl + << " Active: " << (data.active ? "yes" : "no") << endl + << " Slaves: " << data.slave_count << endl + << " Ethernet devices:" << endl; - epoch = data.app_time / 1000000000 + 946684800ULL; - time_str_size = strftime(time_str, MAX_TIME_STR_SIZE, - "%Y-%m-%d %H:%M:%S", gmtime(&epoch)); - cout << string(time_str, time_str_size) << "." - << setfill('0') << setw(9) << data.app_time % 1000000000 << endl; + for (i = 0; i < 2; i++) { + cout << " " << (i == 0 ? "Main" : "Backup") << ": "; + if (data.devices[i].address[0] == 0x00 + && data.devices[i].address[1] == 0x00 + && data.devices[i].address[2] == 0x00 + && data.devices[i].address[3] == 0x00 + && data.devices[i].address[4] == 0x00 + && data.devices[i].address[5] == 0x00) { + cout << "None."; + } else { + cout << hex << setfill('0') + << setw(2) << (unsigned int) data.devices[i].address[0] + << ":" + << setw(2) << (unsigned int) data.devices[i].address[1] + << ":" + << setw(2) << (unsigned int) data.devices[i].address[2] + << ":" + << setw(2) << (unsigned int) data.devices[i].address[3] + << ":" + << setw(2) << (unsigned int) data.devices[i].address[4] + << ":" + << setw(2) << (unsigned int) data.devices[i].address[5] + << " (" + << (data.devices[i].attached ? "attached" : "waiting...") + << ")" << endl << dec + << " Link: " + << (data.devices[i].link_state ? "UP" : "DOWN") << endl + << " Tx count: " << data.devices[i].tx_count << endl + << " Rx count: " << data.devices[i].rx_count; + } + cout << endl; + } + + cout << " Distributed clocks:" << endl + << " Reference clock: "; + if (data.ref_clock != 0xffff) { + cout << "Slave " << dec << data.ref_clock; + } else { + cout << "None"; + } + cout << endl + << " Application time: " << data.app_time << endl + << " "; + + epoch = data.app_time / 1000000000 + 946684800ULL; + time_str_size = strftime(time_str, MAX_TIME_STR_SIZE, + "%Y-%m-%d %H:%M:%S", gmtime(&epoch)); + cout << string(time_str, time_str_size) << "." + << setfill('0') << setw(9) << data.app_time % 1000000000 << endl; + } } /*****************************************************************************/ diff --git a/tool/CommandMaster.h b/tool/CommandMaster.h index c1abc9ac..45add947 100644 --- a/tool/CommandMaster.h +++ b/tool/CommandMaster.h @@ -41,7 +41,7 @@ class CommandMaster: CommandMaster(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandPdos.cpp b/tool/CommandPdos.cpp index d8a56bf5..876de3c5 100644 --- a/tool/CommandPdos.cpp +++ b/tool/CommandPdos.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandPdos.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -88,11 +89,11 @@ string CommandPdos::helpString() const /****************************************************************************/ -void CommandPdos::execute(MasterDevice &m, const StringVector &args) +void CommandPdos::execute(const StringVector &args) { SlaveList slaves; SlaveList::const_iterator si; - bool showHeader; + bool showHeader, multiMaster; if (args.size()) { stringstream err; @@ -100,12 +101,18 @@ void CommandPdos::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - slaves = selectedSlaves(m); - showHeader = slaves.size() > 1; + multiMaster = getMasterIndices().size() > 1; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); + showHeader = multiMaster || slaves.size() > 1; - for (si = slaves.begin(); si != slaves.end(); si++) { - listSlavePdos(m, *si, showHeader); + for (si = slaves.begin(); si != slaves.end(); si++) { + listSlavePdos(m, *si, showHeader); + } } } @@ -123,7 +130,8 @@ void CommandPdos::listSlavePdos( unsigned int i, j, k; if (showHeader) - cout << "=== Slave " << slave.position << " ===" << endl; + cout << "=== Master " << m.getIndex() + << ", Slave " << slave.position << " ===" << endl; for (i = 0; i < slave.sync_count; i++) { m.getSync(&sync, slave.position, i); diff --git a/tool/CommandPdos.h b/tool/CommandPdos.h index 2019a89d..91539509 100644 --- a/tool/CommandPdos.h +++ b/tool/CommandPdos.h @@ -41,7 +41,7 @@ class CommandPdos: CommandPdos(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void listSlavePdos(MasterDevice &, const ec_ioctl_slave_t &, bool); diff --git a/tool/CommandRegRead.cpp b/tool/CommandRegRead.cpp index 90f3bd90..4456f3df 100644 --- a/tool/CommandRegRead.cpp +++ b/tool/CommandRegRead.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandRegRead.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -78,7 +79,7 @@ string CommandRegRead::helpString() const /****************************************************************************/ -void CommandRegRead::execute(MasterDevice &m, const StringVector &args) +void CommandRegRead::execute(const StringVector &args) { SlaveList slaves; ec_ioctl_slave_reg_t data; @@ -141,6 +142,11 @@ void CommandRegRead::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); slaves = selectedSlaves(m); diff --git a/tool/CommandRegRead.h b/tool/CommandRegRead.h index 5969735c..2f112b0e 100644 --- a/tool/CommandRegRead.h +++ b/tool/CommandRegRead.h @@ -41,7 +41,7 @@ class CommandRegRead: CommandRegRead(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandRegWrite.cpp b/tool/CommandRegWrite.cpp index 84336e34..2fa4c816 100644 --- a/tool/CommandRegWrite.cpp +++ b/tool/CommandRegWrite.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandRegWrite.h" #include "sii_crc.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -80,7 +81,7 @@ string CommandRegWrite::helpString() const /****************************************************************************/ -void CommandRegWrite::execute(MasterDevice &m, const StringVector &args) +void CommandRegWrite::execute(const StringVector &args) { stringstream strOffset, err; ec_ioctl_slave_reg_t data; @@ -100,6 +101,12 @@ void CommandRegWrite::execute(MasterDevice &m, const StringVector &args) err << "Invalid offset '" << args[0] << "'!"; throwInvalidUsageException(err); } + + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); if (getDataType().empty()) { if (args[1] == "-") { diff --git a/tool/CommandRegWrite.h b/tool/CommandRegWrite.h index 0380d811..c3bc770f 100644 --- a/tool/CommandRegWrite.h +++ b/tool/CommandRegWrite.h @@ -41,7 +41,7 @@ class CommandRegWrite: CommandRegWrite(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); private: void loadRegData(ec_ioctl_slave_reg_t *, const istream &); diff --git a/tool/CommandSdos.cpp b/tool/CommandSdos.cpp index 7f97c669..484c14f4 100644 --- a/tool/CommandSdos.cpp +++ b/tool/CommandSdos.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandSdos.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -86,11 +87,11 @@ string CommandSdos::helpString() const /****************************************************************************/ -void CommandSdos::execute(MasterDevice &m, const StringVector &args) +void CommandSdos::execute(const StringVector &args) { SlaveList slaves; SlaveList::const_iterator si; - bool showHeader; + bool showHeader, multiMaster; if (args.size()) { stringstream err; @@ -98,12 +99,18 @@ void CommandSdos::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - slaves = selectedSlaves(m); - showHeader = slaves.size() > 1; + multiMaster = getMasterIndices().size() > 1; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); + showHeader = multiMaster || slaves.size() > 1; - for (si = slaves.begin(); si != slaves.end(); si++) { - listSlaveSdos(m, *si, showHeader); + for (si = slaves.begin(); si != slaves.end(); si++) { + listSlaveSdos(m, *si, showHeader); + } } } @@ -121,7 +128,8 @@ void CommandSdos::listSlaveSdos( const DataType *d; if (showHeader) - cout << "=== Slave " << slave.position << " ===" << endl; + cout << "=== Master " << m.getIndex() + << ", Slave " << slave.position << " ===" << endl; for (i = 0; i < slave.sdo_count; i++) { m.getSdo(&sdo, slave.position, i); diff --git a/tool/CommandSdos.h b/tool/CommandSdos.h index 10612755..7aa301f2 100644 --- a/tool/CommandSdos.h +++ b/tool/CommandSdos.h @@ -41,7 +41,7 @@ class CommandSdos: CommandSdos(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void listSlaveSdos(MasterDevice &, const ec_ioctl_slave_t &, bool); diff --git a/tool/CommandSiiRead.cpp b/tool/CommandSiiRead.cpp index 68bb5164..611d6558 100644 --- a/tool/CommandSiiRead.cpp +++ b/tool/CommandSiiRead.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandSiiRead.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -73,7 +74,7 @@ string CommandSiiRead::helpString() const /****************************************************************************/ -void CommandSiiRead::execute(MasterDevice &m, const StringVector &args) +void CommandSiiRead::execute(const StringVector &args) { SlaveList slaves; ec_ioctl_slave_t *slave; @@ -88,6 +89,11 @@ void CommandSiiRead::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); slaves = selectedSlaves(m); diff --git a/tool/CommandSiiRead.h b/tool/CommandSiiRead.h index 4f021e64..8f797a63 100644 --- a/tool/CommandSiiRead.h +++ b/tool/CommandSiiRead.h @@ -41,7 +41,7 @@ class CommandSiiRead: CommandSiiRead(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: struct CategoryName { diff --git a/tool/CommandSiiWrite.cpp b/tool/CommandSiiWrite.cpp index 67bb40c5..2f3a2dd1 100644 --- a/tool/CommandSiiWrite.cpp +++ b/tool/CommandSiiWrite.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandSiiWrite.h" #include "sii_crc.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -75,7 +76,7 @@ string CommandSiiWrite::helpString() const /****************************************************************************/ -void CommandSiiWrite::execute(MasterDevice &m, const StringVector &args) +void CommandSiiWrite::execute(const StringVector &args) { stringstream err; ec_ioctl_slave_sii_t data; @@ -87,6 +88,12 @@ void CommandSiiWrite::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); + if (args[0] == "-") { loadSiiData(&data, cin); } else { diff --git a/tool/CommandSiiWrite.h b/tool/CommandSiiWrite.h index a8f35a15..a22b8db6 100644 --- a/tool/CommandSiiWrite.h +++ b/tool/CommandSiiWrite.h @@ -41,7 +41,7 @@ class CommandSiiWrite: CommandSiiWrite(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void loadSiiData(ec_ioctl_slave_sii_t *, const istream &); diff --git a/tool/CommandSlaves.cpp b/tool/CommandSlaves.cpp index 8620dfd7..1ef54eb5 100644 --- a/tool/CommandSlaves.cpp +++ b/tool/CommandSlaves.cpp @@ -34,6 +34,7 @@ using namespace std; #include "CommandSlaves.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -105,9 +106,10 @@ string CommandSlaves::helpString() const /****************************************************************************/ -void CommandSlaves::execute(MasterDevice &m, const StringVector &args) +void CommandSlaves::execute(const StringVector &args) { SlaveList slaves; + bool doIndent; if (args.size()) { stringstream err; @@ -115,13 +117,23 @@ void CommandSlaves::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::Read); - slaves = selectedSlaves(m); + doIndent = getMasterIndices().size() > 1; + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::Read); + slaves = selectedSlaves(m); - if (getVerbosity() == Verbose) { - showSlaves(m, slaves); - } else { - listSlaves(m, slaves); + if (doIndent) { + cout << "Master" << dec << *mi << endl; + } + + if (getVerbosity() == Verbose) { + showSlaves(m, slaves); + } else { + listSlaves(m, slaves, doIndent); + } } } @@ -129,7 +141,8 @@ void CommandSlaves::execute(MasterDevice &m, const StringVector &args) void CommandSlaves::listSlaves( MasterDevice &m, - const SlaveList &slaves + const SlaveList &slaves, + bool doIndent ) { ec_ioctl_master_t master; @@ -143,6 +156,7 @@ void CommandSlaves::listSlaves( stringstream str; unsigned int maxPosWidth = 0, maxAliasWidth = 0, maxRelPosWidth = 0, maxStateWidth = 0; + string indent(doIndent ? " " : ""); m.getMaster(&master); @@ -200,7 +214,7 @@ void CommandSlaves::listSlaves( } for (iter = infoList.begin(); iter != infoList.end(); iter++) { - cout << setfill(' ') << right + cout << indent << setfill(' ') << right << setw(maxPosWidth) << iter->pos << " " << setw(maxAliasWidth) << iter->alias << ":" << left @@ -222,7 +236,8 @@ void CommandSlaves::showSlaves( int i; for (si = slaves.begin(); si != slaves.end(); si++) { - cout << "=== Slave " << dec << si->position << " ===" << endl; + cout << "=== Master " << dec << m.getIndex() + << ", Slave " << dec << si->position << " ===" << endl; if (si->alias) cout << "Alias: " << si->alias << endl; diff --git a/tool/CommandSlaves.h b/tool/CommandSlaves.h index 6e861004..1ac5b673 100644 --- a/tool/CommandSlaves.h +++ b/tool/CommandSlaves.h @@ -41,7 +41,7 @@ class CommandSlaves: CommandSlaves(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: struct Info { @@ -53,7 +53,7 @@ class CommandSlaves: string name; }; - void listSlaves(MasterDevice &, const SlaveList &); + void listSlaves(MasterDevice &, const SlaveList &, bool); void showSlaves(MasterDevice &, const SlaveList &); static bool slaveInList( const ec_ioctl_slave_t &, const SlaveList &); diff --git a/tool/CommandStates.cpp b/tool/CommandStates.cpp index 35992d9c..24f248ba 100644 --- a/tool/CommandStates.cpp +++ b/tool/CommandStates.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandStates.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -65,7 +66,7 @@ string CommandStates::helpString() const /****************************************************************************/ -void CommandStates::execute(MasterDevice &m, const StringVector &args) +void CommandStates::execute(const StringVector &args) { SlaveList slaves; SlaveList::const_iterator si; @@ -97,15 +98,16 @@ void CommandStates::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } - m.open(MasterDevice::ReadWrite); - slaves = selectedSlaves(m); + MasterIndexList::const_iterator mi; + for (mi = getMasterIndices().begin(); + mi != getMasterIndices().end(); mi++) { + MasterDevice m(*mi); + m.open(MasterDevice::ReadWrite); + slaves = selectedSlaves(m); - if (!slaves.size() && getVerbosity() != Quiet) { - cerr << "Warning: Selection matches no slaves!" << endl; - } - - for (si = slaves.begin(); si != slaves.end(); si++) { - m.requestState(si->position, state); + for (si = slaves.begin(); si != slaves.end(); si++) { + m.requestState(si->position, state); + } } } diff --git a/tool/CommandStates.h b/tool/CommandStates.h index 3258dac3..305b8347 100644 --- a/tool/CommandStates.h +++ b/tool/CommandStates.h @@ -41,7 +41,7 @@ class CommandStates: CommandStates(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandUpload.cpp b/tool/CommandUpload.cpp index 5bff2096..9cf6e423 100644 --- a/tool/CommandUpload.cpp +++ b/tool/CommandUpload.cpp @@ -32,6 +32,7 @@ using namespace std; #include "CommandUpload.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -81,7 +82,7 @@ string CommandUpload::helpString() const /****************************************************************************/ -void CommandUpload::execute(MasterDevice &m, const StringVector &args) +void CommandUpload::execute(const StringVector &args) { SlaveList slaves; stringstream err, strIndex, strSubIndex; @@ -113,6 +114,11 @@ void CommandUpload::execute(MasterDevice &m, const StringVector &args) } data.sdo_entry_subindex = uval; + if (getMasterIndices().size() != 1) { + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); slaves = selectedSlaves(m); if (slaves.size() != 1) { diff --git a/tool/CommandUpload.h b/tool/CommandUpload.h index 84452d0d..2dae88de 100644 --- a/tool/CommandUpload.h +++ b/tool/CommandUpload.h @@ -41,7 +41,7 @@ class CommandUpload: CommandUpload(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: enum {DefaultBufferSize = 64 * 1024}; diff --git a/tool/CommandVersion.cpp b/tool/CommandVersion.cpp index 02c7efeb..c81b8be7 100644 --- a/tool/CommandVersion.cpp +++ b/tool/CommandVersion.cpp @@ -54,7 +54,7 @@ string CommandVersion::helpString() const /****************************************************************************/ -void CommandVersion::execute(MasterDevice &m, const StringVector &args) +void CommandVersion::execute(const StringVector &args) { if (args.size()) { stringstream err; diff --git a/tool/CommandVersion.h b/tool/CommandVersion.h index 2579349e..842db320 100644 --- a/tool/CommandVersion.h +++ b/tool/CommandVersion.h @@ -41,7 +41,7 @@ class CommandVersion: CommandVersion(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); }; /****************************************************************************/ diff --git a/tool/CommandXml.cpp b/tool/CommandXml.cpp index 9621b398..8682fe57 100644 --- a/tool/CommandXml.cpp +++ b/tool/CommandXml.cpp @@ -33,6 +33,7 @@ using namespace std; #include "CommandXml.h" +#include "MasterDevice.h" /*****************************************************************************/ @@ -68,7 +69,7 @@ string CommandXml::helpString() const /****************************************************************************/ -void CommandXml::execute(MasterDevice &m, const StringVector &args) +void CommandXml::execute(const StringVector &args) { SlaveList slaves; SlaveList::const_iterator si; @@ -79,6 +80,12 @@ void CommandXml::execute(MasterDevice &m, const StringVector &args) throwInvalidUsageException(err); } + if (getMasterIndices().size() != 1) { + stringstream err; + err << getName() << " requires to select a single master!"; + throwInvalidUsageException(err); + } + MasterDevice m(getMasterIndices().front()); m.open(MasterDevice::Read); slaves = selectedSlaves(m); diff --git a/tool/CommandXml.h b/tool/CommandXml.h index fd593762..5e8a2b55 100644 --- a/tool/CommandXml.h +++ b/tool/CommandXml.h @@ -41,7 +41,7 @@ class CommandXml: CommandXml(); string helpString() const; - void execute(MasterDevice &, const StringVector &); + void execute(const StringVector &); protected: void generateSlaveXml(MasterDevice &, const ec_ioctl_slave_t &, diff --git a/tool/Makefile.am b/tool/Makefile.am index 9bf6dde5..abc5f221 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -38,8 +38,8 @@ bin_PROGRAMS = ethercat ethercat_SOURCES = \ Command.cpp \ CommandAlias.cpp \ - CommandConfig.cpp \ CommandCStruct.cpp \ + CommandConfig.cpp \ CommandData.cpp \ CommandDebug.cpp \ CommandDomains.cpp \ @@ -62,6 +62,7 @@ ethercat_SOURCES = \ CommandXml.cpp \ FoeCommand.cpp \ MasterDevice.cpp \ + NumberListParser.cpp \ SdoCommand.cpp \ main.cpp \ sii_crc.cpp @@ -75,8 +76,8 @@ endif noinst_HEADERS = \ Command.h \ CommandAlias.h \ - CommandConfig.h \ CommandCStruct.h \ + CommandConfig.h \ CommandData.h \ CommandDebug.h \ CommandDomains.h \ @@ -99,6 +100,7 @@ noinst_HEADERS = \ CommandXml.h \ FoeCommand.h \ MasterDevice.h \ + NumberListParser.h \ SdoCommand.h \ sii_crc.h diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index 1df41d29..49a2a923 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -42,10 +42,11 @@ using namespace std; /****************************************************************************/ -MasterDevice::MasterDevice() +MasterDevice::MasterDevice(unsigned int index): + index(index), + masterCount(0U), + fd(-1) { - index = 0; - fd = -1; } /****************************************************************************/ @@ -69,6 +70,7 @@ void MasterDevice::open(Permissions perm) stringstream deviceName; if (fd == -1) { // not already open + ec_ioctl_module_t module_data; deviceName << "/dev/EtherCAT" << index; if ((fd = ::open(deviceName.str().c_str(), @@ -78,6 +80,16 @@ void MasterDevice::open(Permissions perm) << strerror(errno); throw MasterDeviceException(err); } + + getModule(&module_data); + if (module_data.ioctl_version_magic != EC_IOCTL_VERSION_MAGIC) { + stringstream err; + err << "ioctl() version magic is differing: " + << deviceName << ": " << module_data.ioctl_version_magic + << ", ethercat tool: " << EC_IOCTL_VERSION_MAGIC; + throw MasterDeviceException(err); + } + masterCount = module_data.master_count; } } @@ -93,6 +105,17 @@ void MasterDevice::close() /****************************************************************************/ +void MasterDevice::getModule(ec_ioctl_module_t *data) +{ + if (ioctl(fd, EC_IOCTL_MODULE, data) < 0) { + stringstream err; + err << "Failed to get module information: " << strerror(errno); + throw MasterDeviceException(err); + } +} + +/****************************************************************************/ + void MasterDevice::getMaster(ec_ioctl_master_t *data) { if (ioctl(fd, EC_IOCTL_MASTER, data) < 0) { diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index 37f8ce7a..c47f3675 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -79,7 +79,7 @@ class MasterDeviceSdoAbortException: class MasterDevice { public: - MasterDevice(); + MasterDevice(unsigned int = 0U); ~MasterDevice(); void setIndex(unsigned int); @@ -89,6 +89,8 @@ class MasterDevice void open(Permissions); void close(); + void getModule(ec_ioctl_module_t *); + void getMaster(ec_ioctl_master_t *); void getConfig(ec_ioctl_config_t *, unsigned int); void getConfigPdo(ec_ioctl_config_pdo_t *, unsigned int, uint8_t, @@ -121,8 +123,11 @@ class MasterDevice void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t); #endif + unsigned int getMasterCount() const {return masterCount;} + private: unsigned int index; + unsigned int masterCount; int fd; }; diff --git a/tool/NumberListParser.cpp b/tool/NumberListParser.cpp new file mode 100644 index 00000000..bb67ecdb --- /dev/null +++ b/tool/NumberListParser.cpp @@ -0,0 +1,230 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +#include +#include +#include +using namespace std; + +#include "NumberListParser.h" + +/*****************************************************************************/ + +NumberListParser::NumberListParser(): + max(0U), + hasMax(false) +{ +} + +/*****************************************************************************/ + +NumberListParser::~NumberListParser() +{ +} + +/*****************************************************************************/ + +NumberListParser::NumberList NumberListParser::parse(const char *data) +{ + NumberList ret; + unsigned int i = 0, size = strlen(data), firstNum = 0U, secondNum = 0U; + typedef enum { + SectionStart, + FirstNumber, + Range, + SecondNumber, + Finished + } State; + State state = SectionStart; + + while (state != Finished) { + switch (state) { + case SectionStart: + if (i >= size) { + state = Finished; + } else if (isNumeric(data[i])) { + firstNum = parseNumber(data, &i, size); + state = FirstNumber; + } else if (data[i] == '-') { + firstNum = 0U; + i++; + state = Range; + } else if (data[i] == ',') { + i++; + } else { + stringstream err; + err << "Invalid character " << data[i] + << " at position " << i << "in state " + << state << "." << endl; + throw runtime_error(err.str()); + } + break; + + case FirstNumber: + if (i >= size) { + ret.push_back(firstNum); + state = Finished; + } else if (data[i] == '-') { + i++; + state = Range; + } else if (data[i] == ',') { + i++; + ret.push_back(firstNum); + state = SectionStart; + } else { + stringstream err; + err << "Invalid character " << data[i] + << " at position " << i << "in state " + << state << "." << endl; + throw runtime_error(err.str()); + } + break; + + case Range: + if (i >= size) { + secondNum = maximum(); + NumberList r = range(firstNum, secondNum); + ret.splice(ret.end(), r); + state = Finished; + } else if (isNumeric(data[i])) { + secondNum = parseNumber(data, &i, size); + state = SecondNumber; + } else if (data[i] == ',') { + i++; + secondNum = maximum(); + NumberList r = range(firstNum, secondNum); + ret.splice(ret.end(), r); + state = SectionStart; + } else { + stringstream err; + err << "Invalid character " << data[i] + << " at position " << i << "in state " + << state << "." << endl; + throw runtime_error(err.str()); + } + break; + + case SecondNumber: + if (i >= size) { + NumberList r = range(firstNum, secondNum); + ret.splice(ret.end(), r); + state = Finished; + } else if (data[i] == ',') { + i++; + NumberList r = range(firstNum, secondNum); + ret.splice(ret.end(), r); + state = SectionStart; + } else { + stringstream err; + err << "Invalid character " << data[i] + << " at position " << i << "in state " + << state << "." << endl; + throw runtime_error(err.str()); + } + break; + + default: + { + stringstream err; + err << "Invalid state " << state << "."; + throw runtime_error(err.str()); + } + } + } + + return ret; +} + +/*****************************************************************************/ + +unsigned int NumberListParser::maximum() +{ + if (!hasMax) { + max = getMax(); + } + + return max; +} + +/*****************************************************************************/ + +bool NumberListParser::isNumeric(char c) +{ + return c >= '0' && c <= '9'; +} + +/*****************************************************************************/ + +unsigned int NumberListParser::parseNumber( + const char *data, + unsigned int *i, + unsigned int size + ) +{ + unsigned int numSize = 0U, ret; + + while (*i + numSize < size && isNumeric(data[*i + numSize])) { + numSize++; + } + + if (numSize) { + stringstream str; + str << string(data + *i, numSize); + str >> ret; + } else { + throw runtime_error("EOF"); + } + + *i = *i + numSize; + return ret; +} + +/****************************************************************************/ + +NumberListParser::NumberList NumberListParser::range( + unsigned int i, + unsigned int j + ) +{ + NumberList ret; + + if (i <= j) { + for (; i <= j; i++) { + ret.push_back(i); + } + } else { + for (; i >= j; i--) { + ret.push_back(i); + } + } + + return ret; +} + +/****************************************************************************/ diff --git a/tool/NumberListParser.h b/tool/NumberListParser.h new file mode 100644 index 00000000..60bb2cfa --- /dev/null +++ b/tool/NumberListParser.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * + * $Id$ + * + * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH + * + * This file is part of the IgH EtherCAT Master. + * + * The IgH EtherCAT Master is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * The IgH EtherCAT Master is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the IgH EtherCAT Master; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * --- + * + * The license mentioned above concerns the source code only. Using the + * EtherCAT technology and brand is only permitted in compliance with the + * industrial property and similar rights of Beckhoff Automation GmbH. + * + ****************************************************************************/ + +#include +using namespace std; + +/*****************************************************************************/ + +class NumberListParser +{ + public: + NumberListParser(); + ~NumberListParser(); + + typedef list NumberList; + + NumberList parse(const char *); + + virtual unsigned int getMax() = 0; + + private: + unsigned int max; + bool hasMax; + + unsigned int maximum(); + + static bool isNumeric(char); + static unsigned int parseNumber(const char *, unsigned int *, + unsigned int); + static NumberList range(unsigned int, unsigned int); +}; + +/****************************************************************************/ diff --git a/tool/main.cpp b/tool/main.cpp index 3f7950d0..b3ca9a46 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -61,19 +61,21 @@ using namespace std; #include "CommandVersion.h" #include "CommandXml.h" +#include "NumberListParser.h" +#include "MasterDevice.h" + /*****************************************************************************/ typedef list CommandList; CommandList commandList; -MasterDevice masterDev; - string binaryBaseName; string commandName; Command::StringVector commandArgs; // option variables -unsigned int masterIndex = 0; +list masterIndices; +string masterIndexList = "-"; // all masters int slavePosition = -1; int slaveAlias = -1; int domainIndex = -1; @@ -128,6 +130,20 @@ string usage() /*****************************************************************************/ +class MasterIndexParser: + public NumberListParser +{ + unsigned int getMax() + { + MasterDevice dev; + dev.setIndex(0U); + dev.open(MasterDevice::Read); + return dev.getMasterCount() - 1; + }; +}; + +/*****************************************************************************/ + void getOptions(int argc, char **argv) { int c, argCount; @@ -153,16 +169,7 @@ void getOptions(int argc, char **argv) switch (c) { case 'm': - str.clear(); - str.str(""); - str << optarg; - str >> resetiosflags(ios::basefield) // guess base from prefix - >> masterIndex; - if (str.fail() || masterIndex < 0) { - cerr << "Invalid master number " << optarg << "!" << endl - << endl << usage(); - exit(1); - } + masterIndexList = optarg; break; case 'a': @@ -252,6 +259,19 @@ void getOptions(int argc, char **argv) } } + try { + MasterIndexParser p; + masterIndices = p.parse(masterIndexList.c_str()); + } catch (MasterDeviceException &e) { + cerr << "Failed to obtain number of masters: " << e.what() << endl; + exit(1); + } catch (runtime_error &e) { + cerr << "Invalid master argument " << masterIndexList + << ": " << e.what() << endl + << endl << usage(); + exit(1); + } + commandName = argv[optind]; while (++optind < argc) commandArgs.push_back(string(argv[optind])); @@ -323,13 +343,19 @@ int main(int argc, char **argv) getOptions(argc, argv); matchingCommands = getMatchingCommands(commandName); - masterDev.setIndex(masterIndex); + + if (masterIndices.empty()) { + cerr << "List of master indices may not be empty!" << endl + << endl << usage(); + exit(1); + } if (matchingCommands.size()) { if (matchingCommands.size() == 1) { cmd = matchingCommands.front(); if (!helpRequested) { try { + cmd->setMasterIndices(masterIndices); cmd->setVerbosity(verbosity); cmd->setAlias(slaveAlias); cmd->setPosition(slavePosition); @@ -337,7 +363,7 @@ int main(int argc, char **argv) cmd->setDataType(dataTypeStr); cmd->setOutputFile(outputFile); cmd->setForce(force); - cmd->execute(masterDev, commandArgs); + cmd->execute(commandArgs); } catch (InvalidUsageException &e) { cerr << e.what() << endl << endl; cerr << binaryBaseName << " " << cmd->helpString();