From 902865c32f085b7e5d50f53416c81841c893b2df Mon Sep 17 00:00:00 2001 From: Florian Pose <fp@igh-essen.com> Date: Mon, 2 Jun 2008 10:51:31 +0000 Subject: [PATCH] Added 'pdos' command to ethercat tool. --- master/cdev.c | 283 ++++++++++++++++++++++++++++++++++++----------- master/ioctl.h | 72 ++++++++++-- tools/Master.cpp | 210 ++++++++++++++++++++++++++++------- tools/Master.h | 14 ++- tools/main.cpp | 34 ++++-- 5 files changed, 491 insertions(+), 122 deletions(-) diff --git a/master/cdev.c b/master/cdev.c index fdf2f79d..9f522989 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -52,15 +52,15 @@ int eccdev_open(struct inode *, struct file *); int eccdev_release(struct inode *, struct file *); ssize_t eccdev_read(struct file *, char __user *, size_t, loff_t *); ssize_t eccdev_write(struct file *, const char __user *, size_t, loff_t *); -int eccdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +long eccdev_ioctl(struct file *, unsigned int, unsigned long); /*****************************************************************************/ static struct file_operations eccdev_fops = { - .owner = THIS_MODULE, - .open = eccdev_open, - .release = eccdev_release, - .ioctl = eccdev_ioctl + .owner = THIS_MODULE, + .open = eccdev_open, + .release = eccdev_release, + .unlocked_ioctl = eccdev_ioctl }; /** \endcond */ @@ -107,9 +107,11 @@ void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */) int eccdev_open(struct inode *inode, struct file *filp) { ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); + ec_master_t *master = cdev->master; filp->private_data = cdev; - EC_DBG("File opened.\n"); + if (master->debug_level) + EC_DBG("File opened.\n"); return 0; } @@ -117,88 +119,237 @@ int eccdev_open(struct inode *inode, struct file *filp) int eccdev_release(struct inode *inode, struct file *filp) { - //ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); + ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; + ec_master_t *master = cdev->master; - EC_DBG("File closed.\n"); + if (master->debug_level) + EC_DBG("File closed.\n"); return 0; } /*****************************************************************************/ -int eccdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); + ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; ec_master_t *master = cdev->master; + long retval = 0; if (master->debug_level) - EC_DBG("ioctl(inode = %x, filp = %x, cmd = %u, arg = %u)\n", - (u32) inode, (u32) filp, (u32) cmd, (u32) arg); + EC_DBG("ioctl(filp = %x, cmd = %u, arg = %u)\n", + (u32) filp, (u32) cmd, (u32) arg); + // FIXME lock + switch (cmd) { case EC_IOCTL_SLAVE_COUNT: + retval = master->slave_count; + break; + + case EC_IOCTL_SLAVE: { - unsigned int slave_count = master->slave_count; - EC_INFO("EC_IOCTL_SLAVE_COUNT\n"); - if (!arg) - return -EFAULT; - if (copy_to_user((void __user *) arg, &slave_count, - sizeof(unsigned int))) - return -EFAULT; - return 0; + ec_ioctl_slave_t data; + const ec_slave_t *slave; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.position))) { + EC_ERR("Slave %u does not exist!\n", data.position); + retval = -EINVAL; + break; + } + + data.vendor_id = slave->sii.vendor_id; + data.product_code = slave->sii.product_code; + data.alias = slave->sii.alias; + data.state = slave->current_state; + + data.sync_count = slave->sii.sync_count; + + if (slave->sii.name) { + strncpy(data.name, slave->sii.name, + EC_IOCTL_SLAVE_NAME_SIZE); + data.name[EC_IOCTL_SLAVE_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + + break; } - case EC_IOCTL_SLAVE_INFO: + case EC_IOCTL_SYNC: { - struct ec_ioctl_slave_info *infos, *info; - unsigned int slave_count = master->slave_count; + ec_ioctl_sync_t data; const ec_slave_t *slave; - unsigned int i = 0; - - if (master->debug_level) - EC_DBG("EC_IOCTL_SLAVE_INFOS\n"); - - if (!slave_count) - return 0; - - if (!arg) - return -EFAULT; - - if (!(infos = kmalloc(slave_count * - sizeof(struct ec_ioctl_slave_info), - GFP_KERNEL))) - return -ENOMEM; - - list_for_each_entry(slave, &master->slaves, list) { - info = &infos[i++]; - info->vendor_id = slave->sii.vendor_id; - info->product_code = slave->sii.product_code; - info->alias = slave->sii.alias; - info->ring_position = slave->ring_position; - info->state = slave->current_state; - if (slave->sii.name) { - strncpy(info->description, slave->sii.name, - EC_IOCTL_SLAVE_INFO_DESC_SIZE); - info->description[EC_IOCTL_SLAVE_INFO_DESC_SIZE - 1] - = 0; - } else { - info->description[0] = 0; - } - } - - if (copy_to_user((void __user *) arg, infos, slave_count * - sizeof(struct ec_ioctl_slave_info))) { - kfree(infos); - return -EFAULT; - } - - kfree(infos); - return 0; + const ec_sync_t *sync; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + + data.physical_start_address = sync->physical_start_address; + data.default_size = sync->length; + data.control_register = sync->control_register; + data.enable = sync->enable; + data.assign_source = sync->assign_source; + data.pdo_count = ec_pdo_list_count(&sync->pdos); + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; + } + + case EC_IOCTL_PDO: + { + ec_ioctl_pdo_t data; + const ec_slave_t *slave; + const ec_sync_t *sync; + const ec_pdo_t *pdo; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( + &sync->pdos, data.pdo_pos))) { + EC_ERR("Sync manager %u does not contain a Pdo with " + "position %u in slave %u!\n", data.sync_index, + data.pdo_pos, data.slave_position); + retval = -EINVAL; + break; + } + + data.dir = pdo->dir; + data.index = pdo->index; + data.entry_count = ec_pdo_entry_count(pdo); + + if (pdo->name) { + strncpy(data.name, pdo->name, EC_IOCTL_PDO_NAME_SIZE); + data.name[EC_IOCTL_PDO_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; + } + + case EC_IOCTL_PDO_ENTRY: + { + ec_ioctl_pdo_entry_t data; + const ec_slave_t *slave; + const ec_sync_t *sync; + const ec_pdo_t *pdo; + const ec_pdo_entry_t *entry; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( + &sync->pdos, data.pdo_pos))) { + EC_ERR("Sync manager %u does not contain a Pdo with " + "position %u in slave %u!\n", data.sync_index, + data.pdo_pos, data.slave_position); + retval = -EINVAL; + break; + } + + if (!(entry = ec_pdo_find_entry_by_pos_const( + pdo, data.entry_pos))) { + EC_ERR("Pdo 0x%04X does not contain an entry with " + "position %u in slave %u!\n", data.pdo_pos, + data.entry_pos, data.slave_position); + retval = -EINVAL; + break; + } + + data.index = entry->index; + data.subindex = entry->subindex; + data.bit_length = entry->bit_length; + if (entry->name) { + strncpy(data.name, entry->name, + EC_IOCTL_PDO_ENTRY_NAME_SIZE); + data.name[EC_IOCTL_PDO_ENTRY_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; } default: - return -ENOIOCTLCMD; + retval = -ENOIOCTLCMD; } + + return retval; } /*****************************************************************************/ diff --git a/master/ioctl.h b/master/ioctl.h index 4048e531..e21d5069 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -44,22 +44,80 @@ /*****************************************************************************/ enum { - EC_IOCTL_SLAVE_COUNT = 0, - EC_IOCTL_SLAVE_INFO, + EC_IOCTL_SLAVE_COUNT, + EC_IOCTL_SLAVE, + EC_IOCTL_SYNC, + EC_IOCTL_PDO, + EC_IOCTL_PDO_ENTRY, }; /*****************************************************************************/ -#define EC_IOCTL_SLAVE_INFO_DESC_SIZE 243 +#define EC_IOCTL_SLAVE_NAME_SIZE 114 -struct ec_ioctl_slave_info { +typedef struct { + // input + uint16_t position; + + // outputs uint32_t vendor_id; uint32_t product_code; uint16_t alias; - uint16_t ring_position; uint8_t state; - char description[EC_IOCTL_SLAVE_INFO_DESC_SIZE]; -}; + uint8_t sync_count; + char name[EC_IOCTL_SLAVE_NAME_SIZE]; +} ec_ioctl_slave_t; + +/*****************************************************************************/ + +typedef struct { + // inputs + uint16_t slave_position; + unsigned int sync_index; + + // outputs + uint16_t physical_start_address; + uint16_t default_size; + uint8_t control_register; + uint8_t enable; + uint8_t assign_source; + uint8_t pdo_count; +} ec_ioctl_sync_t; + +/*****************************************************************************/ + +#define EC_IOCTL_PDO_NAME_SIZE 114 + +typedef struct { + // inputs + uint16_t slave_position; + unsigned int sync_index; + unsigned int pdo_pos; + + // outputs + uint8_t dir; + uint16_t index; + uint8_t entry_count; + char name[EC_IOCTL_PDO_NAME_SIZE]; +} ec_ioctl_pdo_t; + +/*****************************************************************************/ + +#define EC_IOCTL_PDO_ENTRY_NAME_SIZE 110 + +typedef struct { + // inputs + uint16_t slave_position; + unsigned int sync_index; + unsigned int pdo_pos; + unsigned int entry_pos; + + // outputs + uint16_t index; + uint8_t subindex; + uint8_t bit_length; + char name[EC_IOCTL_PDO_NAME_SIZE]; +} ec_ioctl_pdo_entry_t; /*****************************************************************************/ diff --git a/tools/Master.cpp b/tools/Master.cpp index b5e4fad2..d0bc9da3 100644 --- a/tools/Master.cpp +++ b/tools/Master.cpp @@ -16,7 +16,6 @@ using namespace std; #include "Master.h" -#include "../master/ioctl.h" /****************************************************************************/ @@ -63,70 +62,205 @@ void Master::close() /****************************************************************************/ +void Master::listSlaves() +{ + unsigned int numSlaves = slaveCount(), i; + ec_ioctl_slave_t slave; + uint16_t lastAlias, aliasIndex; + + lastAlias = 0; + aliasIndex = 0; + for (i = 0; i < numSlaves; i++) { + getSlave(&slave, i); + cout << setw(2) << i << " "; + + if (slave.alias) { + lastAlias = slave.alias; + aliasIndex = 0; + } + if (lastAlias) { + cout << setw(10) << "#" << lastAlias << ":" << aliasIndex; + } + + cout << " " << slaveState(slave.state) << " "; + + if (strlen(slave.name)) { + cout << slave.name; + } else { + cout << "0x" << hex << setfill('0') << slave.vendor_id + << ":0x" << slave.product_code; + } + + cout << endl; + } +} + +/****************************************************************************/ + +void Master::listPdos(int slavePosition) +{ + ec_ioctl_slave_t slave; + ec_ioctl_sync_t sync; + ec_ioctl_pdo_t pdo; + ec_ioctl_pdo_entry_t entry; + unsigned int i, j, k; + + getSlave(&slave, slavePosition); + + for (i = 0; i < slave.sync_count; i++) { + getSync(&sync, slavePosition, i); + + cout << "SM" << i << ":" + << " PhysAddr 0x" + << hex << setfill('0') << setw(4) << sync.physical_start_address + << ", DefaultSize " + << dec << setfill(' ') << setw(4) << sync.default_size + << ", ControlRegister 0x" + << hex << setfill('0') << setw(2) + << (unsigned int) sync.control_register + << ", Enable " << dec << (unsigned int) sync.enable + << endl; + + for (j = 0; j < sync.pdo_count; j++) { + getPdo(&pdo, slavePosition, i, j); + + cout << " " << (pdo.dir ? "T" : "R") << "xPdo 0x" + << hex << setfill('0') << setw(4) << pdo.index + << " \"" << pdo.name << "\"" << endl; + + for (k = 0; k < pdo.entry_count; k++) { + getPdoEntry(&entry, slavePosition, i, j, k); + + cout << " Pdo entry 0x" + << hex << setfill('0') << setw(4) << entry.index + << ":" << hex << setfill('0') << setw(2) + << (unsigned int) entry.subindex + << ", " << dec << (unsigned int) entry.bit_length + << " bit, \"" << entry.name << "\"" << endl; + } + } + } +} + +/****************************************************************************/ + unsigned int Master::slaveCount() { - unsigned int numSlaves; + int ret; - if (ioctl(fd, EC_IOCTL_SLAVE_COUNT, &numSlaves)) { + if ((ret = ioctl(fd, EC_IOCTL_SLAVE_COUNT, 0)) < 0) { stringstream err; - err << "Failed to get number of slaves: " << strerror(errno); + err << "Failed to get slave: " << strerror(errno); throw MasterException(err.str()); } - return numSlaves; + return ret; } /****************************************************************************/ -void Master::listSlaves() +void Master::getSlave(ec_ioctl_slave_t *slave, uint16_t slaveIndex) { - unsigned int numSlaves = slaveCount(), i; - struct ec_ioctl_slave_info *infos, *info; - uint16_t lastAlias, aliasIndex; - - if (!numSlaves) - return; - - infos = new struct ec_ioctl_slave_info[numSlaves]; + slave->position = slaveIndex; - if (ioctl(fd, EC_IOCTL_SLAVE_INFO, infos)) { + if (ioctl(fd, EC_IOCTL_SLAVE, slave)) { stringstream err; - err << "Failed to get slave information: " << strerror(errno); + err << "Failed to get slave: "; + if (errno == EINVAL) + err << "Slave " << slaveIndex << " does not exist!"; + else + err << strerror(errno); throw MasterException(err.str()); } +} - lastAlias = 0; - aliasIndex = 0; - for (i = 0; i < numSlaves; i++) { - info = &infos[i]; - cout << setw(2) << info->ring_position << " "; +/****************************************************************************/ - if (info->alias) { - lastAlias = info->alias; - aliasIndex = 0; - } - if (lastAlias) { - cout << setw(10) << "#" << lastAlias << ":" << aliasIndex; - } +void Master::getSync( + ec_ioctl_sync_t *sync, + uint16_t slaveIndex, + uint8_t syncIndex + ) +{ + sync->slave_position = slaveIndex; + sync->sync_index = syncIndex; + + if (ioctl(fd, EC_IOCTL_SYNC, sync)) { + stringstream err; + err << "Failed to get sync manager: "; + if (errno == EINVAL) + err << "Either slave " << slaveIndex << " does not exist, " + << "or contains less than " << (unsigned int) syncIndex + 1 + << " sync managers!"; + else + err << strerror(errno); + throw MasterException(err.str()); + } +} - cout << " " << slaveState(info->state) << " "; +/****************************************************************************/ - if (strlen(info->description)) { - cout << info->description; - } else { - cout << "0x" << hex << setfill('0') << info->vendor_id - << ":0x" << info->product_code; - } +void Master::getPdo( + ec_ioctl_pdo_t *pdo, + uint16_t slaveIndex, + uint8_t syncIndex, + uint8_t pdoPos + ) +{ + pdo->slave_position = slaveIndex; + pdo->sync_index = syncIndex; + pdo->pdo_pos = pdoPos; - cout << endl; + if (ioctl(fd, EC_IOCTL_PDO, pdo)) { + stringstream err; + err << "Failed to get Pdo: "; + if (errno == EINVAL) + err << "Either slave " << slaveIndex << " does not exist, " + << "or contains less than " << (unsigned int) syncIndex + 1 + << " sync managers, or sync manager " + << (unsigned int) syncIndex << " contains less than " + << pdoPos + 1 << " Pdos!" << endl; + else + err << strerror(errno); + throw MasterException(err.str()); } +} - delete [] infos; +/****************************************************************************/ + +void Master::getPdoEntry( + ec_ioctl_pdo_entry_t *entry, + uint16_t slaveIndex, + uint8_t syncIndex, + uint8_t pdoPos, + uint8_t entryPos + ) +{ + entry->slave_position = slaveIndex; + entry->sync_index = syncIndex; + entry->pdo_pos = pdoPos; + entry->entry_pos = entryPos; + + if (ioctl(fd, EC_IOCTL_PDO_ENTRY, entry)) { + stringstream err; + err << "Failed to get Pdo entry: "; + if (errno == EINVAL) + err << "Either slave " << slaveIndex << " does not exist, " + << "or contains less than " << (unsigned int) syncIndex + 1 + << " sync managers, or sync manager " + << (unsigned int) syncIndex << " contains less than " + << pdoPos + 1 << " Pdos, or the Pdo at position " << pdoPos + << " contains less than " << (unsigned int) entryPos + 1 + << " entries!" << endl; + else + err << strerror(errno); + throw MasterException(err.str()); + } } /****************************************************************************/ -string Master::slaveState(uint8_t state) const +string Master::slaveState(uint8_t state) { switch (state) { case 1: return "INIT"; diff --git a/tools/Master.h b/tools/Master.h index 0fe306b7..f96f5c21 100644 --- a/tools/Master.h +++ b/tools/Master.h @@ -10,6 +10,8 @@ #include <stdexcept> using namespace std; +#include "../master/ioctl.h" + /****************************************************************************/ class MasterException: @@ -38,11 +40,19 @@ class Master void open(unsigned int); void close(); - unsigned int slaveCount(); void listSlaves(); + void listPdos(int); protected: - string slaveState(uint8_t) const; + unsigned int slaveCount(); + void slaveSyncs(uint16_t); + void getSlave(ec_ioctl_slave_t *, uint16_t); + void getSync(ec_ioctl_sync_t *, uint16_t, uint8_t); + void getPdo(ec_ioctl_pdo_t *, uint16_t, uint8_t, uint8_t); + void getPdoEntry(ec_ioctl_pdo_entry_t *, uint16_t, uint8_t, uint8_t, + uint8_t); + + static string slaveState(uint8_t); private: unsigned int index; diff --git a/tools/main.cpp b/tools/main.cpp index 0a521496..6e32e5ca 100644 --- a/tools/main.cpp +++ b/tools/main.cpp @@ -19,7 +19,7 @@ using namespace std; #define DEFAULT_SLAVESPEC "" static unsigned int masterIndex = DEFAULT_MASTER; -static string slaveSpec = DEFAULT_SLAVESPEC; +static int slavePosition = -1; static string command = DEFAULT_COMMAND; /*****************************************************************************/ @@ -30,10 +30,11 @@ void printUsage() << "Usage: ethercat <COMMAND> [OPTIONS]" << endl << "Commands:" << endl << " list (ls, slaves) List all slaves (former 'lsec')." << endl + << " pdos List Pdo mapping of given slaves." << endl << "Global options:" << endl << " --master -m <master> Index of the master to use. Default: " << DEFAULT_MASTER << endl - << " --slave -s <slave> Slave specification. Default: All " + << " --slave -s <slave> Numerical ring position. Default: All " "slaves." << endl << " --help -h Show this help." << endl; } @@ -68,7 +69,14 @@ void getOptions(int argc, char **argv) break; case 's': - slaveSpec = optarg; + number = strtoul(optarg, &remainder, 0); + if (remainder == optarg || *remainder + || number < 0 || number > 0xFFFF) { + cerr << "Invalid slave position " << optarg << "!" << endl; + printUsage(); + exit(1); + } + slavePosition = number; break; case 'h': @@ -101,13 +109,21 @@ int main(int argc, char **argv) getOptions(argc, argv); - master.open(masterIndex); + try { + master.open(masterIndex); + + if (command == "list" || command == "ls" || command == "slaves") { + master.listSlaves(); - if (command == "list" || command == "ls" || command == "slaves") { - master.listSlaves(); - } else { - cerr << "Unknown command " << command << "!" << endl; - printUsage(); + } else if (command == "pdos") { + master.listPdos(slavePosition); + } else { + cerr << "Unknown command " << command << "!" << endl; + printUsage(); + exit(1); + } + } catch (MasterException &e) { + cerr << e.what() << endl; exit(1); } -- GitLab