# HG changeset patch # User Florian Pose # Date 1212403891 0 # Node ID b954e9d91ea5132123a04d55086a5c80f7f9e7b2 # Parent 96241b092fac5bc3e4099901555f3e95de3559d9 Added 'pdos' command to ethercat tool. diff -r 96241b092fac -r b954e9d91ea5 master/cdev.c --- a/master/cdev.c Mon Jun 02 10:49:44 2008 +0000 +++ b/master/cdev.c Mon Jun 02 10:51:31 2008 +0000 @@ -52,15 +52,15 @@ 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 @@ 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_release(struct inode *inode, struct file *filp) { - //ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); - - EC_DBG("File closed.\n"); + ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; + ec_master_t *master = cdev->master; + + 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) -{ - ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); +long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + 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 -r 96241b092fac -r b954e9d91ea5 master/ioctl.h --- a/master/ioctl.h Mon Jun 02 10:49:44 2008 +0000 +++ b/master/ioctl.h Mon Jun 02 10:51:31 2008 +0000 @@ -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 -r 96241b092fac -r b954e9d91ea5 tools/Master.cpp --- a/tools/Master.cpp Mon Jun 02 10:49:44 2008 +0000 +++ b/tools/Master.cpp Mon Jun 02 10:51:31 2008 +0000 @@ -16,7 +16,6 @@ using namespace std; #include "Master.h" -#include "../master/ioctl.h" /****************************************************************************/ @@ -63,70 +62,205 @@ /****************************************************************************/ -unsigned int Master::slaveCount() -{ - unsigned int numSlaves; - - if (ioctl(fd, EC_IOCTL_SLAVE_COUNT, &numSlaves)) { - stringstream err; - err << "Failed to get number of slaves: " << strerror(errno); - throw MasterException(err.str()); - } - - return numSlaves; -} - -/****************************************************************************/ - void Master::listSlaves() { unsigned int numSlaves = slaveCount(), i; - struct ec_ioctl_slave_info *infos, *info; + ec_ioctl_slave_t slave; uint16_t lastAlias, aliasIndex; - if (!numSlaves) - return; - - infos = new struct ec_ioctl_slave_info[numSlaves]; - - if (ioctl(fd, EC_IOCTL_SLAVE_INFO, infos)) { - stringstream err; - err << "Failed to get slave information: " << 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; + getSlave(&slave, i); + cout << setw(2) << i << " "; + + if (slave.alias) { + lastAlias = slave.alias; aliasIndex = 0; } if (lastAlias) { cout << setw(10) << "#" << lastAlias << ":" << aliasIndex; } - cout << " " << slaveState(info->state) << " "; - - if (strlen(info->description)) { - cout << info->description; + cout << " " << slaveState(slave.state) << " "; + + if (strlen(slave.name)) { + cout << slave.name; } else { - cout << "0x" << hex << setfill('0') << info->vendor_id - << ":0x" << info->product_code; + cout << "0x" << hex << setfill('0') << slave.vendor_id + << ":0x" << slave.product_code; } cout << endl; } - - delete [] infos; -} - -/****************************************************************************/ - -string Master::slaveState(uint8_t state) const +} + +/****************************************************************************/ + +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() +{ + int ret; + + if ((ret = ioctl(fd, EC_IOCTL_SLAVE_COUNT, 0)) < 0) { + stringstream err; + err << "Failed to get slave: " << strerror(errno); + throw MasterException(err.str()); + } + + return ret; +} + +/****************************************************************************/ + +void Master::getSlave(ec_ioctl_slave_t *slave, uint16_t slaveIndex) +{ + slave->position = slaveIndex; + + if (ioctl(fd, EC_IOCTL_SLAVE, slave)) { + stringstream err; + err << "Failed to get slave: "; + if (errno == EINVAL) + err << "Slave " << slaveIndex << " does not exist!"; + else + err << strerror(errno); + throw MasterException(err.str()); + } +} + +/****************************************************************************/ + +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()); + } +} + +/****************************************************************************/ + +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; + + 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()); + } +} + +/****************************************************************************/ + +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) { switch (state) { case 1: return "INIT"; diff -r 96241b092fac -r b954e9d91ea5 tools/Master.h --- a/tools/Master.h Mon Jun 02 10:49:44 2008 +0000 +++ b/tools/Master.h Mon Jun 02 10:51:31 2008 +0000 @@ -10,6 +10,8 @@ #include using namespace std; +#include "../master/ioctl.h" + /****************************************************************************/ class MasterException: @@ -38,11 +40,19 @@ 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 -r 96241b092fac -r b954e9d91ea5 tools/main.cpp --- a/tools/main.cpp Mon Jun 02 10:49:44 2008 +0000 +++ b/tools/main.cpp Mon Jun 02 10:51:31 2008 +0000 @@ -19,7 +19,7 @@ #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 @@ << "Usage: ethercat [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 Index of the master to use. Default: " << DEFAULT_MASTER << endl - << " --slave -s Slave specification. Default: All " + << " --slave -s Numerical ring position. Default: All " "slaves." << endl << " --help -h Show this help." << endl; } @@ -68,7 +69,14 @@ 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 @@ getOptions(argc, argv); - master.open(masterIndex); + try { + master.open(masterIndex); - if (command == "list" || command == "ls" || command == "slaves") { - master.listSlaves(); - } else { - cerr << "Unknown command " << command << "!" << endl; - printUsage(); + if (command == "list" || command == "ls" || command == "slaves") { + master.listSlaves(); + + } 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); }