From 536f6ada2b30b23d2a7630855667076f3d75606b Mon Sep 17 00:00:00 2001 From: Florian Pose <fp@igh-essen.com> Date: Tue, 18 Nov 2008 11:13:49 +0000 Subject: [PATCH] Included ecrt_voe_handler_read_nosync()-Patch by Mathias Weber. --- include/ecrt.h | 19 ++++++++ lib/voe_handler.c | 14 ++++++ master/cdev.c | 43 +++++++++++++++++ master/ioctl.h | 7 +-- master/voe_handler.c | 112 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+), 3 deletions(-) diff --git a/include/ecrt.h b/include/ecrt.h index e1a6a1c7..e70d9ed7 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -1049,6 +1049,25 @@ void ecrt_voe_handler_read( 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 --git a/lib/voe_handler.c b/lib/voe_handler.c index 92cc9c67..37986e55 100644 --- a/lib/voe_handler.c +++ b/lib/voe_handler.c @@ -111,6 +111,20 @@ void ecrt_voe_handler_read(ec_voe_handler_t *voe) /*****************************************************************************/ +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 --git a/master/cdev.c b/master/cdev.c index e49d4f89..b1cb9670 100644 --- a/master/cdev.c +++ b/master/cdev.c @@ -2227,6 +2227,45 @@ int ec_cdev_ioctl_voe_read( /*****************************************************************************/ +/** 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 @@ long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 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 --git a/master/ioctl.h b/master/ioctl.h index d7c6102c..da96a7fa 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -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 --git a/master/voe_handler.c b/master/voe_handler.c index 2050c601..bad865f2 100644 --- a/master/voe_handler.c +++ b/master/voe_handler.c @@ -65,6 +65,9 @@ void ec_voe_handler_state_read_start(ec_voe_handler_t *); 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(ec_voe_handler_t *voe) /*****************************************************************************/ +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 @@ void ec_voe_handler_state_read_response(ec_voe_handler_t *voe) /*****************************************************************************/ +/** 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) -- GitLab