# HG changeset patch # User Florian Pose # Date 1227006829 0 # Node ID b3d06a8807b3cf55a1281974bfa47306d0f1b135 # Parent ed15eef57d5c2392f226fe0dca4181e7b0ac3e10 Included ecrt_voe_handler_read_nosync()-Patch by Mathias Weber. diff -r ed15eef57d5c -r b3d06a8807b3 include/ecrt.h --- a/include/ecrt.h Mon Nov 17 17:18:02 2008 +0000 +++ b/include/ecrt.h Tue Nov 18 11:13:49 2008 +0000 @@ -1049,6 +1049,25 @@ ec_voe_handler_t *voe /**< VoE handler. */ ); +/** Start a VoE read operation without querying the sync manager status. + * + * After this function has been called, the ecrt_voe_handler_execute() method + * must be called in every bus cycle as long as it returns EC_REQUEST_BUSY. No + * other operation may be started while the handler is busy. + * + * The state machine queries the slave by sending an empty mailbox. The slave + * fills its data to the master in this mailbox. If no data appear within the + * EC_VOE_RESPONSE_TIMEOUT (defined in master/voe_handler.c), the operation + * fails. + * + * On success, the size of the read data can be determined via + * ecrt_voe_handler_data_size(), while the VoE header of the received data + * can be retrieved with ecrt_voe_handler_received_header(). + */ +void ecrt_voe_handler_read_nosync( + ec_voe_handler_t *voe /**< VoE handler. */ + ); + /** Execute the handler. * * This method executes the VoE handler. It has to be called in every bus cycle diff -r ed15eef57d5c -r b3d06a8807b3 lib/voe_handler.c --- a/lib/voe_handler.c Mon Nov 17 17:18:02 2008 +0000 +++ b/lib/voe_handler.c Tue Nov 18 11:13:49 2008 +0000 @@ -111,6 +111,20 @@ /*****************************************************************************/ +void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe) +{ + ec_ioctl_voe_t data; + + data.config_index = voe->config->index; + data.voe_index = voe->index; + + if (ioctl(voe->config->master->fd, EC_IOCTL_VOE_READ_NOSYNC, &data) == -1) + fprintf(stderr, "Failed to initiate VoE reading: %s\n", + strerror(errno)); +} + +/*****************************************************************************/ + void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size) { ec_ioctl_voe_t data; diff -r ed15eef57d5c -r b3d06a8807b3 master/cdev.c --- a/master/cdev.c Mon Nov 17 17:18:02 2008 +0000 +++ b/master/cdev.c Tue Nov 18 11:13:49 2008 +0000 @@ -2227,6 +2227,45 @@ /*****************************************************************************/ +/** Starts a VoE read operation without sending a sync message first. + */ +int ec_cdev_ioctl_voe_read_nosync( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_voe_t data; + ec_slave_config_t *sc; + ec_voe_handler_t *voe; + + if (unlikely(!priv->requested)) + return -EPERM; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + return -EFAULT; + + if (down_interruptible(&master->master_sem)) + return -EINTR; + + if (!(sc = ec_master_get_config(master, data.config_index))) { + up(&master->master_sem); + return -ENOENT; + } + + if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { + up(&master->master_sem); + return -ENOENT; + } + + up(&master->master_sem); + + ecrt_voe_handler_read_nosync(voe); + return 0; +} + +/*****************************************************************************/ + /** Starts a VoE write operation. */ int ec_cdev_ioctl_voe_write( @@ -2559,6 +2598,10 @@ case EC_IOCTL_VOE_READ: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; + case EC_IOCTL_VOE_READ_NOSYNC: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_voe_read_nosync(master, arg, priv); return ec_cdev_ioctl_voe_read(master, arg, priv); case EC_IOCTL_VOE_WRITE: if (!(filp->f_mode & FMODE_WRITE)) diff -r ed15eef57d5c -r b3d06a8807b3 master/ioctl.h --- a/master/ioctl.h Mon Nov 17 17:18:02 2008 +0000 +++ b/master/ioctl.h Tue Nov 18 11:13:49 2008 +0000 @@ -104,9 +104,10 @@ #define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x2a, ec_ioctl_voe_t) #define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x2b, ec_ioctl_voe_t) #define EC_IOCTL_VOE_READ EC_IOW(0x2c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x2d, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x2e, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x2f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x2d, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x2e, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x2f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x30, ec_ioctl_voe_t) /*****************************************************************************/ diff -r ed15eef57d5c -r b3d06a8807b3 master/voe_handler.c --- a/master/voe_handler.c Mon Nov 17 17:18:02 2008 +0000 +++ b/master/voe_handler.c Tue Nov 18 11:13:49 2008 +0000 @@ -65,6 +65,9 @@ void ec_voe_handler_state_read_check(ec_voe_handler_t *); void ec_voe_handler_state_read_response(ec_voe_handler_t *); +void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *); +void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *); + void ec_voe_handler_state_end(ec_voe_handler_t *); void ec_voe_handler_state_error(ec_voe_handler_t *); @@ -168,6 +171,15 @@ /*****************************************************************************/ +void ecrt_voe_handler_read_nosync(ec_voe_handler_t *voe) +{ + voe->dir = EC_DIR_INPUT; + voe->state = ec_voe_handler_state_read_nosync_start; + voe->request_state = EC_INT_REQUEST_QUEUED; +} + +/*****************************************************************************/ + void ecrt_voe_handler_write(ec_voe_handler_t *voe, size_t size) { voe->dir = EC_DIR_OUTPUT; @@ -427,6 +439,106 @@ /*****************************************************************************/ +/** Start reading VoE data without sending a sync message before. + */ +void ec_voe_handler_state_read_nosync_start(ec_voe_handler_t *voe) +{ + ec_datagram_t *datagram = &voe->datagram; + ec_slave_t *slave = voe->config->slave; + + if (slave->master->debug_level) + EC_DBG("Reading VoE data to slave %u.\n", slave->ring_position); + + if (!(slave->sii.mailbox_protocols & EC_MBOX_VOE)) { + EC_ERR("Slave %u does not support VoE!\n", slave->ring_position); + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + return; + } + + ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail. + + voe->jiffies_start = jiffies; + voe->retries = EC_FSM_RETRIES; + voe->state = ec_voe_handler_state_read_nosync_response; +} + +/*****************************************************************************/ + +/** Read the pending mailbox data without sending a sync message before. This + * might lead to an empty reponse from the client. + */ +void ec_voe_handler_state_read_nosync_response(ec_voe_handler_t *voe) +{ + ec_datagram_t *datagram = &voe->datagram; + ec_slave_t *slave = voe->config->slave; + ec_master_t *master = voe->config->master; + uint8_t *data, mbox_prot; + size_t rec_size; + + if (datagram->state == EC_DATAGRAM_TIMED_OUT && voe->retries--) + return; + + if (datagram->state != EC_DATAGRAM_RECEIVED) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + EC_ERR("Failed to receive VoE read datagram for" + " slave %u (datagram state %u).\n", + slave->ring_position, datagram->state); + return; + } + + if (datagram->working_counter == 0) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + EC_DBG("Slave (%u) did not send data with Mailbox.", + slave->ring_position); + return; + } + + if (datagram->working_counter != 1) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + EC_WARN("Reception of VoE read response failed on slave %u: ", + slave->ring_position); + ec_datagram_print_wc_error(datagram); + return; + } + + if (!(data = ec_slave_mbox_fetch(slave, datagram, + &mbox_prot, &rec_size))) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + return; + } + + if (mbox_prot != EC_MBOX_TYPE_VOE) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + EC_WARN("Received mailbox protocol 0x%02X as response.\n", mbox_prot); + ec_print_data(data, rec_size); + return; + } + + if (rec_size < EC_VOE_HEADER_SIZE) { + voe->state = ec_voe_handler_state_error; + voe->request_state = EC_INT_REQUEST_FAILURE; + EC_ERR("Received VoE header is incomplete (%u bytes)!\n", rec_size); + return; + } + + if (master->debug_level) { + EC_DBG("VoE data:\n"); + ec_print_data(data, rec_size); + } + + voe->data_size = rec_size - EC_VOE_HEADER_SIZE; + voe->request_state = EC_INT_REQUEST_SUCCESS; + voe->state = ec_voe_handler_state_end; // success +} + +/*****************************************************************************/ + /** Successful termination state function. */ void ec_voe_handler_state_end(ec_voe_handler_t *voe)