From 10c75018518ae05a2bd76e4566b419ead2a9ab73 Mon Sep 17 00:00:00 2001 From: Florian Pose Date: Thu, 13 Aug 2009 13:53:56 +0200 Subject: [PATCH] Implemented CompleteAccess for SDO downloads. --- NEWS | 1 + TODO | 3 +++ include/ecrt.h | 19 +++++++++++++++++++ lib/slave_config.c | 23 ++++++++++++++++++++++ master/cdev.c | 11 ++++++++--- master/fsm_coe.c | 34 ++++++++++++++++++++++++--------- master/ioctl.h | 8 +++++++- master/sdo_request.c | 2 ++ master/sdo_request.h | 1 + master/slave_config.c | 43 ++++++++++++++++++++++++++++++++++++++++++ tool/CommandConfig.cpp | 31 ++++++++++++++---------------- 11 files changed, 146 insertions(+), 30 deletions(-) diff --git a/NEWS b/NEWS index b19674f9..afbef8e1 100644 --- a/NEWS +++ b/NEWS @@ -61,6 +61,7 @@ Changes since 1.4.0: * Added 'ethercat eoe' command to display Ethernet over EtherCAT statistics. * Added 'ethercat cstruct' command to output PDO information in C language. * Significantly improved EoE bandwidth by running EoE processing in a kthread. +* Implemented CompleteAccess for SDO downloads. Changes in 1.4.0: diff --git a/TODO b/TODO index a03f5c35..2c9c6f44 100644 --- a/TODO +++ b/TODO @@ -47,6 +47,9 @@ Version 1.5.0: * Document ec_fsm_foe members. * Test KBUILD_EXTRA_SYMBOLS. * Remove default buffer size in SDO upload. +* Check for Enable SDO Complete Access flag. +* Implement CompleteAccess for command-line tool. +* Implement CompleteAccess for SDO uploads. Future issues: diff --git a/include/ecrt.h b/include/ecrt.h index 1c269d9b..b8d88e99 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -53,6 +53,8 @@ * - Added watchdog configuration (method ecrt_slave_config_watchdog(), * #ec_watchdog_mode_t, \a watchdog_mode parameter in ec_sync_info_t and * ecrt_slave_config_sync_manager()). + * - Added ecrt_slave_config_complete_sdo() method to download an SDO during + * configuration via CompleteAccess. * - Added ecrt_open_master() and ecrt_master_reserve() separation for * userspace. * - Added bus information interface (methods ecrt_master(), @@ -1032,6 +1034,23 @@ int ecrt_slave_config_sdo32( uint32_t value /**< Value to set. */ ); +/** Add configuration data for a complete SDO. + * + * The SDO data are transferred via CompleteAccess. Data for the first + * subindex (0) have to be included. + * + * \see ecrt_slave_config_sdo(). + * + * \retval 0 Success. + * \retval <0 Error code. + */ +int ecrt_slave_config_complete_sdo( + ec_slave_config_t *sc, /**< Slave configuration. */ + uint16_t index, /**< Index of the SDO to configure. */ + const uint8_t *data, /**< Pointer to the data. */ + size_t size /**< Size of the \a data. */ + ); + /** Create an SDO request to exchange SDOs during realtime operation. * * The created SDO request object is freed automatically when the master is diff --git a/lib/slave_config.c b/lib/slave_config.c index 0b62b8cf..bbbc63e6 100644 --- a/lib/slave_config.c +++ b/lib/slave_config.c @@ -294,6 +294,29 @@ int ecrt_slave_config_sdo(ec_slave_config_t *sc, uint16_t index, data.subindex = subindex; data.data = sdo_data; data.size = size; + data.complete_access = 0; + + if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) { + fprintf(stderr, "Failed to configure SDO.\n"); + return -1; // FIXME + } + + return 0; +} + +/*****************************************************************************/ + +int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index, + const uint8_t *sdo_data, size_t size) +{ + ec_ioctl_sc_sdo_t data; + + data.config_index = sc->index; + data.index = index; + data.subindex = 0; + data.data = sdo_data; + data.size = size; + data.complete_access = 1; if (ioctl(sc->master->fd, EC_IOCTL_SC_SDO, &data) == -1) { fprintf(stderr, "Failed to configure SDO.\n"); diff --git a/master/cdev.c b/master/cdev.c index 2e85040e..a744bf76 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -1434,7 +1434,8 @@ int ec_cdev_ioctl_config_sdo( data.index = req->index; data.subindex = req->subindex; data.size = req->data_size; - memcpy(&data.data, req->data, min((u32) data.size, (u32) 4)); + memcpy(&data.data, req->data, + min((u32) data.size, (u32) EC_MAX_SDO_DATA_SIZE)); up(&master->master_sem); @@ -2120,8 +2121,12 @@ int ec_cdev_ioctl_sc_sdo( up(&master->master_sem); // FIXME - ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data, - data.size); + if (data.complete_access) { + ret = ecrt_slave_config_complete_sdo(sc, data.index, sdo_data, data.size); + } else { + ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data, + data.size); + } kfree(sdo_data); return ret; } diff --git a/master/fsm_coe.c b/master/fsm_coe.c index 8cf6a75f..366c41c1 100644 --- a/master/fsm_coe.c +++ b/master/fsm_coe.c @@ -1074,8 +1074,14 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */) uint8_t size; if (fsm->slave->master->debug_level) { - EC_DBG("Downloading SDO 0x%04X:%02X to slave %u.\n", - request->index, request->subindex, slave->ring_position); + char subidxstr[10]; + if (request->complete_access) { + subidxstr[0] = 0x00; + } else { + sprintf(subidxstr, ":%02X", request->subindex); + } + EC_DBG("Downloading SDO 0x%04X%s to slave %u.\n", + request->index, subidxstr, slave->ring_position); ec_print_data(request->data, request->data_size); } @@ -1097,9 +1103,11 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */) EC_WRITE_U16(data, 0x2 << 12); // SDO request EC_WRITE_U8 (data + 2, (0x3 // size specified, expedited | size << 2 + | ((request->complete_access ? 1 : 0) << 4) | 0x1 << 5)); // Download request EC_WRITE_U16(data + 3, request->index); - EC_WRITE_U8 (data + 5, request->subindex); + EC_WRITE_U8 (data + 5, + request->complete_access ? 0x00 : request->subindex); memcpy(data + 6, request->data, request->data_size); memset(data + 6 + request->data_size, 0x00, 4 - request->data_size); @@ -1110,7 +1118,7 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */) } else { // request->data_size > 4, use normal transfer type if (slave->configured_rx_mailbox_size < 6 + 10 + request->data_size) { - EC_ERR("SDO fragmenting not supported yet!\n"); + EC_ERR("SDO fragmenting not supported yet!\n"); // FIXME fsm->state = ec_fsm_coe_error; return; } @@ -1124,9 +1132,11 @@ void ec_fsm_coe_down_start(ec_fsm_coe_t *fsm /**< finite state machine */) EC_WRITE_U16(data, 0x2 << 12); // SDO request EC_WRITE_U8 (data + 2, (0x1 // size indicator, normal + | ((request->complete_access ? 1 : 0) << 4) | 0x1 << 5)); // Download request EC_WRITE_U16(data + 3, request->index); - EC_WRITE_U8 (data + 5, request->subindex); + EC_WRITE_U8 (data + 5, + request->complete_access ? 0x00 : request->subindex); EC_WRITE_U32(data + 6, request->data_size); memcpy(data + 10, request->data, request->data_size); @@ -1311,12 +1321,18 @@ void ec_fsm_coe_down_response(ec_fsm_coe_t *fsm /**< finite state machine */) if (EC_READ_U16(data) >> 12 == 0x2 && // SDO request EC_READ_U8 (data + 2) >> 5 == 0x4) { // abort SDO transfer request + char subidxstr[10]; fsm->state = ec_fsm_coe_error; - EC_ERR("SDO download 0x%04X:%02X (%u bytes) aborted on slave %u.\n", - request->index, request->subindex, request->data_size, - slave->ring_position); + if (request->complete_access) { + subidxstr[0] = 0x00; + } else { + sprintf(subidxstr, ":%02X", request->subindex); + } + EC_ERR("SDO download 0x%04X%s (%u bytes) aborted on slave %u.\n", + request->index, subidxstr, request->data_size, + slave->ring_position); if (rec_size < 10) { - EC_ERR("Incomplete Abort command:\n"); + EC_ERR("Incomplete abort command:\n"); ec_print_data(data, rec_size); } else { fsm->request->abort_code = EC_READ_U32(data + 6); diff --git a/master/ioctl.h b/master/ioctl.h index c1785d71..4e84df9a 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -438,6 +438,11 @@ typedef struct { /*****************************************************************************/ +/** Maximum size for displayed SDO data. + * \todo Make this dynamic. + */ +#define EC_MAX_SDO_DATA_SIZE 1024 + typedef struct { // inputs uint32_t config_index; @@ -447,7 +452,7 @@ typedef struct { uint16_t index; uint8_t subindex; uint32_t size; - uint8_t data[4]; + uint8_t data[EC_MAX_SDO_DATA_SIZE]; } ec_ioctl_config_sdo_t; /*****************************************************************************/ @@ -505,6 +510,7 @@ typedef struct { uint8_t subindex; const uint8_t *data; size_t size; + uint8_t complete_access; } ec_ioctl_sc_sdo_t; /*****************************************************************************/ diff --git a/master/sdo_request.c b/master/sdo_request.c index 7ec39967..fb2b8703 100644 --- a/master/sdo_request.c +++ b/master/sdo_request.c @@ -56,6 +56,7 @@ void ec_sdo_request_init( ec_sdo_request_t *req /**< SDO request. */ ) { + req->complete_access = 0; req->data = NULL; req->mem_size = 0; req->data_size = 0; @@ -88,6 +89,7 @@ int ec_sdo_request_copy( const ec_sdo_request_t *other /**< Other SDO request to copy from. */ ) { + req->complete_access = other->complete_access; req->index = other->index; req->subindex = other->subindex; return ec_sdo_request_copy_data(req, other->data, other->data_size); diff --git a/master/sdo_request.h b/master/sdo_request.h index 43826883..81975e51 100644 --- a/master/sdo_request.h +++ b/master/sdo_request.h @@ -52,6 +52,7 @@ struct ec_sdo_request { uint8_t *data; /**< Pointer to SDO data. */ size_t mem_size; /**< Size of SDO data memory. */ size_t data_size; /**< Size of SDO data. */ + uint8_t complete_access; /**< SDO shall be transferred completely. */ uint32_t issue_timeout; /**< Maximum time in ms, the processing of the request may take. */ uint32_t response_timeout; /**< Maximum time in ms, the transfer is diff --git a/master/slave_config.c b/master/slave_config.c index 874ed8bc..dd3bf35a 100644 --- a/master/slave_config.c +++ b/master/slave_config.c @@ -794,6 +794,48 @@ int ecrt_slave_config_sdo32(ec_slave_config_t *sc, uint16_t index, /*****************************************************************************/ +int ecrt_slave_config_complete_sdo(ec_slave_config_t *sc, uint16_t index, + const uint8_t *data, size_t size) +{ + ec_slave_t *slave = sc->slave; + ec_sdo_request_t *req; + int ret; + + if (sc->master->debug_level) + EC_DBG("ecrt_slave_config_complete_sdo(sc = 0x%x, index = 0x%04X, " + "data = 0x%x, size = %u)\n", (u32) sc, + index, (u32) data, size); + + if (slave && !(slave->sii.mailbox_protocols & EC_MBOX_COE)) { + EC_ERR("Slave %u does not support CoE!\n", slave->ring_position); + return -EPROTONOSUPPORT; // protocol not supported + } + + if (!(req = (ec_sdo_request_t *) + kmalloc(sizeof(ec_sdo_request_t), GFP_KERNEL))) { + EC_ERR("Failed to allocate memory for SDO configuration!\n"); + return -ENOMEM; + } + + ec_sdo_request_init(req); + ec_sdo_request_address(req, index, 0); + req->complete_access = 1; + + ret = ec_sdo_request_copy_data(req, data, size); + if (ret < 0) { + ec_sdo_request_clear(req); + kfree(req); + return ret; + } + + down(&sc->master->master_sem); + list_add_tail(&req->list, &sc->sdo_configs); + up(&sc->master->master_sem); + return 0; +} + +/*****************************************************************************/ + /** Same as ecrt_slave_config_create_sdo_request(), but with ERR_PTR() return * value. */ @@ -923,6 +965,7 @@ EXPORT_SYMBOL(ecrt_slave_config_sdo); EXPORT_SYMBOL(ecrt_slave_config_sdo8); EXPORT_SYMBOL(ecrt_slave_config_sdo16); EXPORT_SYMBOL(ecrt_slave_config_sdo32); +EXPORT_SYMBOL(ecrt_slave_config_complete_sdo); EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request); EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler); EXPORT_SYMBOL(ecrt_slave_config_state); diff --git a/tool/CommandConfig.cpp b/tool/CommandConfig.cpp index 9532665e..9deae0a7 100644 --- a/tool/CommandConfig.cpp +++ b/tool/CommandConfig.cpp @@ -131,7 +131,7 @@ void CommandConfig::showDetailedConfigs( ) { ConfigList::const_iterator configIter; - unsigned int j, k, l; + unsigned int i, j, k, l; ec_ioctl_slave_t slave; ec_ioctl_config_pdo_t pdo; ec_ioctl_config_pdo_entry_t entry; @@ -217,26 +217,23 @@ void CommandConfig::showDetailedConfigs( << hex << setfill('0') << setw(4) << sdo.index << ":" << setw(2) << (unsigned int) sdo.subindex - << ", " << dec << sdo.size << " byte: " << hex; + << ", " << dec << sdo.size << " byte" << endl; - switch (sdo.size) { - case 1: - cout << "0x" << setw(2) - << (unsigned int) *(uint8_t *) &sdo.data; - break; - case 2: - cout << "0x" << setw(4) - << le16_to_cpup(&sdo.data); - break; - case 4: - cout << "0x" << setw(8) - << le32_to_cpup(&sdo.data); - break; - default: - cout << "???"; + cout << " " << hex; + for (i = 0; i < min((uint32_t) sdo.size, + (uint32_t) EC_MAX_SDO_DATA_SIZE); i++) { + cout << setw(2) << (unsigned int) sdo.data[i]; + if ((i + 1) % 16 == 0 && i < sdo.size - 1) { + cout << endl << " "; + } else { + cout << " "; + } } cout << endl; + if (sdo.size > EC_MAX_SDO_DATA_SIZE) { + cout << " ..." << endl; + } } } else { cout << " None." << endl;