Implemented SII writing (including alias writing) via ethercat command.
This commit is contained in:
parent
ee57578c05
commit
6249f1dd91
2
TODO
2
TODO
|
|
@ -9,7 +9,6 @@ $Id$
|
|||
Version 1.4.0:
|
||||
|
||||
* Replace all Sysfs files via the new ethercat tool.
|
||||
- Slave alias write
|
||||
- Slave info (flags, mailbox, general)
|
||||
- Config info (alias, position, type, Pdos, Sdos)
|
||||
* Slaves as array.
|
||||
|
|
@ -26,6 +25,7 @@ Version 1.4.0:
|
|||
* Check for sizes of uploaded Sdos when reading mapping from CoE.
|
||||
* Attach Pdo names from SII or Coe dictioary to Pdos read via CoE.
|
||||
* Make scanning and configuration run parallel (each).
|
||||
* List of commands that require a slave.
|
||||
|
||||
Future issues:
|
||||
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
|
||||
case EC_IOCTL_SII_READ:
|
||||
{
|
||||
ec_ioctl_sii_read_t data;
|
||||
ec_ioctl_sii_t data;
|
||||
const ec_slave_t *slave;
|
||||
|
||||
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
|
||||
|
|
@ -795,6 +795,54 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
}
|
||||
|
||||
case EC_IOCTL_SII_WRITE:
|
||||
{
|
||||
ec_ioctl_sii_t data;
|
||||
ec_slave_t *slave;
|
||||
unsigned int byte_size;
|
||||
uint16_t *words;
|
||||
|
||||
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.nwords)
|
||||
break;
|
||||
|
||||
byte_size = sizeof(uint16_t) * data.nwords;
|
||||
if (!(words = kmalloc(byte_size, GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate %u bytes for SII contents.\n",
|
||||
byte_size);
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_from_user(words,
|
||||
(void __user *) data.words, byte_size)) {
|
||||
retval = -EFAULT;
|
||||
kfree(words);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ec_slave_write_sii(slave,
|
||||
data.offset, data.nwords, words)) {
|
||||
retval = -EIO;
|
||||
kfree(words);
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(words);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
retval = -ENOTTY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@
|
|||
#define EC_IOCTL_SDO_ENTRY EC_IOWR(0x0c, ec_ioctl_sdo_entry_t)
|
||||
#define EC_IOCTL_SDO_UPLOAD EC_IOWR(0x0d, ec_ioctl_sdo_upload_t)
|
||||
#define EC_IOCTL_SDO_DOWNLOAD EC_IOW(0x0e, ec_ioctl_sdo_download_t)
|
||||
#define EC_IOCTL_SII_READ EC_IOWR(0x0f, ec_ioctl_sii_read_t)
|
||||
#define EC_IOCTL_SII_READ EC_IOWR(0x0f, ec_ioctl_sii_t)
|
||||
#define EC_IOCTL_SII_WRITE EC_IOW(0x10, ec_ioctl_sii_t)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -264,7 +265,7 @@ typedef struct {
|
|||
uint16_t offset;
|
||||
uint32_t nwords;
|
||||
uint16_t *words;
|
||||
} ec_ioctl_sii_read_t;
|
||||
} ec_ioctl_sii_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
259
master/slave.c
259
master/slave.c
|
|
@ -57,8 +57,6 @@ extern const ec_code_msg_t al_status_messages[];
|
|||
void ec_slave_clear(struct kobject *);
|
||||
void ec_slave_sdos_clear(struct kobject *);
|
||||
ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *);
|
||||
ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *,
|
||||
const char *, size_t);
|
||||
char *ec_slave_sii_string(ec_slave_t *, unsigned int);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -66,19 +64,14 @@ char *ec_slave_sii_string(ec_slave_t *, unsigned int);
|
|||
/** \cond */
|
||||
|
||||
EC_SYSFS_READ_ATTR(info);
|
||||
EC_SYSFS_READ_WRITE_ATTR(sii);
|
||||
EC_SYSFS_READ_WRITE_ATTR(alias);
|
||||
|
||||
static struct attribute *def_attrs[] = {
|
||||
&attr_info,
|
||||
&attr_sii,
|
||||
&attr_alias,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct sysfs_ops sysfs_ops = {
|
||||
.show = ec_show_slave_attribute,
|
||||
.store = ec_store_slave_attribute
|
||||
};
|
||||
|
||||
static struct kobj_type ktype_ec_slave = {
|
||||
|
|
@ -848,30 +841,40 @@ ssize_t ec_slave_info(const ec_slave_t *slave, /**< EtherCAT slave */
|
|||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Schedules an SII write request.
|
||||
* \return 0 case of success, otherwise error code.
|
||||
* Writes SII contents to a slave.
|
||||
* \return Zero on success, otherwise error code.
|
||||
*/
|
||||
|
||||
int ec_slave_schedule_sii_writing(
|
||||
ec_sii_write_request_t *request /**< SII write request */
|
||||
int ec_slave_write_sii(
|
||||
ec_slave_t *slave, /**< EtherCAT slave */
|
||||
uint16_t offset, /**< SII word offset. */
|
||||
unsigned int nwords, /**< Number of words. */
|
||||
const uint16_t *words /**< New SII data. */
|
||||
)
|
||||
{
|
||||
ec_master_t *master = request->slave->master;
|
||||
ec_master_t *master = slave->master;
|
||||
ec_sii_write_request_t request;
|
||||
|
||||
request->state = EC_REQUEST_QUEUED;
|
||||
// init SII write request
|
||||
INIT_LIST_HEAD(&request.list);
|
||||
request.slave = slave;
|
||||
request.words = words;
|
||||
request.offset = offset;
|
||||
request.nwords = nwords;
|
||||
request.state = EC_REQUEST_QUEUED;
|
||||
|
||||
// schedule SII write request.
|
||||
down(&master->sii_sem);
|
||||
list_add_tail(&request->list, &master->sii_requests);
|
||||
list_add_tail(&request.list, &master->sii_requests);
|
||||
up(&master->sii_sem);
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->sii_queue,
|
||||
request->state != EC_REQUEST_QUEUED)) {
|
||||
request.state != EC_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->sii_sem);
|
||||
if (request->state == EC_REQUEST_QUEUED) {
|
||||
list_del(&request->list);
|
||||
if (request.state == EC_REQUEST_QUEUED) {
|
||||
list_del(&request.list);
|
||||
up(&master->sii_sem);
|
||||
return -EINTR;
|
||||
}
|
||||
|
|
@ -881,184 +884,16 @@ int ec_slave_schedule_sii_writing(
|
|||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->sii_queue,
|
||||
request->state != EC_REQUEST_BUSY);
|
||||
request.state != EC_REQUEST_BUSY);
|
||||
|
||||
return request->state == EC_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Calculates the SII checksum field.
|
||||
*
|
||||
* The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
|
||||
* initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
|
||||
*
|
||||
* The below code was originally generated with PYCRC
|
||||
* http://www.tty1.net/pycrc
|
||||
*
|
||||
* ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
|
||||
* --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
|
||||
*
|
||||
* \return CRC8
|
||||
*/
|
||||
|
||||
uint8_t ec_slave_sii_crc(
|
||||
const uint8_t *data, /**< pointer to data */
|
||||
size_t length /**< number of bytes in \a data */
|
||||
)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t bit, byte, crc = 0x48;
|
||||
|
||||
while (length--) {
|
||||
byte = *data++;
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = crc & 0x80;
|
||||
crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
|
||||
if (bit) crc ^= 0x07;
|
||||
if (request.state == EC_REQUEST_SUCCESS) {
|
||||
if (offset <= 4 && offset + nwords > 4) { // alias was written
|
||||
slave->sii.alias = EC_READ_U16(words + 4);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = crc & 0x80;
|
||||
crc <<= 1;
|
||||
if (bit) crc ^= 0x07;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Writes complete SII contents to a slave.
|
||||
* \return data size written in case of success, otherwise error code.
|
||||
*/
|
||||
|
||||
ssize_t ec_slave_write_sii(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
const uint8_t *data, /**< new SII data */
|
||||
size_t size /**< size of data in bytes */
|
||||
)
|
||||
{
|
||||
ec_sii_write_request_t request;
|
||||
const uint16_t *cat_header;
|
||||
uint16_t cat_type, cat_size;
|
||||
int ret;
|
||||
uint8_t crc;
|
||||
|
||||
if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
|
||||
EC_ERR("Writing SIIs only allowed in idle mode!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (size % 2) {
|
||||
EC_ERR("SII data size is odd (%u bytes)! SII data must be"
|
||||
" word-aligned. Dropping.\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// init SII write request
|
||||
INIT_LIST_HEAD(&request.list);
|
||||
request.slave = slave;
|
||||
request.words = (const uint16_t *) data;
|
||||
request.offset = 0;
|
||||
request.nwords = size / 2;
|
||||
|
||||
if (request.nwords < 0x0041) {
|
||||
EC_ERR("SII data too short (%u words)! Mimimum is"
|
||||
" 40 fixed words + 1 delimiter. Dropping.\n",
|
||||
request.nwords);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// calculate checksum
|
||||
crc = ec_slave_sii_crc(data, 14); // CRC over words 0 to 6
|
||||
if (crc != data[14]) {
|
||||
EC_WARN("SII CRC incorrect. Must be 0x%02x.\n", crc);
|
||||
}
|
||||
|
||||
cat_header = request.words + EC_FIRST_SII_CATEGORY_OFFSET;
|
||||
cat_type = EC_READ_U16(cat_header);
|
||||
while (cat_type != 0xFFFF) { // cycle through categories
|
||||
if (cat_header + 1 > request.words + request.nwords) {
|
||||
EC_ERR("SII data corrupted! Dropping.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
cat_size = EC_READ_U16(cat_header + 1);
|
||||
if (cat_header + cat_size + 2 > request.words + request.nwords) {
|
||||
EC_ERR("SII data corrupted! Dropping.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
cat_header += cat_size + 2;
|
||||
cat_type = EC_READ_U16(cat_header);
|
||||
}
|
||||
|
||||
// SII data ok. schedule writing.
|
||||
if ((ret = ec_slave_schedule_sii_writing(&request)))
|
||||
return ret; // error code
|
||||
|
||||
return size; // success
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Writes the Secondary slave address (alias) to the slave's SII.
|
||||
* \return data size written in case of success, otherwise error code.
|
||||
*/
|
||||
|
||||
ssize_t ec_slave_write_alias(ec_slave_t *slave, /**< EtherCAT slave */
|
||||
const uint8_t *data, /**< alias string */
|
||||
size_t size /**< size of data in bytes */
|
||||
)
|
||||
{
|
||||
ec_sii_write_request_t request;
|
||||
char *remainder;
|
||||
uint16_t alias;
|
||||
int ret;
|
||||
uint8_t sii_data[16], crc;
|
||||
|
||||
if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
|
||||
EC_ERR("Writing to SII is only allowed in idle mode!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
alias = simple_strtoul(data, &remainder, 0);
|
||||
if (remainder == (char *) data || (*remainder && *remainder != '\n')) {
|
||||
EC_ERR("Invalid alias value! Dropping.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!slave->sii_words || slave->sii_nwords < 8) {
|
||||
EC_ERR("Failed to read SII contents from slave %u.\n",
|
||||
slave->ring_position);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// copy first 7 words of recent SII contents
|
||||
memcpy(sii_data, (uint8_t *) slave->sii_words, 14);
|
||||
|
||||
// write new alias address in word 4
|
||||
EC_WRITE_U16(sii_data + 8, alias);
|
||||
|
||||
// calculate new checksum over words 0 to 6
|
||||
crc = ec_slave_sii_crc(sii_data, 14);
|
||||
EC_WRITE_U16(sii_data + 14, crc);
|
||||
|
||||
// init SII write request
|
||||
INIT_LIST_HEAD(&request.list);
|
||||
request.slave = slave;
|
||||
request.words = (const uint16_t *) sii_data;
|
||||
request.offset = 0x0000;
|
||||
request.nwords = 8;
|
||||
|
||||
if ((ret = ec_slave_schedule_sii_writing(&request)))
|
||||
return ret; // error code
|
||||
|
||||
slave->sii.alias = alias; // FIXME: do this in state machine
|
||||
|
||||
return size; // success
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1074,25 +909,9 @@ ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */
|
|||
)
|
||||
{
|
||||
ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
|
||||
unsigned int sii_size;
|
||||
|
||||
if (attr == &attr_info) {
|
||||
return ec_slave_info(slave, buffer);
|
||||
} else if (attr == &attr_sii) {
|
||||
if (slave->sii_words) {
|
||||
sii_size = slave->sii_nwords * 2;
|
||||
if (sii_size > PAGE_SIZE) {
|
||||
EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
|
||||
slave->ring_position, sii_size,
|
||||
(int) PAGE_SIZE);
|
||||
}
|
||||
else {
|
||||
memcpy(buffer, (uint8_t *) slave->sii_words, sii_size);
|
||||
return sii_size;
|
||||
}
|
||||
}
|
||||
} else if (attr == &attr_alias) {
|
||||
return sprintf(buffer, "%u\n", slave->sii.alias);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1100,30 +919,6 @@ ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
Formats attribute data for SysFS write access.
|
||||
\return number of bytes processed, or negative error code
|
||||
*/
|
||||
|
||||
ssize_t ec_store_slave_attribute(struct kobject *kobj, /**< slave's kobject */
|
||||
struct attribute *attr, /**< attribute */
|
||||
const char *buffer, /**< memory with data */
|
||||
size_t size /**< size of data to store */
|
||||
)
|
||||
{
|
||||
ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
|
||||
|
||||
if (attr == &attr_sii) {
|
||||
return ec_slave_write_sii(slave, buffer, size);
|
||||
} else if (attr == &attr_alias) {
|
||||
return ec_slave_write_alias(slave, buffer, size);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Get the sync manager for either Rx- or Tx-Pdos.
|
||||
*
|
||||
* \todo This seems not to be correct in every case...
|
||||
|
|
|
|||
|
|
@ -228,6 +228,9 @@ const ec_sdo_t *ec_slave_get_sdo_by_pos_const(const ec_slave_t *, uint16_t);
|
|||
uint16_t ec_slave_sdo_count(const ec_slave_t *);
|
||||
const ec_pdo_t *ec_slave_find_pdo(const ec_slave_t *, uint16_t);
|
||||
|
||||
int ec_slave_write_sii(ec_slave_t *, uint16_t, unsigned int,
|
||||
const uint16_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
|
|||
265
tools/Master.cpp
265
tools/Master.cpp
|
|
@ -13,6 +13,7 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <cctype> // toupper()
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -116,6 +117,60 @@ void Master::setIndex(unsigned int i)
|
|||
index = i;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Writes the Secondary slave address (alias) to the slave's SII.
|
||||
*/
|
||||
void Master::writeAlias(
|
||||
int slavePosition,
|
||||
bool force,
|
||||
const vector<string> &commandArgs
|
||||
)
|
||||
{
|
||||
ec_ioctl_sii_t data;
|
||||
ec_ioctl_slave_t slave;
|
||||
unsigned int i;
|
||||
uint16_t alias;
|
||||
stringstream err, strAlias;
|
||||
int number;
|
||||
|
||||
if (commandArgs.size() != 1) {
|
||||
stringstream err;
|
||||
err << "'alias' takes exactly one argument!";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
strAlias << commandArgs[0];
|
||||
strAlias >> hex >> number;
|
||||
if (strAlias.fail() || number < 0x0000 || number > 0xffff) {
|
||||
err << "Invalid alias '" << commandArgs[0] << "'!";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
alias = number;
|
||||
|
||||
if (slavePosition == -1) {
|
||||
unsigned int numSlaves, i;
|
||||
|
||||
if (!force) {
|
||||
err << "This will write the alias addresses of all slaves to 0x"
|
||||
<< hex << setfill('0') << setw(4) << alias << "! "
|
||||
<< "Please specify --force to proceed.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
open(ReadWrite);
|
||||
numSlaves = slaveCount();
|
||||
|
||||
for (i = 0; i < numSlaves; i++) {
|
||||
writeSlaveAlias(i, alias);
|
||||
}
|
||||
} else {
|
||||
open(ReadWrite);
|
||||
writeSlaveAlias(slavePosition, alias);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Master::outputData(int domainIndex)
|
||||
|
|
@ -197,14 +252,17 @@ void Master::listSlaves()
|
|||
aliasIndex = 0;
|
||||
for (i = 0; i < numSlaves; i++) {
|
||||
getSlave(&slave, i);
|
||||
cout << setw(2) << i << " ";
|
||||
cout << setfill(' ') << setw(2) << i << " ";
|
||||
|
||||
if (slave.alias) {
|
||||
lastAlias = slave.alias;
|
||||
aliasIndex = 0;
|
||||
}
|
||||
if (lastAlias) {
|
||||
cout << setw(10) << "#" << lastAlias << ":" << aliasIndex;
|
||||
cout << "#"
|
||||
<< hex << setfill('0') << setw(4) << lastAlias
|
||||
<< ":" << dec << aliasIndex;
|
||||
aliasIndex++;
|
||||
}
|
||||
|
||||
cout << " " << slaveState(slave.state) << " ";
|
||||
|
|
@ -212,8 +270,9 @@ void Master::listSlaves()
|
|||
if (strlen(slave.name)) {
|
||||
cout << slave.name;
|
||||
} else {
|
||||
cout << "0x" << hex << setfill('0') << slave.vendor_id
|
||||
<< ":0x" << slave.product_code;
|
||||
cout << hex << setfill('0')
|
||||
<< setw(8) << slave.vendor_id << ":"
|
||||
<< setw(8) << slave.product_code << dec;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
|
@ -608,7 +667,7 @@ void Master::sdoUpload(
|
|||
|
||||
void Master::siiRead(int slavePosition)
|
||||
{
|
||||
ec_ioctl_sii_read_t data;
|
||||
ec_ioctl_sii_t data;
|
||||
ec_ioctl_slave_t slave;
|
||||
unsigned int i;
|
||||
|
||||
|
|
@ -647,6 +706,102 @@ void Master::siiRead(int slavePosition)
|
|||
|
||||
/****************************************************************************/
|
||||
|
||||
void Master::siiWrite(
|
||||
int slavePosition,
|
||||
bool force,
|
||||
const vector<string> &commandArgs
|
||||
)
|
||||
{
|
||||
stringstream err;
|
||||
ec_ioctl_sii_t data;
|
||||
ifstream file;
|
||||
unsigned int byte_size;
|
||||
const uint16_t *categoryHeader;
|
||||
uint16_t categoryType, categorySize;
|
||||
uint8_t crc;
|
||||
|
||||
if (slavePosition < 0) {
|
||||
err << "'sii_write' requires a slave! Please specify --slave.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
data.slave_position = slavePosition;
|
||||
|
||||
if (commandArgs.size() != 1) {
|
||||
err << "'ssi_write' takes exactly one argument!";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
file.open(commandArgs[0].c_str(), ifstream::in | ifstream::binary);
|
||||
if (file.fail()) {
|
||||
err << "Failed to open '" << commandArgs[0] << "'!";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
// get length of file
|
||||
file.seekg(0, ios::end);
|
||||
byte_size = file.tellg();
|
||||
file.seekg(0, ios::beg);
|
||||
|
||||
if (!byte_size || byte_size % 2) {
|
||||
stringstream err;
|
||||
err << "Invalid file size! Must be non-zero and even.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
data.nwords = byte_size / 2;
|
||||
if (data.nwords < 0x0041 && !force) {
|
||||
err << "SII data too short (" << data.nwords << " words)! Mimimum is"
|
||||
" 40 fixed words + 1 delimiter. Use --force to write anyway.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
// allocate buffer and read file into buffer
|
||||
data.words = new uint16_t[data.nwords];
|
||||
file.read((char *) data.words, byte_size);
|
||||
file.close();
|
||||
|
||||
if (!force) {
|
||||
// calculate checksum over words 0 to 6
|
||||
crc = calcSiiCrc((const uint8_t *) data.words, 14);
|
||||
if (crc != ((const uint8_t *) data.words)[14]) {
|
||||
err << "CRC incorrect. Must be 0x"
|
||||
<< hex << setfill('0') << setw(2) << (unsigned int) crc
|
||||
<< ". Use --force to write anyway.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
// cycle through categories to detect corruption
|
||||
categoryHeader = data.words + 0x0040;
|
||||
categoryType = le16tocpu(*categoryHeader);
|
||||
while (categoryType != 0xffff) {
|
||||
if (categoryHeader + 1 > data.words + data.nwords) {
|
||||
err << "SII data seem to be corrupted! "
|
||||
<< "Use --force to write anyway.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
categorySize = le16tocpu(*(categoryHeader + 1));
|
||||
if (categoryHeader + categorySize + 2 > data.words + data.nwords) {
|
||||
err << "SII data seem to be corrupted! "
|
||||
"Use --force to write anyway.";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
categoryHeader += categorySize + 2;
|
||||
categoryType = le16tocpu(*categoryHeader);
|
||||
}
|
||||
}
|
||||
|
||||
// send data to master
|
||||
open(ReadWrite);
|
||||
data.offset = 0;
|
||||
if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) {
|
||||
stringstream err;
|
||||
err << "Failed to write SII: " << strerror(errno);
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Master::requestStates(
|
||||
int slavePosition,
|
||||
const vector<string> &commandArgs
|
||||
|
|
@ -744,6 +899,62 @@ void Master::close()
|
|||
::close(fd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Writes the Secondary slave address (alias) to the slave's SII.
|
||||
*/
|
||||
void Master::writeSlaveAlias(
|
||||
uint16_t slavePosition,
|
||||
uint16_t alias
|
||||
)
|
||||
{
|
||||
ec_ioctl_sii_t data;
|
||||
ec_ioctl_slave_t slave;
|
||||
stringstream err;
|
||||
uint8_t crc;
|
||||
|
||||
open(ReadWrite);
|
||||
|
||||
getSlave(&slave, slavePosition);
|
||||
|
||||
if (slave.sii_nwords < 8) {
|
||||
err << "Current SII contents are too small to set an alias "
|
||||
<< "(" << slave.sii_nwords << " words)!";
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
data.slave_position = slavePosition;
|
||||
data.offset = 0;
|
||||
data.nwords = 8;
|
||||
data.words = new uint16_t[data.nwords];
|
||||
|
||||
// read first 8 SII words
|
||||
if (ioctl(fd, EC_IOCTL_SII_READ, &data) < 0) {
|
||||
delete [] data.words;
|
||||
err << "Failed to read SII: " << strerror(errno);
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
// write new alias address in word 4
|
||||
data.words[4] = cputole16(alias);
|
||||
|
||||
// calculate checksum over words 0 to 6
|
||||
crc = calcSiiCrc((const uint8_t *) data.words, 14);
|
||||
|
||||
// write new checksum into first byte of word 7
|
||||
*(uint8_t *) (data.words + 7) = crc;
|
||||
|
||||
// write first 8 words with new alias and checksum
|
||||
if (ioctl(fd, EC_IOCTL_SII_WRITE, &data) < 0) {
|
||||
delete [] data.words;
|
||||
err << "Failed to write SII: " << strerror(errno);
|
||||
throw MasterException(err.str());
|
||||
}
|
||||
|
||||
delete [] data.words;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Master::outputDomainData(unsigned int domainIndex)
|
||||
|
|
@ -1330,4 +1541,46 @@ void Master::printRawData(
|
|||
cout << endl;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Calculates the SII checksum field.
|
||||
*
|
||||
* The checksum is generated with the polynom x^8+x^2+x+1 (0x07) and an
|
||||
* initial value of 0xff (see IEC 61158-6-12 ch. 5.4).
|
||||
*
|
||||
* The below code was originally generated with PYCRC
|
||||
* http://www.tty1.net/pycrc
|
||||
*
|
||||
* ./pycrc.py --width=8 --poly=0x07 --reflect-in=0 --xor-in=0xff
|
||||
* --reflect-out=0 --xor-out=0 --generate c --algorithm=bit-by-bit
|
||||
*
|
||||
* \return CRC8
|
||||
*/
|
||||
uint8_t Master::calcSiiCrc(
|
||||
const uint8_t *data, /**< pointer to data */
|
||||
size_t length /**< number of bytes in \a data */
|
||||
)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t bit, byte, crc = 0x48;
|
||||
|
||||
while (length--) {
|
||||
byte = *data++;
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = crc & 0x80;
|
||||
crc = (crc << 1) | ((byte >> (7 - i)) & 0x01);
|
||||
if (bit) crc ^= 0x07;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = crc & 0x80;
|
||||
crc <<= 1;
|
||||
if (bit) crc ^= 0x07;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class Master
|
|||
|
||||
void setIndex(unsigned int);
|
||||
|
||||
void writeAlias(int, bool, const vector<string> &);
|
||||
void outputData(int);
|
||||
void setDebug(const vector<string> &);
|
||||
void showDomains(int);
|
||||
|
|
@ -51,6 +52,7 @@ class Master
|
|||
void sdoDownload(int, const string &, const vector<string> &);
|
||||
void sdoUpload(int, const string &, const vector<string> &);
|
||||
void siiRead(int);
|
||||
void siiWrite(int, bool, const vector<string> &);
|
||||
void requestStates(int, const vector<string> &);
|
||||
void generateXml(int);
|
||||
|
||||
|
|
@ -59,6 +61,7 @@ class Master
|
|||
void open(Permissions);
|
||||
void close();
|
||||
|
||||
void writeSlaveAlias(uint16_t, uint16_t);
|
||||
void outputDomainData(unsigned int);
|
||||
void showDomain(unsigned int);
|
||||
void listSlavePdos(uint16_t, bool = false, bool = false);
|
||||
|
|
@ -83,6 +86,7 @@ class Master
|
|||
|
||||
static string slaveState(uint8_t);
|
||||
static void printRawData(const uint8_t *, unsigned int);
|
||||
static uint8_t calcSiiCrc(const uint8_t *, unsigned int);
|
||||
|
||||
private:
|
||||
enum {DefaultBufferSize = 1024};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ static string command;
|
|||
vector<string> commandArgs;
|
||||
static bool quiet = false;
|
||||
string dataTypeStr;
|
||||
bool force = false;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ void printUsage()
|
|||
cerr
|
||||
<< "Usage: ethercat <COMMAND> [OPTIONS]" << endl
|
||||
<< "Commands:" << endl
|
||||
<< " alias Write alias address(es)." << endl
|
||||
<< " data Output binary domain process data." << endl
|
||||
<< " debug Set the master debug level." << endl
|
||||
<< " domain Show domain information." << endl
|
||||
|
|
@ -42,6 +44,7 @@ void printUsage()
|
|||
<< " sdo_download (sd) Write an Sdo entry." << endl
|
||||
<< " sdo_upload (su) Read an Sdo entry." << endl
|
||||
<< " sii_read (sr) Output a slave's SII contents." << endl
|
||||
<< " sii_write (sw) Write slave's SII contents." << endl
|
||||
<< " state Request slave states." << endl
|
||||
<< " xml Generate slave information xmls." << endl
|
||||
<< "Global options:" << endl
|
||||
|
|
@ -56,6 +59,7 @@ void printUsage()
|
|||
<< " or 'all' for all domains (default)."
|
||||
<< endl
|
||||
<< " --type -t <type> Forced Sdo data type." << endl
|
||||
<< " --force -f Force action." << endl
|
||||
<< " --quiet -q Show less output." << endl
|
||||
<< " --help -h Show this help." << endl;
|
||||
}
|
||||
|
|
@ -73,13 +77,14 @@ void getOptions(int argc, char **argv)
|
|||
{"slave", required_argument, NULL, 's'},
|
||||
{"domain", required_argument, NULL, 'd'},
|
||||
{"type", required_argument, NULL, 't'},
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{}
|
||||
};
|
||||
|
||||
do {
|
||||
c = getopt_long(argc, argv, "m:s:d:t:qh", longOptions, &optionIndex);
|
||||
c = getopt_long(argc, argv, "m:s:d:t:fqh", longOptions, &optionIndex);
|
||||
|
||||
switch (c) {
|
||||
case 'm':
|
||||
|
|
@ -127,6 +132,10 @@ void getOptions(int argc, char **argv)
|
|||
dataTypeStr = optarg;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
|
|
@ -166,7 +175,9 @@ int main(int argc, char **argv)
|
|||
try {
|
||||
master.setIndex(masterIndex);
|
||||
|
||||
if (command == "data") {
|
||||
if (command == "alias") {
|
||||
master.writeAlias(slavePosition, force, commandArgs);
|
||||
} else if (command == "data") {
|
||||
master.outputData(domainIndex);
|
||||
} else if (command == "debug") {
|
||||
master.setDebug(commandArgs);
|
||||
|
|
@ -186,6 +197,8 @@ int main(int argc, char **argv)
|
|||
master.sdoUpload(slavePosition, dataTypeStr, commandArgs);
|
||||
} else if (command == "sii_read" || command == "sr") {
|
||||
master.siiRead(slavePosition);
|
||||
} else if (command == "sii_write" || command == "sw") {
|
||||
master.siiWrite(slavePosition, force, commandArgs);
|
||||
} else if (command == "state") {
|
||||
master.requestStates(slavePosition, commandArgs);
|
||||
} else if (command == "xml") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue