Newer
Older
cat_size = EC_READ_U16(cat_header + 1);
if (cat_header + cat_size + 2 >
(const uint16_t *) request.data + request.word_size) {
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 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 */
)
{
uint16_t alias;
if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
EC_ERR("Writing to SII is only allowed in idle mode!\n");
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_data || slave->sii_size < 16) {
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, slave->sii_data, 14);
// write new alias address in word 4
// calculate new checksum over words 0 to 6
crc = ec_slave_sii_crc(sii_data, 14);
EC_WRITE_U16(sii_data + 14, crc);
INIT_LIST_HEAD(&request.list);
request.slave = slave;
request.word_offset = 0x0000;
request.word_size = 8;
if ((ret = ec_slave_schedule_sii_writing(&request)))
slave->sii.alias = alias; // FIXME: do this in state machine
return size; // success
}
/*****************************************************************************/
Formats attribute data for SysFS read access.
\return number of bytes to read
ssize_t ec_show_slave_attribute(struct kobject *kobj, /**< slave's kobject */
struct attribute *attr, /**< attribute */
char *buffer /**< memory to store data */
)
{
ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj);
if (attr == &attr_info) {
return ec_slave_info(slave, buffer);
else if (attr == &attr_state) {
switch (slave->current_state) {
case EC_SLAVE_STATE_INIT:
return sprintf(buffer, "INIT\n");
case EC_SLAVE_STATE_PREOP:
return sprintf(buffer, "PREOP\n");
case EC_SLAVE_STATE_SAFEOP:
return sprintf(buffer, "SAFEOP\n");
case EC_SLAVE_STATE_OP:
return sprintf(buffer, "OP\n");
default:
return sprintf(buffer, "UNKNOWN\n");
}
}
else if (attr == &attr_sii) {
if (slave->sii_data) {
if (slave->sii_size > PAGE_SIZE) {
EC_ERR("SII contents of slave %u exceed 1 page (%u/%u).\n",
slave->ring_position, slave->sii_size,
(int) PAGE_SIZE);
}
else {
memcpy(buffer, slave->sii_data, slave->sii_size);
return slave->sii_size;
}
}
}
else if (attr == &attr_alias) {
return sprintf(buffer, "%u\n", slave->sii.alias);
/*****************************************************************************/
/**
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_state) {
Florian Pose
committed
char state[EC_STATE_STRING_SIZE];
ec_slave_request_state(slave, EC_SLAVE_STATE_INIT);
ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP);
else if (!strcmp(buffer, "SAFEOP\n"))
ec_slave_request_state(slave, EC_SLAVE_STATE_SAFEOP);
ec_slave_request_state(slave, EC_SLAVE_STATE_OP);
else {
EC_ERR("Invalid slave state \"%s\"!\n", buffer);
return -EINVAL;
ec_state_string(slave->requested_state, state);
EC_INFO("Accepted new state %s for slave %u.\n",
state, slave->ring_position);
else 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);
}
/*****************************************************************************/
* Get the sync manager for either Rx- or Tx-Pdos.
* \return pointer to sync manager, or NULL.
ec_slave_t *slave, /**< EtherCAT slave */
ec_direction_t dir /**< input or output */
)
{
unsigned int sync_index;
if (dir != EC_DIR_INPUT && dir != EC_DIR_OUTPUT) {
EC_ERR("Invalid direction!\n");
return NULL;
sync_index = (unsigned int) dir;
if (slave->sii.mailbox_protocols) sync_index += 2;
}
/*****************************************************************************/
/**
\return 0 in case of success, else < 0
*/
int ec_slave_validate(const ec_slave_t *slave, /**< EtherCAT slave */
uint32_t vendor_id, /**< vendor ID */
uint32_t product_code /**< product code */
)
{
if (vendor_id != slave->sii.vendor_id ||
product_code != slave->sii.product_code) {
EC_ERR("Invalid slave type at position %u:\n", slave->ring_position);
EC_ERR(" Requested: 0x%08X 0x%08X\n", vendor_id, product_code);
EC_ERR(" Found: 0x%08X 0x%08X\n",
slave->sii.vendor_id, slave->sii.product_code);
/*****************************************************************************/
/**
Counts the total number of Sdos and entries in the dictionary.
*/
void ec_slave_sdo_dict_info(const ec_slave_t *slave, /**< EtherCAT slave */
unsigned int *sdo_count, /**< number of Sdos */
unsigned int *entry_count /**< total number of
entries */
)
{
unsigned int sdos = 0, entries = 0;
ec_sdo_t *sdo;
ec_sdo_entry_t *entry;
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
sdos++;
list_for_each_entry(entry, &sdo->entries, list) {
entries++;
}
}
*sdo_count = sdos;
*entry_count = entries;
}
/*****************************************************************************/
/**
* Get an Sdo from the dictionary.
* \returns The desired Sdo, or NULL.
*/
ec_sdo_t *ec_slave_get_sdo(
ec_slave_t *slave /**< EtherCAT slave */,
)
{
ec_sdo_t *sdo;
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
if (sdo->index != index) continue;
return sdo;
}
return NULL;
}
/*****************************************************************************/
/** Finds a mapped Pdo.
* \returns The desired Pdo object, or NULL.
*/
const ec_pdo_t *ec_slave_find_pdo(
const ec_slave_t *slave, /**< Slave. */
uint16_t index /**< Pdo index to find. */
)
{
unsigned int i;
const ec_sync_t *sync;
const ec_pdo_t *pdo;
for (i = 0; i < slave->sii.sync_count; i++) {
sync = &slave->sii.syncs[i];
if (!(pdo = ec_pdo_mapping_find_pdo_const(&sync->mapping, index)))