Dear Etherlab users,

I have a setup with some Elmo Gold boards where I wish to access some data
objects that unfortunately are not mappable. The information from these
data objects is not really required each cycle, though it should be
requested regularly.

I'm attaching a sample test code where I try to read the same data object
in three different slaves each cycle. The result is that the sdo request
for the third slave is never successful.

It is as if the master could not serve more than one SDO request at a time.
Is this correct? I am doing something wrong?

Kinds regards.

Jordán.
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h> /* clock_gettime() */
#include <sys/mman.h> /* mlockall() */

/****************************************************************************/

#include "ecrt.h"

/****************************************************************************/

/** Task period in ns. */
#define PERIOD_NS   (1000000)

#define MAX_SAFE_STACK (8 * 1024) /* The maximum stack size which is
                                     guranteed safe to access without
                                     faulting */

/****************************************************************************/

/* Constants */
#define NSEC_PER_SEC (1000000000)
#define FREQUENCY (NSEC_PER_SEC / PERIOD_NS)

/****************************************************************************/

// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};

static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};

/****************************************************************************/

// process data
static uint8_t *domain1_pd = NULL;

#define Slave1AliasPos 0, 0
#define Slave2AliasPos 0, 1
#define Slave3AliasPos 0, 2
#define Slave4AliasPos 0, 3

#define Slave1VendorProduct 0x0000009a, 0x00030924
#define Slave2VendorProduct 0x0000009a, 0x00030924
#define Slave3VendorProduct 0x0000009a, 0x00030924
#define Slave4VendorProduct 0x0000009a, 0x00030924

/*****************************************************************************/

static ec_sdo_request_t *sdo_1;
static ec_sdo_request_t *sdo_2;
static ec_sdo_request_t *sdo_3;

/*****************************************************************************/

void read_sdo(const char* name, ec_sdo_request_t *sdo)
{
    switch (ecrt_sdo_request_state(sdo)) {
        case EC_REQUEST_UNUSED: // request was not used yet
            ecrt_sdo_request_read(sdo); // trigger first read
            break;
        case EC_REQUEST_BUSY:
            printf("%s still busy...\n", name);
            break;
        case EC_REQUEST_SUCCESS:
            printf("%s value: 0x%04X\n", name,
                    EC_READ_U16(ecrt_sdo_request_data(sdo)));
            ecrt_sdo_request_read(sdo); // trigger next read
            break;
        case EC_REQUEST_ERROR:
            printf("%s failed to read!\n", name);
            ecrt_sdo_request_read(sdo); // retry reading
            break;
    }
}

/*****************************************************************************/

void cyclic_task()
{
    // receive process data
    ecrt_master_receive(master);
    ecrt_domain_process(domain1);

    read_sdo("SDO1", sdo_1);
    read_sdo("SDO2", sdo_2);
    read_sdo("SDO3", sdo_3);
    printf("\n");

    // send process data
    ecrt_domain_queue(domain1);
    ecrt_master_send(master);
}

/****************************************************************************/

void stack_prefault(void)
{
    unsigned char dummy[MAX_SAFE_STACK];

    memset(dummy, 0, MAX_SAFE_STACK);
}

/****************************************************************************/

int main(int argc, char **argv)
{
    ec_slave_config_t *sc1, *sc2, *sc3;
    struct timespec wakeup_time;
    int ret = 0;

    master = ecrt_request_master(0);
    if (!master) {
        return -1;
    }

    domain1 = ecrt_master_create_domain(master);
    if (!domain1) {
        return -1;
    }

    // Create slave configurations
    sc1 = ecrt_master_slave_config(master, Slave1AliasPos, Slave1VendorProduct);
    if (!sc1) {
        return -1;
    }

    sc2 = ecrt_master_slave_config(master, Slave2AliasPos, Slave2VendorProduct);
    if (!sc2) {
        return -1;
    }

    sc3 = ecrt_master_slave_config(master, Slave3AliasPos, Slave3VendorProduct);
    if (!sc3) {
        return -1;
    }

    // Create SDO requests
    // 0x22A3 = DriveTemperature
    if (!(sdo_1 = ecrt_slave_config_create_sdo_request(sc1, 0x22A3, 1, 2)) ||
        !(sdo_2 = ecrt_slave_config_create_sdo_request(sc2, 0x22A3, 1, 2)) ||
        !(sdo_3 = ecrt_slave_config_create_sdo_request(sc3, 0x22A3, 1, 2)))
    {
        printf("Failed to create SDO requests.\n");
        return -1;
    }

    ecrt_sdo_request_timeout(sdo_1, 500); // ms
    ecrt_sdo_request_timeout(sdo_2, 500); // ms
    ecrt_sdo_request_timeout(sdo_3, 500); // ms

    printf("Activating master...\n");
    if (ecrt_master_activate(master)) {
        return -1;
    }

    /* Set priority */

    pid_t pid = getpid();
    if (setpriority(PRIO_PROCESS, pid, -19)) {
        fprintf(stderr, "Warning: Failed to set priority: %s\n",
                strerror(errno));
    }

    /* Lock memory */

    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
        fprintf(stderr, "Warning: Failed to lock memory: %s\n",
                strerror(errno));
    }

    stack_prefault();

    printf("Starting RT task with dt=%u ns.\n", PERIOD_NS);

    clock_gettime(CLOCK_MONOTONIC, &wakeup_time);
    wakeup_time.tv_sec += 1; /* start in future */
    wakeup_time.tv_nsec = 0;

    while (1) {
        ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
                &wakeup_time, NULL);
        if (ret) {
            fprintf(stderr, "clock_nanosleep(): %s\n", strerror(ret));
            break;
        }

        cyclic_task();

        wakeup_time.tv_nsec += PERIOD_NS;
        while (wakeup_time.tv_nsec >= NSEC_PER_SEC) {
            wakeup_time.tv_nsec -= NSEC_PER_SEC;
            wakeup_time.tv_sec++;
        }
    }

    return ret;
}

/****************************************************************************/
_______________________________________________
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to