Newer
Older
cat_size = EC_READ_U16(cat_header + 1);
if (cat_header + cat_size + 2 > request.words + request.size) {
EC_ERR("EEPROM data corrupted! Dropping.\n");
return -EINVAL;
}
cat_header += cat_size + 2;
cat_type = EC_READ_U16(cat_header);
}
// EEPROM data ok. schedule writing.
if ((ret = ec_slave_schedule_eeprom_writing(&request)))
return ret; // error code
return size; // success
}
/*****************************************************************************/
/**
* Writes the Secondary slave address (alias) to the slave's EEPROM.
* \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_eeprom_write_request_t request;
char *remainder;
uint16_t alias, words[8];
if (slave->master->mode != EC_MASTER_MODE_IDLE) { // FIXME
EC_ERR("Writing to EEPROM 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->eeprom_data || slave->eeprom_size < 16) {
EC_ERR("Failed to read EEPROM contents from slave %u.\n",
slave->ring_position);
return -EINVAL;
}
// copy first 7 words of recent EEPROM contents
memcpy(words, slave->eeprom_data, 14);
// write new alias address
EC_WRITE_U16(words + 4, alias);
// calculate new checksum over words 0 to 6
crc = ec_slave_eeprom_crc((const uint8_t *) words, 14);
EC_WRITE_U16(words + 7, crc);
// init EEPROM write request
INIT_LIST_HEAD(&request.list);
request.slave = slave;
request.words = words;
request.offset = 0x0000;
request.size = 8;
if ((ret = ec_slave_schedule_eeprom_writing(&request)))
return ret; // error code
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_SAVEOP:
return sprintf(buffer, "SAVEOP\n");
case EC_SLAVE_STATE_OP:
return sprintf(buffer, "OP\n");
default:
return sprintf(buffer, "UNKNOWN\n");
}
}
else if (attr == &attr_eeprom) {
if (slave->eeprom_data) {
if (slave->eeprom_size > PAGE_SIZE) {
EC_ERR("EEPROM contents of slave %i exceed 1 page (%i/%i).\n",
slave->ring_position, slave->eeprom_size,
(int) PAGE_SIZE);
}
else {
memcpy(buffer, slave->eeprom_data, slave->eeprom_size);
return slave->eeprom_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, "SAVEOP\n"))
ec_slave_request_state(slave, EC_SLAVE_STATE_SAVEOP);
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 %i.\n",
state, slave->ring_position);
return ec_slave_write_eeprom(slave, buffer, size);
else if (attr == &attr_alias) {
return ec_slave_write_alias(slave, buffer, size);
}
/*****************************************************************************/
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;
if (sync_index >= slave->sii_sync_count)
return NULL;
return &slave->sii_syncs[sync_index];
}
/*****************************************************************************/
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
/**
\return 0 in case of success, else < 0
*/
int ec_slave_conf_sdo(ec_slave_t *slave, /**< EtherCAT slave */
uint16_t sdo_index, /**< SDO index */
uint8_t sdo_subindex, /**< SDO subindex */
const uint8_t *data, /**< SDO data */
size_t size /**< SDO size in bytes */
)
{
ec_sdo_data_t *sdodata;
if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
EC_ERR("Slave %i does not support CoE!\n", slave->ring_position);
return -1;
}
if (!(sdodata = (ec_sdo_data_t *)
kmalloc(sizeof(ec_sdo_data_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for SDO configuration object!\n");
return -1;
}
if (!(sdodata->data = (uint8_t *) kmalloc(size, GFP_KERNEL))) {
EC_ERR("Failed to allocate memory for SDO configuration data!\n");
kfree(sdodata);
return -1;
}
sdodata->index = sdo_index;
sdodata->subindex = sdo_subindex;
memcpy(sdodata->data, data, size);
sdodata->size = size;
list_add_tail(&sdodata->list, &slave->sdo_confs);
return 0;
}
/*****************************************************************************/
/**
\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 %i:\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);
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
/*****************************************************************************/
/**
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;
}
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
/*****************************************************************************/
/**
* Get an SDO from the dictionary.
* \returns The desired SDO, of NULL.
*/
ec_sdo_t *ec_slave_get_sdo(
ec_slave_t *slave /**< EtherCAT slave */,
uint16_t index /**< SDO index */
)
{
ec_sdo_t *sdo;
list_for_each_entry(sdo, &slave->sdo_dictionary, list) {
if (sdo->index != index) continue;
return sdo;
}
return NULL;
}
/******************************************************************************
* Realtime interface
*****************************************************************************/
/**
\return 0 in case of success, else < 0
\ingroup RealtimeInterface
*/
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
int ecrt_slave_conf_sdo8(ec_slave_t *slave, /**< EtherCAT slave */
uint16_t sdo_index, /**< SDO index */
uint8_t sdo_subindex, /**< SDO subindex */
uint8_t value /**< new SDO value */
)
{
uint8_t data[1];
EC_WRITE_U8(data, value);
return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 1);
}
/*****************************************************************************/
/**
\return 0 in case of success, else < 0
\ingroup RealtimeInterface
*/
int ecrt_slave_conf_sdo16(ec_slave_t *slave, /**< EtherCAT slave */
uint16_t sdo_index, /**< SDO index */
uint8_t sdo_subindex, /**< SDO subindex */
uint16_t value /**< new SDO value */
)
{
uint8_t data[2];
EC_WRITE_U16(data, value);
return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 2);
}
/*****************************************************************************/
/**
\return 0 in case of success, else < 0
\ingroup RealtimeInterface
*/
int ecrt_slave_conf_sdo32(ec_slave_t *slave, /**< EtherCAT slave */
uint16_t sdo_index, /**< SDO index */
uint8_t sdo_subindex, /**< SDO subindex */
uint32_t value /**< new SDO value */
)
{
uint8_t data[4];
EC_WRITE_U32(data, value);
return ec_slave_conf_sdo(slave, sdo_index, sdo_subindex, data, 4);
}
/*****************************************************************************/
void ecrt_slave_pdo_mapping_clear(
ec_slave_t *slave, /**< EtherCAT slave */
ec_direction_t dir /**< output/input */
)
{
ec_sync_t *sync;
if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
EC_ERR("Slave %i does not support CoE!\n", slave->ring_position);
return;
}
if (!(sync = ec_slave_get_pdo_sync(slave, dir)))
return;
ec_sync_clear_pdos(sync);
sync->alt_mapping = 1;
}
/*****************************************************************************/
int ecrt_slave_pdo_mapping_add(
ec_slave_t *slave, /**< EtherCAT slave */
ec_direction_t dir, /**< input/output */
uint16_t pdo_index /**< Index of PDO mapping list */)
{
ec_pdo_t *pdo;
ec_sync_t *sync;
unsigned int not_found = 1;
if (!(slave->sii_mailbox_protocols & EC_MBOX_COE)) {
EC_ERR("Slave %u does not support CoE!\n", slave->ring_position);
return -1;
}
list_for_each_entry(pdo, &slave->sii_pdos, list) {
if (pdo->index == pdo_index) {
not_found = 0;
break;
}
}
if (not_found) {
EC_ERR("Slave %u does not provide PDO 0x%04X!\n",
slave->ring_position, pdo_index);
return -1;
}
// check direction
if ((pdo->type == EC_TX_PDO && dir == EC_DIR_OUTPUT) ||
(pdo->type == EC_RX_PDO && dir == EC_DIR_INPUT)) {
EC_ERR("Invalid direction for PDO 0x%04X.\n", pdo_index);
return -1;
}
if (!(sync = ec_slave_get_pdo_sync(slave, dir))) {
EC_ERR("Failed to obtain sync manager for PDO mapping of slave %u!\n",
slave->ring_position);
if (ec_sync_add_pdo(sync, pdo))
return -1;
sync->alt_mapping = 1;
return 0;
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
}
/*****************************************************************************/
int ecrt_slave_pdo_mapping(ec_slave_t *slave, /**< EtherCAT slave */
ec_direction_t dir, /**< input/output */
unsigned int num_args, /**< Number of following arguments */
... /**< PDO indices to map */
)
{
va_list ap;
ecrt_slave_pdo_mapping_clear(slave, dir);
va_start(ap, num_args);
for (; num_args; num_args--) {
if (ecrt_slave_pdo_mapping_add(
slave, dir, (uint16_t) va_arg(ap, int))) {
return -1;
}
}
va_end(ap);
return 0;
}
/*****************************************************************************/
EXPORT_SYMBOL(ecrt_slave_conf_sdo8);
EXPORT_SYMBOL(ecrt_slave_conf_sdo16);
EXPORT_SYMBOL(ecrt_slave_conf_sdo32);
EXPORT_SYMBOL(ecrt_slave_pdo_mapping_clear);
EXPORT_SYMBOL(ecrt_slave_pdo_mapping_add);
EXPORT_SYMBOL(ecrt_slave_pdo_mapping);
/*****************************************************************************/