Added ecrt_master_sdo_download_complete() for ad-hoc downloading SDOs (also

via the command-line tool).
This commit is contained in:
Florian Pose 2011-10-24 10:49:27 +02:00
parent 0f875c88cf
commit 7555b87512
6 changed files with 219 additions and 26 deletions

View File

@ -64,8 +64,9 @@
* ecrt_master_get_slave(), ecrt_master_get_sync_manager(),
* ecrt_master_get_pdo() and ecrt_master_get_pdo_entry()) to get information
* about the currently connected slaves and the PDO entries provided.
* - Added ecrt_master_sdo_download() and ecrt_master_sdo_upload()
* methods to let an application transfer SDOs before activating the master.
* - Added ecrt_master_sdo_download(), ecrt_master_sdo_download_complete() and
* ecrt_master_sdo_upload() methods to let an application transfer SDOs
* before activating the master.
* - Changed the meaning of the negative return values of
* ecrt_slave_config_reg_pdo_entry() and ecrt_slave_config_sdo*().
* - Implemented the Vendor-specific over EtherCAT mailbox protocol. See
@ -656,6 +657,25 @@ int ecrt_master_sdo_download(
uint32_t *abort_code /**< Abort code of the SDO download. */
);
/** Executes an SDO download request to write data to a slave via complete
* access.
*
* This request is processed by the master state machine. This method blocks,
* until the request has been processed and may not be called in realtime
* context.
*
* \retval 0 Success.
* \retval <0 Error code.
*/
int ecrt_master_sdo_download_complete(
ec_master_t *master, /**< EtherCAT master. */
uint16_t slave_position, /**< Slave position. */
uint16_t index, /**< Index of the SDO. */
uint8_t *data, /**< Data buffer to download. */
size_t data_size, /**< Size of the data buffer. */
uint32_t *abort_code /**< Abort code of the SDO download. */
);
/** Executes an SDO upload request to read data from a slave.
*
* This request is processed by the master state machine. This method blocks,

View File

@ -340,6 +340,34 @@ int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
download.slave_position = slave_position;
download.sdo_index = index;
download.sdo_entry_subindex = subindex;
download.complete_access = 0;
download.data_size = data_size;
download.data = data;
if (ioctl(master->fd, EC_IOCTL_SLAVE_SDO_DOWNLOAD, &download) == -1) {
if (errno == EIO && abort_code) {
*abort_code = download.abort_code;
}
fprintf(stderr, "Failed to execute SDO download: %s\n",
strerror(errno));
return -1;
}
return 0;
}
/*****************************************************************************/
int ecrt_master_sdo_download_complete(ec_master_t *master,
uint16_t slave_position, uint16_t index, uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_ioctl_slave_sdo_download_t download;
download.slave_position = slave_position;
download.sdo_index = index;
download.sdo_entry_subindex = 0;
download.complete_access = 1;
download.data_size = data_size;
download.data = data;

View File

@ -900,9 +900,14 @@ int ec_cdev_ioctl_slave_sdo_download(
return -EFAULT;
}
retval = ecrt_master_sdo_download(master, data.slave_position,
data.sdo_index, data.sdo_entry_subindex, sdo_data, data.data_size,
&data.abort_code);
if (data.complete_access) {
retval = ecrt_master_sdo_download_complete(master, data.slave_position,
data.sdo_index, sdo_data, data.data_size, &data.abort_code);
} else {
retval = ecrt_master_sdo_download(master, data.slave_position,
data.sdo_index, data.sdo_entry_subindex, sdo_data,
data.data_size, &data.abort_code);
}
kfree(sdo_data);

View File

@ -56,7 +56,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 11
#define EC_IOCTL_VERSION_MAGIC 12
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@ -368,6 +368,7 @@ typedef struct {
uint16_t slave_position;
uint16_t sdo_index;
uint8_t sdo_entry_subindex;
uint8_t complete_access;
uint32_t data_size;
uint8_t *data;

View File

@ -2446,6 +2446,88 @@ int ecrt_master_sdo_download(ec_master_t *master, uint16_t slave_position,
/*****************************************************************************/
int ecrt_master_sdo_download_complete(ec_master_t *master,
uint16_t slave_position, uint16_t index, uint8_t *data,
size_t data_size, uint32_t *abort_code)
{
ec_master_sdo_request_t request;
EC_MASTER_DBG(master, 1, "%s(master = 0x%p,"
" slave_position = %u, index = 0x%04X,"
" data = 0x%p, data_size = %zu, abort_code = 0x%p)\n",
__func__, master, slave_position, index, data, data_size,
abort_code);
if (!data_size) {
EC_MASTER_ERR(master, "Zero data size!\n");
return -EINVAL;
}
ec_sdo_request_init(&request.req);
ec_sdo_request_address(&request.req, index, 0);
if (ec_sdo_request_alloc(&request.req, data_size)) {
ec_sdo_request_clear(&request.req);
return -ENOMEM;
}
request.req.complete_access = 1;
memcpy(request.req.data, data, data_size);
request.req.data_size = data_size;
ecrt_sdo_request_write(&request.req);
if (down_interruptible(&master->master_sem))
return -EINTR;
if (!(request.slave = ec_master_find_slave(master, 0, slave_position))) {
up(&master->master_sem);
EC_MASTER_ERR(master, "Slave %u does not exist!\n", slave_position);
ec_sdo_request_clear(&request.req);
return -EINVAL;
}
EC_SLAVE_DBG(request.slave, 1, "Schedule SDO download request"
" (complete access).\n");
// schedule request.
list_add_tail(&request.list, &request.slave->slave_sdo_requests);
up(&master->master_sem);
// wait for processing through FSM
if (wait_event_interruptible(request.slave->sdo_queue,
request.req.state != EC_INT_REQUEST_QUEUED)) {
// interrupted by signal
down(&master->master_sem);
if (request.req.state == EC_INT_REQUEST_QUEUED) {
list_del(&request.list);
up(&master->master_sem);
ec_sdo_request_clear(&request.req);
return -EINTR;
}
// request already processing: interrupt not possible.
up(&master->master_sem);
}
// wait until master FSM has finished processing
wait_event(request.slave->sdo_queue,
request.req.state != EC_INT_REQUEST_BUSY);
EC_SLAVE_DBG(request.slave, 1, "Finished SDO download request"
" (complete access).\n");
*abort_code = request.req.abort_code;
if (request.req.state == EC_INT_REQUEST_SUCCESS) {
return 0;
} else if (request.req.errno) {
return -request.req.errno;
} else {
return -EIO;
}
}
/*****************************************************************************/
int ecrt_master_sdo_upload(ec_master_t *master, uint16_t slave_position,
uint16_t index, uint8_t subindex, uint8_t *target,
size_t target_size, size_t *result_size, uint32_t *abort_code)
@ -2717,6 +2799,7 @@ EXPORT_SYMBOL(ecrt_master_sync_slave_clocks);
EXPORT_SYMBOL(ecrt_master_sync_monitor_queue);
EXPORT_SYMBOL(ecrt_master_sync_monitor_process);
EXPORT_SYMBOL(ecrt_master_sdo_download);
EXPORT_SYMBOL(ecrt_master_sdo_download_complete);
EXPORT_SYMBOL(ecrt_master_sdo_upload);
EXPORT_SYMBOL(ecrt_master_write_idn);
EXPORT_SYMBOL(ecrt_master_read_idn);

View File

@ -49,6 +49,7 @@ string CommandDownload::helpString(const string &binaryBaseName) const
str << binaryBaseName << " " << getName()
<< " [OPTIONS] <INDEX> <SUBINDEX> <VALUE>" << endl
<< " [OPTIONS] <INDEX> <VALUE>" << endl
<< endl
<< getBriefDescription() << endl
<< endl
@ -60,6 +61,9 @@ string CommandDownload::helpString(const string &binaryBaseName) const
<< "information service or the SDO is not in the dictionary," << endl
<< "the --type option is mandatory." << endl
<< endl
<< "The second call (without <SUBINDEX>) uses the complete" << endl
<< "access method." << endl
<< endl
<< typeInfo()
<< endl
<< "Arguments:" << endl
@ -68,7 +72,8 @@ string CommandDownload::helpString(const string &binaryBaseName) const
<< " SUBINDEX is the SDO entry subindex and must be an" << endl
<< " unsigned 8 bit number." << endl
<< " VALUE is the value to download and must correspond" << endl
<< " to the SDO entry datatype (see above)." << endl
<< " to the SDO entry datatype (see above). Use" << endl
<< " '-' to read from standard input." << endl
<< endl
<< "Command-specific options:" << endl
<< " --alias -a <alias>" << endl
@ -85,16 +90,18 @@ string CommandDownload::helpString(const string &binaryBaseName) const
void CommandDownload::execute(const StringVector &args)
{
stringstream strIndex, strSubIndex, err;
stringstream strIndex, err;
ec_ioctl_slave_sdo_download_t data;
unsigned int number;
unsigned int valueIndex;
const DataType *dataType = NULL;
SlaveList slaves;
if (args.size() != 3) {
err << "'" << getName() << "' takes 3 arguments!";
if (args.size() != 2 && args.size() != 3) {
err << "'" << getName() << "' takes 2 or 3 arguments!";
throwInvalidUsageException(err);
}
data.complete_access = args.size() == 2;
valueIndex = data.complete_access ? 1 : 2;
strIndex << args[0];
strIndex
@ -105,15 +112,22 @@ void CommandDownload::execute(const StringVector &args)
throwInvalidUsageException(err);
}
strSubIndex << args[1];
strSubIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> number;
if (strSubIndex.fail() || number > 0xff) {
err << "Invalid SDO subindex '" << args[1] << "'!";
throwInvalidUsageException(err);
if (data.complete_access) {
data.sdo_entry_subindex = 0;
} else {
stringstream strSubIndex;
unsigned int number;
strSubIndex << args[1];
strSubIndex
>> resetiosflags(ios::basefield) // guess base from prefix
>> number;
if (strSubIndex.fail() || number > 0xff) {
err << "Invalid SDO subindex '" << args[1] << "'!";
throwInvalidUsageException(err);
}
data.sdo_entry_subindex = number;
}
data.sdo_entry_subindex = number;
MasterDevice m(getSingleMasterIndex());
m.open(MasterDevice::ReadWrite);
@ -147,17 +161,59 @@ void CommandDownload::execute(const StringVector &args)
}
}
if (dataType->byteSize) {
data.data_size = dataType->byteSize;
} else {
data.data_size = DefaultBufferSize;
}
if (args[valueIndex] == "-") {
ostringstream tmp;
data.data = new uint8_t[data.data_size + 1];
tmp << cin.rdbuf();
string const &contents = tmp.str();
if (!contents.size()) {
err << "Invalid data size " << contents.size() << "! "
<< "Must be non-zero.";
throwCommandException(err);
}
data.data_size = contents.size();
data.data = new uint8_t[data.data_size + 1];
try {
data.data_size = interpretAsType(
dataType, contents, data.data, data.data_size);
} catch (SizeException &e) {
delete [] data.data;
throwCommandException(e.what());
} catch (ios::failure &e) {
delete [] data.data;
err << "Invalid value argument '" << args[2]
<< "' for type '" << dataType->name << "'!";
throwInvalidUsageException(err);
}
} else {
if (dataType->byteSize) {
data.data_size = dataType->byteSize;
} else {
data.data_size = DefaultBufferSize;
}
data.data = new uint8_t[data.data_size + 1];
try {
data.data_size = interpretAsType(
dataType, args[valueIndex], data.data, data.data_size);
} catch (SizeException &e) {
delete [] data.data;
throwCommandException(e.what());
} catch (ios::failure &e) {
delete [] data.data;
err << "Invalid value argument '" << args[2]
<< "' for type '" << dataType->name << "'!";
throwInvalidUsageException(err);
}
}
try {
data.data_size = interpretAsType(
dataType, args[2], data.data, data.data_size);
dataType, args[valueIndex], data.data, data.data_size);
} catch (SizeException &e) {
delete [] data.data;
throwCommandException(e.what());