mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-02-06 03:41:52 +08:00
Added VoE handler.
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
#define EL3152_ALT_PDOS 0
|
||||
#define EXTERNAL_MEMORY 1
|
||||
#define SDO_ACCESS 0
|
||||
#define VOE_ACCESS 0
|
||||
|
||||
#define PFX "ec_mini: "
|
||||
|
||||
@@ -184,6 +185,10 @@ static ec_sync_info_t el2004_syncs[] = {
|
||||
static ec_sdo_request_t *sdo;
|
||||
#endif
|
||||
|
||||
#if VOE_ACCESS
|
||||
static ec_voe_handler_t *voe;
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void check_domain1_state(void)
|
||||
@@ -249,18 +254,18 @@ void check_slave_config_states(void)
|
||||
void read_sdo(void)
|
||||
{
|
||||
switch (ecrt_sdo_request_state(sdo)) {
|
||||
case EC_SDO_REQUEST_UNUSED: // request was not used yet
|
||||
case EC_REQUEST_UNUSED: // request was not used yet
|
||||
ecrt_sdo_request_read(sdo); // trigger first read
|
||||
break;
|
||||
case EC_SDO_REQUEST_BUSY:
|
||||
case EC_REQUEST_BUSY:
|
||||
printk(KERN_INFO PFX "Still busy...\n");
|
||||
break;
|
||||
case EC_SDO_REQUEST_SUCCESS:
|
||||
case EC_REQUEST_SUCCESS:
|
||||
printk(KERN_INFO PFX "Sdo value: 0x%04X\n",
|
||||
EC_READ_U16(ecrt_sdo_request_data(sdo)));
|
||||
ecrt_sdo_request_read(sdo); // trigger next read
|
||||
break;
|
||||
case EC_SDO_REQUEST_ERROR:
|
||||
case EC_REQUEST_ERROR:
|
||||
printk(KERN_INFO PFX "Failed to read Sdo!\n");
|
||||
ecrt_sdo_request_read(sdo); // retry reading
|
||||
break;
|
||||
@@ -270,6 +275,31 @@ void read_sdo(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#if VOE_ACCESS
|
||||
void read_voe(void)
|
||||
{
|
||||
switch (ecrt_voe_handler_execute(voe)) {
|
||||
case EC_REQUEST_UNUSED:
|
||||
ecrt_voe_handler_read(voe); // trigger first read
|
||||
break;
|
||||
case EC_REQUEST_BUSY:
|
||||
printk(KERN_INFO PFX "VoE read still busy...\n");
|
||||
break;
|
||||
case EC_REQUEST_SUCCESS:
|
||||
printk(KERN_INFO PFX "VoE received.\n");
|
||||
// get data via ecrt_voe_handler_data(voe)
|
||||
ecrt_voe_handler_read(voe); // trigger next read
|
||||
break;
|
||||
case EC_REQUEST_ERROR:
|
||||
printk(KERN_INFO PFX "Failed to read VoE data!\n");
|
||||
ecrt_voe_handler_read(voe); // retry reading
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void cyclic_task(unsigned long data)
|
||||
{
|
||||
// receive process data
|
||||
@@ -299,6 +329,10 @@ void cyclic_task(unsigned long data)
|
||||
// read process data Sdo
|
||||
read_sdo();
|
||||
#endif
|
||||
|
||||
#if VOE_ACCESS
|
||||
read_voe();
|
||||
#endif
|
||||
}
|
||||
|
||||
// write process data
|
||||
@@ -401,6 +435,14 @@ int __init init_mini_module(void)
|
||||
ecrt_sdo_request_timeout(sdo, 500); // ms
|
||||
#endif
|
||||
|
||||
#if VOE_ACCESS
|
||||
printk(KERN_INFO PFX "Creating VoE handlers...\n");
|
||||
if (!(voe = ecrt_slave_config_create_voe_handler(sc_ana_in, 1000))) {
|
||||
printk(KERN_ERR PFX "Failed to create VoE handler.\n");
|
||||
goto out_release_master;
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO PFX "Registering Pdo entries...\n");
|
||||
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
|
||||
printk(KERN_ERR PFX "Pdo entry registration failed!\n");
|
||||
|
||||
100
include/ecrt.h
100
include/ecrt.h
@@ -113,7 +113,7 @@
|
||||
|
||||
/** EtherCAT realtime interface minor version number.
|
||||
*/
|
||||
#define ECRT_VER_MINOR 4
|
||||
#define ECRT_VER_MINOR 5
|
||||
|
||||
/** EtherCAT realtime interface version word generator.
|
||||
*/
|
||||
@@ -151,6 +151,9 @@ typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
|
||||
struct ec_sdo_request;
|
||||
typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */
|
||||
|
||||
struct ec_voe_handler;
|
||||
typedef struct ec_voe_handler ec_voe_handler_t; /**< \see ec_voe_handler. */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Master state.
|
||||
@@ -305,16 +308,17 @@ typedef struct {
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sdo request state.
|
||||
/** Request state.
|
||||
*
|
||||
* This is used as return type of ecrt_sdo_request_state().
|
||||
* This is used as return type for ecrt_sdo_request_state() and
|
||||
* ecrt_voe_handler_state().
|
||||
*/
|
||||
typedef enum {
|
||||
EC_SDO_REQUEST_UNUSED, /**< Not requested. */
|
||||
EC_SDO_REQUEST_BUSY, /**< Request is being processed. */
|
||||
EC_SDO_REQUEST_SUCCESS, /**< Request was processed successfully. */
|
||||
EC_SDO_REQUEST_ERROR, /**< Request processing failed. */
|
||||
} ec_sdo_request_state_t;
|
||||
EC_REQUEST_UNUSED, /**< Not requested. */
|
||||
EC_REQUEST_BUSY, /**< Request is being processed. */
|
||||
EC_REQUEST_SUCCESS, /**< Request was processed successfully. */
|
||||
EC_REQUEST_ERROR, /**< Request processing failed. */
|
||||
} ec_request_state_t;
|
||||
|
||||
/******************************************************************************
|
||||
* Global functions
|
||||
@@ -727,6 +731,17 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
|
||||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Create an VoE handler to exchange vendor-specific data during realtime
|
||||
* operation.
|
||||
*
|
||||
* The created VoE handler object is freed automatically when the master is
|
||||
* released.
|
||||
*/
|
||||
ec_voe_handler_t *ecrt_slave_config_create_voe_handler(
|
||||
ec_slave_config_t *sc, /**< Slave configuration. */
|
||||
size_t size /**< Data size to reserve. */
|
||||
);
|
||||
|
||||
/** Outputs the state of the slave configuration.
|
||||
*
|
||||
* Stores the state information in the given \a state structure.
|
||||
@@ -878,7 +893,7 @@ size_t ecrt_sdo_request_data_size(
|
||||
*
|
||||
* \return Request state.
|
||||
*/
|
||||
ec_sdo_request_state_t ecrt_sdo_request_state(
|
||||
ec_request_state_t ecrt_sdo_request_state(
|
||||
const ec_sdo_request_t *req /**< Sdo request. */
|
||||
);
|
||||
|
||||
@@ -904,6 +919,73 @@ void ecrt_sdo_request_read(
|
||||
ec_sdo_request_t *req /**< Sdo request. */
|
||||
);
|
||||
|
||||
/*****************************************************************************
|
||||
* VoE handler methods.
|
||||
****************************************************************************/
|
||||
|
||||
/** Access to the VoE handler's data.
|
||||
*
|
||||
* This function returns a pointer to the handler's internal memory.
|
||||
*
|
||||
* - After a read operation was successful, the memory contains the received
|
||||
* data. The size of the received data can be determined via
|
||||
* ecrt_voe_handler_data_size().
|
||||
* - Before a write operation is triggered, the data have to be written to
|
||||
* the internal memory. Be sure, that the data fit into the memory. The
|
||||
* memory size is a parameter of ecrt_slave_config_create_voe_handler().
|
||||
*
|
||||
* \return Pointer to the internal memory.
|
||||
*/
|
||||
uint8_t *ecrt_voe_handler_data(
|
||||
ec_voe_handler_t *voe /**< VoE handler. */
|
||||
);
|
||||
|
||||
/** Returns the current data size.
|
||||
*
|
||||
* When the VoE handler is created, the data size is set to the size of the
|
||||
* reserved memory. At a write operation, the data size is set to the number
|
||||
* of bytes to write. After a read operation the size is set to the size of
|
||||
* the read data. The size is not modified in any other situation.
|
||||
*
|
||||
* \return Data size in bytes.
|
||||
*/
|
||||
size_t ecrt_voe_handler_data_size(
|
||||
const ec_voe_handler_t *voe /**< VoE handler. */
|
||||
);
|
||||
|
||||
/** Start a VoE write operation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void ecrt_voe_handler_write(
|
||||
ec_voe_handler_t *voe, /**< VoE handler. */
|
||||
size_t size /**< Number of bytes to write. */
|
||||
);
|
||||
|
||||
/** Start a VoE read operation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* On success, the size of the read data can be determined via
|
||||
* ecrt_voe_handler_data_size().
|
||||
*/
|
||||
void ecrt_voe_handler_read(
|
||||
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
|
||||
* as long as it returns EC_REQUEST_BUSY.
|
||||
*
|
||||
* \return Handler state.
|
||||
*/
|
||||
ec_request_state_t ecrt_voe_handler_execute(
|
||||
ec_voe_handler_t *voe /**< VoE handler. */
|
||||
);
|
||||
|
||||
/******************************************************************************
|
||||
* Bitwise read/write macros
|
||||
*****************************************************************************/
|
||||
|
||||
@@ -61,7 +61,8 @@ ec_master-objs := \
|
||||
slave.o \
|
||||
slave_config.o \
|
||||
sync.o \
|
||||
sync_config.o
|
||||
sync_config.o \
|
||||
voe_handler.o
|
||||
|
||||
ifeq (@ENABLE_EOE@,1)
|
||||
ec_master-objs += ethernet.o
|
||||
|
||||
@@ -64,7 +64,8 @@ noinst_HEADERS = \
|
||||
slave.c slave.h \
|
||||
slave_config.c slave_config.h \
|
||||
sync.c sync.h \
|
||||
sync_config.c sync_config.h
|
||||
sync_config.c sync_config.h \
|
||||
voe_handler.c voe_handler.h
|
||||
|
||||
BUILT_SOURCES = \
|
||||
Kbuild
|
||||
|
||||
@@ -726,10 +726,10 @@ int ec_cdev_ioctl_slave_sdo_upload(
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->sdo_queue,
|
||||
request.req.state != EC_REQUEST_QUEUED)) {
|
||||
request.req.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
if (request.req.state == EC_REQUEST_QUEUED) {
|
||||
if (request.req.state == EC_INT_REQUEST_QUEUED) {
|
||||
list_del(&request.req.list);
|
||||
up(&master->master_sem);
|
||||
ec_sdo_request_clear(&request.req);
|
||||
@@ -740,11 +740,11 @@ int ec_cdev_ioctl_slave_sdo_upload(
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY);
|
||||
wait_event(master->sdo_queue, request.req.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
data.abort_code = request.req.abort_code;
|
||||
|
||||
if (request.req.state != EC_REQUEST_SUCCESS) {
|
||||
if (request.req.state != EC_INT_REQUEST_SUCCESS) {
|
||||
data.data_size = 0;
|
||||
retval = -EIO;
|
||||
} else {
|
||||
@@ -828,10 +828,10 @@ int ec_cdev_ioctl_slave_sdo_download(
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->sdo_queue,
|
||||
request.req.state != EC_REQUEST_QUEUED)) {
|
||||
request.req.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
if (request.req.state == EC_REQUEST_QUEUED) {
|
||||
if (request.req.state == EC_INT_REQUEST_QUEUED) {
|
||||
list_del(&request.req.list);
|
||||
up(&master->master_sem);
|
||||
ec_sdo_request_clear(&request.req);
|
||||
@@ -842,11 +842,11 @@ int ec_cdev_ioctl_slave_sdo_download(
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY);
|
||||
wait_event(master->sdo_queue, request.req.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
data.abort_code = request.req.abort_code;
|
||||
|
||||
retval = request.req.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
|
||||
if (__copy_to_user((void __user *) arg, &data, sizeof(data))) {
|
||||
retval = -EFAULT;
|
||||
@@ -954,7 +954,7 @@ int ec_cdev_ioctl_slave_sii_write(
|
||||
request.words = words;
|
||||
request.offset = data.offset;
|
||||
request.nwords = data.nwords;
|
||||
request.state = EC_REQUEST_QUEUED;
|
||||
request.state = EC_INT_REQUEST_QUEUED;
|
||||
|
||||
// schedule SII write request.
|
||||
list_add_tail(&request.list, &master->sii_requests);
|
||||
@@ -963,10 +963,10 @@ int ec_cdev_ioctl_slave_sii_write(
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->sii_queue,
|
||||
request.state != EC_REQUEST_QUEUED)) {
|
||||
request.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
if (request.state == EC_REQUEST_QUEUED) {
|
||||
if (request.state == EC_INT_REQUEST_QUEUED) {
|
||||
// abort request
|
||||
list_del(&request.list);
|
||||
up(&master->master_sem);
|
||||
@@ -977,11 +977,11 @@ int ec_cdev_ioctl_slave_sii_write(
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->sii_queue, request.state != EC_REQUEST_BUSY);
|
||||
wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
kfree(words);
|
||||
|
||||
return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1027,7 +1027,7 @@ int ec_cdev_ioctl_slave_phy_read(
|
||||
request.data = contents;
|
||||
request.offset = data.offset;
|
||||
request.length = data.length;
|
||||
request.state = EC_REQUEST_QUEUED;
|
||||
request.state = EC_INT_REQUEST_QUEUED;
|
||||
|
||||
// schedule request.
|
||||
list_add_tail(&request.list, &master->phy_requests);
|
||||
@@ -1036,10 +1036,10 @@ int ec_cdev_ioctl_slave_phy_read(
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->phy_queue,
|
||||
request.state != EC_REQUEST_QUEUED)) {
|
||||
request.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
if (request.state == EC_REQUEST_QUEUED) {
|
||||
if (request.state == EC_INT_REQUEST_QUEUED) {
|
||||
// abort request
|
||||
list_del(&request.list);
|
||||
up(&master->master_sem);
|
||||
@@ -1050,15 +1050,15 @@ int ec_cdev_ioctl_slave_phy_read(
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->phy_queue, request.state != EC_REQUEST_BUSY);
|
||||
wait_event(master->phy_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
if (request.state == EC_REQUEST_SUCCESS) {
|
||||
if (request.state == EC_INT_REQUEST_SUCCESS) {
|
||||
if (copy_to_user((void __user *) data.data, contents, data.length))
|
||||
return -EFAULT;
|
||||
}
|
||||
kfree(contents);
|
||||
|
||||
return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1110,7 +1110,7 @@ int ec_cdev_ioctl_slave_phy_write(
|
||||
request.data = contents;
|
||||
request.offset = data.offset;
|
||||
request.length = data.length;
|
||||
request.state = EC_REQUEST_QUEUED;
|
||||
request.state = EC_INT_REQUEST_QUEUED;
|
||||
|
||||
// schedule request.
|
||||
list_add_tail(&request.list, &master->phy_requests);
|
||||
@@ -1119,10 +1119,10 @@ int ec_cdev_ioctl_slave_phy_write(
|
||||
|
||||
// wait for processing through FSM
|
||||
if (wait_event_interruptible(master->phy_queue,
|
||||
request.state != EC_REQUEST_QUEUED)) {
|
||||
request.state != EC_INT_REQUEST_QUEUED)) {
|
||||
// interrupted by signal
|
||||
down(&master->master_sem);
|
||||
if (request.state == EC_REQUEST_QUEUED) {
|
||||
if (request.state == EC_INT_REQUEST_QUEUED) {
|
||||
// abort request
|
||||
list_del(&request.list);
|
||||
up(&master->master_sem);
|
||||
@@ -1133,11 +1133,11 @@ int ec_cdev_ioctl_slave_phy_write(
|
||||
}
|
||||
|
||||
// wait until master FSM has finished processing
|
||||
wait_event(master->phy_queue, request.state != EC_REQUEST_BUSY);
|
||||
wait_event(master->phy_queue, request.state != EC_INT_REQUEST_BUSY);
|
||||
|
||||
kfree(contents);
|
||||
|
||||
return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
#include "../devices/ecdev.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "slave.h"
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "datagram.h"
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
#ifndef __EC_FMMU_CONFIG_H__
|
||||
#define __EC_FMMU_CONFIG_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "sync.h"
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#define __EC_FSM_CHANGE_H__
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#define __EC_FSM_COE_H__
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
#include "sdo.h"
|
||||
|
||||
@@ -305,7 +305,7 @@ int ec_fsm_master_action_process_sii(
|
||||
request = list_entry(master->sii_requests.next,
|
||||
ec_sii_write_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
request->state = EC_REQUEST_BUSY;
|
||||
request->state = EC_INT_REQUEST_BUSY;
|
||||
|
||||
// found pending SII write operation. execute it!
|
||||
if (master->debug_level)
|
||||
@@ -345,7 +345,7 @@ int ec_fsm_master_action_process_phy(
|
||||
request = list_entry(master->phy_requests.next,
|
||||
ec_phy_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
request->state = EC_REQUEST_BUSY;
|
||||
request->state = EC_INT_REQUEST_BUSY;
|
||||
|
||||
// found pending request; process it!
|
||||
if (master->debug_level)
|
||||
@@ -360,7 +360,7 @@ int ec_fsm_master_action_process_phy(
|
||||
if (request->length > fsm->datagram->mem_size) {
|
||||
EC_ERR("Request length (%u) exceeds maximum datagram size (%u)!\n",
|
||||
request->length, fsm->datagram->mem_size);
|
||||
request->state = EC_REQUEST_FAILURE;
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->phy_queue);
|
||||
continue;
|
||||
}
|
||||
@@ -398,10 +398,10 @@ int ec_fsm_master_action_process_sdo(
|
||||
if (!slave->config)
|
||||
continue;
|
||||
list_for_each_entry(req, &slave->config->sdo_requests, list) {
|
||||
if (req->state == EC_REQUEST_QUEUED) {
|
||||
if (req->state == EC_INT_REQUEST_QUEUED) {
|
||||
|
||||
if (ec_sdo_request_timed_out(req)) {
|
||||
req->state = EC_REQUEST_FAILURE;
|
||||
req->state = EC_INT_REQUEST_FAILURE;
|
||||
if (master->debug_level)
|
||||
EC_DBG("Sdo request for slave %u timed out...\n",
|
||||
slave->ring_position);
|
||||
@@ -409,11 +409,11 @@ int ec_fsm_master_action_process_sdo(
|
||||
}
|
||||
|
||||
if (slave->current_state == EC_SLAVE_STATE_INIT) {
|
||||
req->state = EC_REQUEST_FAILURE;
|
||||
req->state = EC_INT_REQUEST_FAILURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
req->state = EC_REQUEST_BUSY;
|
||||
req->state = EC_INT_REQUEST_BUSY;
|
||||
if (master->debug_level)
|
||||
EC_DBG("Processing Sdo request for slave %u...\n",
|
||||
slave->ring_position);
|
||||
@@ -438,13 +438,13 @@ int ec_fsm_master_action_process_sdo(
|
||||
request = list_entry(master->slave_sdo_requests.next,
|
||||
ec_master_sdo_request_t, list);
|
||||
list_del_init(&request->list); // dequeue
|
||||
request->req.state = EC_REQUEST_BUSY;
|
||||
request->req.state = EC_INT_REQUEST_BUSY;
|
||||
|
||||
slave = request->slave;
|
||||
if (slave->current_state == EC_SLAVE_STATE_INIT) {
|
||||
EC_ERR("Discarding Sdo request, slave %u is in INIT.\n",
|
||||
slave->ring_position);
|
||||
request->req.state = EC_REQUEST_FAILURE;
|
||||
request->req.state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->sdo_queue);
|
||||
continue;
|
||||
}
|
||||
@@ -812,7 +812,7 @@ void ec_fsm_master_state_write_sii(
|
||||
if (!ec_fsm_sii_success(&fsm->fsm_sii)) {
|
||||
EC_ERR("Failed to write SII data to slave %u.\n",
|
||||
slave->ring_position);
|
||||
request->state = EC_REQUEST_FAILURE;
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->sii_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
@@ -839,7 +839,7 @@ void ec_fsm_master_state_write_sii(
|
||||
}
|
||||
// TODO: Evaluate other SII contents!
|
||||
|
||||
request->state = EC_REQUEST_SUCCESS;
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
wake_up(&master->sii_queue);
|
||||
|
||||
// check for another SII write request
|
||||
@@ -898,14 +898,14 @@ void ec_fsm_master_state_sdo_request(
|
||||
if (!ec_fsm_coe_success(&fsm->fsm_coe)) {
|
||||
EC_DBG("Failed to process Sdo request for slave %u.\n",
|
||||
fsm->slave->ring_position);
|
||||
request->state = EC_REQUEST_FAILURE;
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->sdo_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sdo request finished
|
||||
request->state = EC_REQUEST_SUCCESS;
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
wake_up(&master->sdo_queue);
|
||||
|
||||
if (master->debug_level)
|
||||
@@ -934,7 +934,7 @@ void ec_fsm_master_state_phy_request(
|
||||
if (datagram->state != EC_DATAGRAM_RECEIVED) {
|
||||
EC_ERR("Failed to receive phy request datagram (state %u).\n",
|
||||
datagram->state);
|
||||
request->state = EC_REQUEST_FAILURE;
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->phy_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
@@ -947,7 +947,7 @@ void ec_fsm_master_state_phy_request(
|
||||
if (!request->data) {
|
||||
EC_ERR("Failed to allocate %u bytes of memory for phy request.\n",
|
||||
request->length);
|
||||
request->state = EC_REQUEST_FAILURE;
|
||||
request->state = EC_INT_REQUEST_FAILURE;
|
||||
wake_up(&master->phy_queue);
|
||||
ec_fsm_master_restart(fsm);
|
||||
return;
|
||||
@@ -955,7 +955,7 @@ void ec_fsm_master_state_phy_request(
|
||||
memcpy(request->data, datagram->data, request->length);
|
||||
}
|
||||
|
||||
request->state = EC_REQUEST_SUCCESS;
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
wake_up(&master->phy_queue);
|
||||
|
||||
// check for another PHY request
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#ifndef __EC_FSM_MASTER_H__
|
||||
#define __EC_FSM_MASTER_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "sdo_request.h"
|
||||
@@ -60,7 +58,7 @@ typedef struct {
|
||||
uint16_t offset; /**< SII word offset. */
|
||||
size_t nwords; /**< Number of words. */
|
||||
const uint16_t *words; /**< Pointer to the data words. */
|
||||
ec_request_state_t state; /**< State of the request. */
|
||||
ec_internal_request_state_t state; /**< State of the request. */
|
||||
} ec_sii_write_request_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -74,7 +72,7 @@ typedef struct {
|
||||
uint16_t offset; /**< Physical memory offset. */
|
||||
size_t length; /**< Number of bytes. */
|
||||
uint8_t *data;
|
||||
ec_request_state_t state; /**< State of the request. */
|
||||
ec_internal_request_state_t state; /**< State of the request. */
|
||||
} ec_phy_request_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#ifndef __EC_FSM_PDO_H__
|
||||
#define __EC_FSM_PDO_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "fsm_coe.h"
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#define __EC_FSM_PDO_ENTRY_H__
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "fsm_coe.h"
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#define __EC_FSM_SII_H__
|
||||
|
||||
#include "globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#ifndef __EC_FSM_SLAVE_CONFIG_H__
|
||||
#define __EC_FSM_SLAVE_CONFIG_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "datagram.h"
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#ifndef __EC_FSM_SLAVE_SCAN_H__
|
||||
#define __EC_FSM_SLAVE_SCAN_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "slave.h"
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
/******************************************************************************
|
||||
* EtherCAT master
|
||||
@@ -253,12 +254,16 @@ typedef struct {
|
||||
* state_table in master/sdo_request.c.
|
||||
*/
|
||||
typedef enum {
|
||||
EC_REQUEST_INIT,
|
||||
EC_REQUEST_QUEUED,
|
||||
EC_REQUEST_BUSY,
|
||||
EC_REQUEST_SUCCESS,
|
||||
EC_REQUEST_FAILURE
|
||||
} ec_request_state_t;
|
||||
EC_INT_REQUEST_INIT,
|
||||
EC_INT_REQUEST_QUEUED,
|
||||
EC_INT_REQUEST_BUSY,
|
||||
EC_INT_REQUEST_SUCCESS,
|
||||
EC_INT_REQUEST_FAILURE
|
||||
} ec_internal_request_state_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
extern const ec_request_state_t ec_request_state_translation_table[];
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "slave_config.h"
|
||||
|
||||
@@ -545,6 +545,20 @@ unsigned int ecrt_version_magic(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Global request state type translation table.
|
||||
*
|
||||
* Translates an internal request state to an external one.
|
||||
*/
|
||||
const ec_request_state_t ec_request_state_translation_table[] = {
|
||||
EC_REQUEST_UNUSED, // EC_INT_REQUEST_INIT,
|
||||
EC_REQUEST_BUSY, // EC_INT_REQUEST_QUEUED,
|
||||
EC_REQUEST_BUSY, // EC_INT_REQUEST_BUSY,
|
||||
EC_REQUEST_SUCCESS, // EC_INT_REQUEST_SUCCESS,
|
||||
EC_REQUEST_ERROR // EC_INT_REQUEST_FAILURE
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
module_init(ec_init_module);
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo_entry.h"
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo.h"
|
||||
|
||||
|
||||
@@ -54,18 +54,6 @@ void ec_sdo_request_clear_data(ec_sdo_request_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** State type translation table.
|
||||
*/
|
||||
static const ec_sdo_request_state_t state_translation_table[] = {
|
||||
EC_SDO_REQUEST_UNUSED, // EC_REQUEST_INIT,
|
||||
EC_SDO_REQUEST_BUSY, // EC_REQUEST_QUEUED,
|
||||
EC_SDO_REQUEST_BUSY, // EC_REQUEST_BUSY,
|
||||
EC_SDO_REQUEST_SUCCESS, // EC_REQUEST_SUCCESS,
|
||||
EC_SDO_REQUEST_ERROR // EC_REQUEST_FAILURE
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Sdo request constructor.
|
||||
*/
|
||||
void ec_sdo_request_init(
|
||||
@@ -78,7 +66,7 @@ void ec_sdo_request_init(
|
||||
req->dir = EC_DIR_INVALID;
|
||||
req->issue_timeout = 0; // no timeout
|
||||
req->response_timeout = EC_SDO_REQUEST_RESPONSE_TIMEOUT;
|
||||
req->state = EC_REQUEST_INIT;
|
||||
req->state = EC_INT_REQUEST_INIT;
|
||||
req->abort_code = 0x00000000;
|
||||
}
|
||||
|
||||
@@ -207,9 +195,9 @@ size_t ecrt_sdo_request_data_size(const ec_sdo_request_t *req)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_sdo_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
|
||||
ec_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
|
||||
{
|
||||
return state_translation_table[req->state];
|
||||
return ec_request_state_translation_table[req->state];
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -217,7 +205,7 @@ ec_sdo_request_state_t ecrt_sdo_request_state(const ec_sdo_request_t *req)
|
||||
void ecrt_sdo_request_read(ec_sdo_request_t *req)
|
||||
{
|
||||
req->dir = EC_DIR_INPUT;
|
||||
req->state = EC_REQUEST_QUEUED;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
req->abort_code = 0x00000000;
|
||||
req->jiffies_start = jiffies;
|
||||
}
|
||||
@@ -227,7 +215,7 @@ void ecrt_sdo_request_read(ec_sdo_request_t *req)
|
||||
void ecrt_sdo_request_write(ec_sdo_request_t *req)
|
||||
{
|
||||
req->dir = EC_DIR_OUTPUT;
|
||||
req->state = EC_REQUEST_QUEUED;
|
||||
req->state = EC_INT_REQUEST_QUEUED;
|
||||
req->abort_code = 0x00000000;
|
||||
req->jiffies_start = jiffies;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -65,7 +63,7 @@ struct ec_sdo_request {
|
||||
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means downloading to
|
||||
the slave, EC_DIR_INPUT means uploading from the
|
||||
slave. */
|
||||
ec_request_state_t state; /**< Sdo request state. */
|
||||
ec_internal_request_state_t state; /**< Sdo request state. */
|
||||
unsigned long jiffies_start; /**< Jiffies, when the request was issued. */
|
||||
unsigned long jiffies_sent; /**< Jiffies, when the upload/download
|
||||
request was sent. */
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
#include "pdo.h"
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include "globals.h"
|
||||
#include "master.h"
|
||||
#include "voe_handler.h"
|
||||
|
||||
#include "slave_config.h"
|
||||
|
||||
@@ -75,6 +76,7 @@ void ec_slave_config_init(
|
||||
|
||||
INIT_LIST_HEAD(&sc->sdo_configs);
|
||||
INIT_LIST_HEAD(&sc->sdo_requests);
|
||||
INIT_LIST_HEAD(&sc->voe_handlers);
|
||||
|
||||
sc->used_fmmus = 0;
|
||||
}
|
||||
@@ -91,6 +93,7 @@ void ec_slave_config_clear(
|
||||
{
|
||||
unsigned int i;
|
||||
ec_sdo_request_t *req, *next_req;
|
||||
ec_voe_handler_t *voe, *next_voe;
|
||||
|
||||
ec_slave_config_detach(sc);
|
||||
|
||||
@@ -111,6 +114,13 @@ void ec_slave_config_clear(
|
||||
ec_sdo_request_clear(req);
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
// free all VoE handlers
|
||||
list_for_each_entry_safe(voe, next_voe, &sc->voe_handlers, list) {
|
||||
list_del(&voe->list);
|
||||
ec_voe_handler_clear(voe);
|
||||
kfree(voe);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -742,6 +752,35 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_voe_handler_t *ecrt_slave_config_create_voe_handler(ec_slave_config_t *sc,
|
||||
size_t size)
|
||||
{
|
||||
ec_voe_handler_t *voe;
|
||||
|
||||
if (sc->master->debug_level)
|
||||
EC_DBG("ecrt_slave_config_create_voe_handler(sc = 0x%x, size = %u)\n",
|
||||
(u32) sc, size);
|
||||
|
||||
if (!(voe = (ec_voe_handler_t *)
|
||||
kmalloc(sizeof(ec_voe_handler_t), GFP_KERNEL))) {
|
||||
EC_ERR("Failed to allocate Sdo request memory!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ec_voe_handler_init(voe, sc, size)) {
|
||||
kfree(voe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
down(&sc->master->master_sem);
|
||||
list_add_tail(&voe->list, &sc->voe_handlers);
|
||||
up(&sc->master->master_sem);
|
||||
|
||||
return voe;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_slave_config_state(const ec_slave_config_t *sc,
|
||||
ec_slave_config_state_t *state)
|
||||
{
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "slave.h"
|
||||
#include "sync_config.h"
|
||||
@@ -74,7 +72,7 @@ struct ec_slave_config {
|
||||
|
||||
struct list_head sdo_configs; /**< List of Sdo configurations. */
|
||||
struct list_head sdo_requests; /**< List of Sdo requests. */
|
||||
|
||||
struct list_head voe_handlers; /**< List of VoE handlers. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
#ifndef __EC_SYNC_H__
|
||||
#define __EC_SYNC_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo_list.h"
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
#ifndef __EC_SYNC_CONFIG_H__
|
||||
#define __EC_SYNC_CONFIG_H__
|
||||
|
||||
#include "../include/ecrt.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "pdo_list.h"
|
||||
|
||||
|
||||
386
master/voe_handler.c
Normal file
386
master/voe_handler.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/** \file
|
||||
* Vendor-specific-over-EtherCAT protocol handler functions.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "master.h"
|
||||
#include "slave_config.h"
|
||||
#include "mailbox.h"
|
||||
#include "voe_handler.h"
|
||||
|
||||
/** VoE response timeout in [ms].
|
||||
*/
|
||||
#define EC_VOE_RESPONSE_TIMEOUT 500
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_clear_data(ec_voe_handler_t *);
|
||||
|
||||
void ec_voe_handler_state_write_start(ec_voe_handler_t *);
|
||||
void ec_voe_handler_state_write_response(ec_voe_handler_t *);
|
||||
|
||||
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_end(ec_voe_handler_t *);
|
||||
void ec_voe_handler_state_error(ec_voe_handler_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** VoE handler constructor.
|
||||
*/
|
||||
int ec_voe_handler_init(
|
||||
ec_voe_handler_t *voe, /**< VoE handler. */
|
||||
ec_slave_config_t *sc, /**< Parent slave configuration. */
|
||||
size_t size /**< Size of memory to reserve. */
|
||||
)
|
||||
{
|
||||
voe->config = sc;
|
||||
voe->data_size = 0;
|
||||
voe->dir = EC_DIR_INVALID;
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_INIT;
|
||||
|
||||
ec_datagram_init(&voe->datagram);
|
||||
if (ec_datagram_prealloc(&voe->datagram, size + 6))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** VoE handler destructor.
|
||||
*/
|
||||
void ec_voe_handler_clear(
|
||||
ec_voe_handler_t *voe /**< VoE handler. */
|
||||
)
|
||||
{
|
||||
ec_datagram_clear(&voe->datagram);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Application interface.
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t *ecrt_voe_handler_data(ec_voe_handler_t *voe)
|
||||
{
|
||||
return voe->datagram.data + 6;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
size_t ecrt_voe_handler_data_size(const ec_voe_handler_t *voe)
|
||||
{
|
||||
return voe->data_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ecrt_voe_handler_read(ec_voe_handler_t *voe)
|
||||
{
|
||||
voe->dir = EC_DIR_INPUT;
|
||||
voe->state = ec_voe_handler_state_read_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;
|
||||
voe->datagram.data_size = size + 6;
|
||||
voe->state = ec_voe_handler_state_write_start;
|
||||
voe->request_state = EC_INT_REQUEST_QUEUED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
ec_request_state_t ecrt_voe_handler_execute(ec_voe_handler_t *voe)
|
||||
{
|
||||
if (voe->config->slave) {
|
||||
voe->state(voe);
|
||||
if (voe->request_state == EC_REQUEST_BUSY)
|
||||
ec_master_queue_datagram(voe->config->master, &voe->datagram);
|
||||
} else {
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
}
|
||||
|
||||
return ec_request_state_translation_table[voe->request_state];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* State functions.
|
||||
*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_write_start(ec_voe_handler_t *voe)
|
||||
{
|
||||
ec_slave_t *slave = voe->config->slave;
|
||||
uint8_t *data;
|
||||
|
||||
if (slave->master->debug_level) {
|
||||
EC_DBG("Writing %u bytes of VoE data to slave %u.\n",
|
||||
voe->data_size, slave->ring_position);
|
||||
ec_print_data(ecrt_voe_handler_data(voe), voe->data_size);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(data = ec_slave_mbox_prepare_send(
|
||||
slave, &voe->datagram, 0x01, voe->data_size))) {
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
voe->retries = EC_FSM_RETRIES;
|
||||
voe->jiffies_start = jiffies;
|
||||
voe->state = ec_voe_handler_state_write_response;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_write_response(ec_voe_handler_t *voe)
|
||||
{
|
||||
ec_datagram_t *datagram = &voe->datagram;
|
||||
ec_slave_t *slave = voe->config->slave;
|
||||
|
||||
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 write request datagram for"
|
||||
" slave %u (datagram state %u).\n",
|
||||
slave->ring_position, datagram->state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
if (!datagram->working_counter) {
|
||||
unsigned long diff_ms =
|
||||
(jiffies - voe->jiffies_start) * 1000 / HZ;
|
||||
if (diff_ms < EC_VOE_RESPONSE_TIMEOUT) {
|
||||
if (slave->master->debug_level) {
|
||||
EC_DBG("Slave %u did not respond to VoE write request. "
|
||||
"Retrying after %u ms...\n",
|
||||
slave->ring_position, (u32) diff_ms);
|
||||
}
|
||||
// no response; send request datagram again
|
||||
return;
|
||||
}
|
||||
}
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
EC_ERR("Reception of VoE write request failed on slave %u: ",
|
||||
slave->ring_position);
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (voe->config->master->debug_level)
|
||||
EC_DBG("VoE write request successful.\n");
|
||||
|
||||
voe->request_state = EC_INT_REQUEST_SUCCESS;
|
||||
voe->state = ec_voe_handler_state_end;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_read_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_check(slave, datagram); // can not fail.
|
||||
|
||||
voe->jiffies_start = jiffies;
|
||||
voe->retries = EC_FSM_RETRIES;
|
||||
voe->state = ec_voe_handler_state_read_check;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_read_check(ec_voe_handler_t *voe)
|
||||
{
|
||||
ec_datagram_t *datagram = &voe->datagram;
|
||||
ec_slave_t *slave = voe->config->slave;
|
||||
|
||||
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 mailbox check datagram from slave %u"
|
||||
" (datagram state %u).\n",
|
||||
slave->ring_position, datagram->state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (datagram->working_counter != 1) {
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
EC_ERR("Reception of VoE mailbox check"
|
||||
" datagram failed on slave %u: ", slave->ring_position);
|
||||
ec_datagram_print_wc_error(datagram);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ec_slave_mbox_check(datagram)) {
|
||||
unsigned long diff_ms =
|
||||
(datagram->jiffies_received - voe->jiffies_start) * 1000 / HZ;
|
||||
if (diff_ms >= EC_VOE_RESPONSE_TIMEOUT) {
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
EC_ERR("Timeout while waiting for VoE data on "
|
||||
"slave %u.\n", slave->ring_position);
|
||||
return;
|
||||
}
|
||||
|
||||
ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
|
||||
voe->retries = EC_FSM_RETRIES;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch response
|
||||
ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
|
||||
voe->retries = EC_FSM_RETRIES;
|
||||
voe->state = ec_voe_handler_state_read_response;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_read_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 != 1) {
|
||||
voe->state = ec_voe_handler_state_error;
|
||||
voe->request_state = EC_INT_REQUEST_FAILURE;
|
||||
EC_ERR("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 != 0x01) { // 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 (master->debug_level) {
|
||||
EC_DBG("VoE data:\n");
|
||||
ec_print_data(data, rec_size);
|
||||
}
|
||||
|
||||
voe->data_size = rec_size;
|
||||
voe->request_state = EC_INT_REQUEST_SUCCESS;
|
||||
voe->state = ec_voe_handler_state_end; // success
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_end(ec_voe_handler_t *voe)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ec_voe_handler_state_error(ec_voe_handler_t *voe)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** \cond */
|
||||
|
||||
EXPORT_SYMBOL(ecrt_voe_handler_data);
|
||||
EXPORT_SYMBOL(ecrt_voe_handler_data_size);
|
||||
EXPORT_SYMBOL(ecrt_voe_handler_read);
|
||||
EXPORT_SYMBOL(ecrt_voe_handler_write);
|
||||
EXPORT_SYMBOL(ecrt_voe_handler_execute);
|
||||
|
||||
/** \endcond */
|
||||
|
||||
/*****************************************************************************/
|
||||
74
master/voe_handler.h
Normal file
74
master/voe_handler.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
* The IgH EtherCAT Master is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The IgH EtherCAT Master is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The right to use EtherCAT Technology is granted and comes free of
|
||||
* charge under condition of compatibility of product made by
|
||||
* Licensee. People intending to distribute/sell products based on the
|
||||
* code, have to sign an agreement to guarantee that products using
|
||||
* software based on IgH EtherCAT master stay compatible with the actual
|
||||
* EtherCAT specification (which are released themselves as an open
|
||||
* standard) as the (only) precondition to have the right to use EtherCAT
|
||||
* Technology, IP and trade marks.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
\file
|
||||
Vendor-specific-over-EtherCAT protocol handler.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef __EC_VOE_HANDLER_H__
|
||||
#define __EC_VOE_HANDLER_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "datagram.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Vendor-specific-over-EtherCAT handler.
|
||||
*/
|
||||
struct ec_voe_handler {
|
||||
struct list_head list; /**< List item. */
|
||||
ec_slave_config_t *config; /**< Parent slave configuration. */
|
||||
ec_datagram_t datagram; /**< State machine datagram. */
|
||||
size_t data_size; /**< Size of Sdo data. */
|
||||
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to
|
||||
the slave, EC_DIR_INPUT means reading from the
|
||||
slave. */
|
||||
void (*state)(ec_voe_handler_t *); /**< State function */
|
||||
ec_internal_request_state_t request_state; /**< Handler state. */
|
||||
unsigned int retries; /**< retries upon datagram timeout */
|
||||
unsigned long jiffies_start; /**< Timestamp for timeout calculation. */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int ec_voe_handler_init(ec_voe_handler_t *, ec_slave_config_t *, size_t);
|
||||
void ec_voe_handler_clear(ec_voe_handler_t *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user