// Channel Access callback
// Each subscription monitor or 'get' callback goes here:
void ProcessVariable::value_callback(struct event_handler_args arg)
{
    ProcessVariable *me = (ProcessVariable *) ca_puser(arg.chid);
    LOG_ASSERT(me != 0);
    // Check if there is a useful value at all.
    if (arg.status != ECA_NORMAL)
    {
        LOG_MSG("ProcessVariable(%s) value_callback failed: %s\n",
                me->getName().c_str(),  ca_message(arg.status));
        return;
    }
    const RawValue::Data *value = (const RawValue::Data *)arg.dbr;
    LOG_ASSERT(value != 0);
    // Catch records that never processed and give null times.
    if (value->stamp.secPastEpoch == 0)
    {
        nulltime_throttle.LOG_MSG("ProcessVariable::value_callback(%s) "
            "with invalid null timestamp\n", me->getName().c_str());
        return;
    }
    // Check the nanoseconds of each incoming value. Problems will arise later
    // unless they are normalized to less than one second.
    if (value->stamp.nsec >= 1000000000L)
    {
        epicsTimeStamp s = value->stamp;
        s.nsec = 0;
        epicsTime t = s;
        stdString txt;
        epicsTime2string(t, txt);
        nanosecond_throttle.LOG_MSG("ProcessVariable::value_callback(%s) "
            "with invalid secs/nsecs %zu, %zu: %s\n",
            me->getName().c_str(),
            (size_t) value->stamp.secPastEpoch,
            (size_t) value->stamp.nsec,
            txt.c_str());
        return;
    }
    try
    {
        {
            // Do we expect a value because of 'get' or subscription?
            Guard guard(__FILE__, __LINE__, *me);
            if (me->outstanding_gets > 0)
                --me->outstanding_gets;
            else if (me->isSubscribed(guard) == false)
            {
                LOG_MSG("ProcessVariable::value_callback(%s): not expected\n",
                        me->getName().c_str());
                return;
            }
#           ifdef CHECK_EVID
            if (me->ev_id)
            {
                void *user = peek_evid_userptr(me->ev_id);
                LOG_ASSERT(user == me);
            }
#           endif
            if (me->state != CONNECTED)
            {
                // After a disconnect, this can happen in the GETTING_INFO state:
                // The CAC lib already sends us new monitors after the re-connect,
                // while we wait for the ctrl-info get_callback to finish.
                if (me->state == GETTING_INFO) // ignore
                    return;
                LOG_MSG("ProcessVariable(%s) received value_callback while %s\n",
                        me->getName().c_str(), me->getStateStr(guard));
                return;
            }
        }
        // Finally, notify listeners of new value.
        me->firePvValue(value);
    }
    catch (GenericException &e)
    {
        LOG_MSG("ProcessVariable(%s) value_callback exception:\n%s\n",
                me->getName().c_str(), e.what());
    }
}
void ProcessVariable::subscribe(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
    if (dbr_type == 0)
        throw GenericException(__FILE__, __LINE__,
                               "Cannot subscribe to %s, never connected",
                               getName().c_str());
    // Prevent multiple subscriptions
    if (isSubscribed(guard))
        return;
    // While we were unlocked, a disconnect or stop() could have happend,
    // in which case we need to bail out.
    if (id == 0 || state != CONNECTED)
    {
        LOG_MSG("'%s': Skipped subscription, state %s, id 0x%lu.\n",
                getName().c_str(),  getStateStr(guard), (unsigned long) id);
        return;
    }
    chid     _id    = id;
    evid     _ev_id = 0;
    DbrType  _type  = dbr_type;
    DbrCount _count = dbr_count;
    {   // Release around CA call??
        // --  GuardRelease release(__FILE__, __LINE__, guard);
        // Right now, could a stop() and ca_clear_channel(id) happen,
        // so that ca_create_subscription() uses an invalid id?
        //
        // Task A, CAC client:
        // control_callback, pvConnected, subscribe
        //
        // Task B, Engine or HTTPD:
        // stop, clear_channel
        //
        // LockTest.cpp indicates that the clear_channel() will wait
        // for the CAC library to leabe the control_callback.
        // So even though we unlock the ProcessVariable and somebody
        // could invoke stop() and set id=0, we have the copied _id,
        // and the ca_clear_channel(id) won't happen until we leave
        // the control_callback.
        // This of course only handles the use case of the engine
        // where subscribe is invoked from control_callback & pvConnected.
        // to be on the safe side, we keep the guard and prevent a stop(),
        // until we find a deadlock that forces us to reconsider....
        {
            int status;
            try
            {
                status = ca_create_subscription(_type, _count, _id,
                                                DBE_LOG | DBE_ALARM,
                                                value_callback, this, &_ev_id);
            }
            catch (std::exception &e)
            {
                LOG_MSG("ProcessVariable::subscribe(%s): %s\n",
                        getName().c_str(), e.what());
            }
            catch (...)
            {
                LOG_MSG("ProcessVariable::subscribe(%s): Unknown Exception\n",
                        getName().c_str());
            } 
            if (status != ECA_NORMAL)
            {
                LOG_MSG("%s: ca_create_subscription failed: %s\n",
                        getName().c_str(), ca_message(status));
                return;
            }
            Guard ctx_guard(__FILE__, __LINE__, ctx);
            ctx.requestFlush(ctx_guard);
        }
    }
    ev_id = _ev_id;
    LOG_ASSERT(ev_id != 0);
#ifdef CHECK_EVID
    void *user = peek_evid_userptr(ev_id);
    LOG_ASSERT(user == this);
#endif
}
// Channel Access callback
void ProcessVariable::connection_handler(struct connection_handler_args arg)
{
    ProcessVariable *me = (ProcessVariable *) ca_puser(arg.chid);
    LOG_ASSERT(me != 0);
    try
    {
        if (arg.op == CA_OP_CONN_DOWN)
        {   // Connection is down
            {
                Guard guard(__FILE__, __LINE__, *me);
                me->state = DISCONNECTED;
            }
            me->firePvDisconnected();
            return;
        }
        {   // else: Connection is 'up'
            Guard guard(__FILE__, __LINE__, *me);
            if (me->id == 0)
            {
                LOG_MSG("ProcessVariable(%s) received "
                        "unexpected connection_handler\n",
                        me->getName().c_str());
                return;
            }
#           ifdef DEBUG_PV
            printf("ProcessVariable(%s) getting control info\n",
                   me->getName().c_str());
#           endif
            me->state = GETTING_INFO;
            // Get control information for this channel.
            // Bug in (at least older) CA: Works only for 1 element,
            // even for array channels.
            // We are in CAC callback, and managed to lock ourself,
            // so it should be OK to issue another CAC call.
            try
            {
                int status = ca_array_get_callback(
                    ca_field_type(me->id)+DBR_CTRL_STRING,
                    1 /* ca_element_count(me->ch_id) */,
                    me->id, control_callback, me);
                if (status != ECA_NORMAL)
                {
                    LOG_MSG("ProcessVariable('%s') connection_handler error %s\n",
                            me->getName().c_str(), ca_message (status));
                    return;
                }
            }
            catch (std::exception &e)
            {
                LOG_MSG("ProcessVariable::connection_handler(%s): %s\n",
                        me->getName().c_str(), e.what());
            }
            catch (...)
            {
                LOG_MSG("ProcessVariable::connection_handler(%s): "
                        "Unknown Exception\n", me->getName().c_str());
            } 
        }
        Guard ctx_guard(__FILE__, __LINE__, me->ctx);
        me->ctx.requestFlush(ctx_guard);
    }
    catch (GenericException &e)
    {
        LOG_MSG("ProcessVariable(%s) connection_handler exception:\n%s\n",
                me->getName().c_str(), e.what());
    }    
}
Esempio n. 4
0
int main (int argc, char *argv[])
{
    int i;
    int result;                 /* CA result */
    OutputT format = plain;     /* User specified format */
    RequestT request = get;     /* User specified request type */
    int isArray = 0;            /* Flag for array operation */
    int enumAsString = 0;       /* Force ENUM values to be strings */

    int count = 1;
    int opt;                    /* getopt() current option */
    chtype dbrType = DBR_STRING;
    char *pend;
    EpicsStr *sbuf;
    double *dbuf;
    char *cbuf = 0;
    char *ebuf = 0;
    void *pbuf;
    int len = 0;
    int waitStatus;
    struct dbr_gr_enum bufGrEnum;

    int nPvs;                   /* Number of PVs */
    pv* pvs;                /* Array of PV structures */

    LINE_BUFFER(stdout);        /* Configure stdout buffering */
    putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */

    while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) {
        switch (opt) {
        case 'h':               /* Print usage */
            usage();
            return 0;
        case 'n':               /* Force interpret ENUM as index number */
            enumAsNr = 1;
            enumAsString = 0;
            break;
        case 's':               /* Force interpret ENUM as menu string */
            enumAsString = 1;
            enumAsNr = 0;
            break;
        case 'S':               /* Treat char array as (long) string */
            charArrAsStr = 1;
            isArray = 0;
            break;
        case 't':               /* Select terse output format */
            format = terse;
            break;
        case 'l':               /* Select long output format */
            format = all;
            break;
        case 'a':               /* Select array mode */
            isArray = 1;
            charArrAsStr = 0;
            break;
        case 'c':               /* Select put_callback mode */
            request = callback;
            break;
        case 'w':               /* Set CA timeout value */
            if(epicsScanDouble(optarg, &caTimeout) != 1)
            {
                fprintf(stderr, "'%s' is not a valid timeout value "
                        "- ignored. ('caput -h' for help.)\n", optarg);
                caTimeout = DEFAULT_TIMEOUT;
            }
            break;
        case '#':               /* Array count */
            if (sscanf(optarg,"%d", &count) != 1)
            {
                fprintf(stderr, "'%s' is not a valid array element count "
                        "- ignored. ('caput -h' for help.)\n", optarg);
                count = 0;
            }
            break;
        case 'p':               /* CA priority */
            if (sscanf(optarg,"%u", &caPriority) != 1)
            {
                fprintf(stderr, "'%s' is not a valid CA priority "
                        "- ignored. ('caget -h' for help.)\n", optarg);
                caPriority = DEFAULT_CA_PRIORITY;
            }
            if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
            break;
        case 'F':               /* Store this for output and tool_lib formatting */
            fieldSeparator = (char) *optarg;
            break;
        case '?':
            fprintf(stderr,
                    "Unrecognized option: '-%c'. ('caput -h' for help.)\n",
                    optopt);
            return 1;
        case ':':
            fprintf(stderr,
                    "Option '-%c' requires an argument. ('caput -h' for help.)\n",
                    optopt);
            return 1;
        default :
            usage();
            return 1;
        }
    }

    nPvs = argc - optind;       /* Remaining arg list are PV names and values */

    if (nPvs < 1) {
        fprintf(stderr, "No pv name specified. ('caput -h' for help.)\n");
        return 1;
    }
    if (nPvs == 1) {
        fprintf(stderr, "No value specified. ('caput -h' for help.)\n");
        return 1;
    }

    nPvs = 1;                   /* One PV - the rest is value(s) */

    epId = epicsEventCreate(epicsEventEmpty);  /* Create empty EPICS event (semaphore) */

                                /* Start up Channel Access */

    result = ca_context_create(ca_enable_preemptive_callback);
    if (result != ECA_NORMAL) {
        fprintf(stderr, "CA error %s occurred while trying "
                "to start channel access.\n", ca_message(result));
        return 1;
    }
                                /* Allocate PV structure array */

    pvs = calloc (nPvs, sizeof(pv));
    if (!pvs) {
        fprintf(stderr, "Memory allocation for channel structure failed.\n");
        return 1;
    }
                                /* Connect channels */

    pvs[0].name = argv[optind] ;   /* Copy PV name from command line */

    result = connect_pvs(pvs, nPvs); /* If the connection fails, we're done */
    if (result) {
        ca_context_destroy();
        return result;
    }

                                /* Get values from command line */
    optind++;

    if (isArray) {
        optind++;               /* In case of array skip first value (nr
                                 * of elements) - actual number of values is used */
        count = argc - optind;

    } else {                    /* Concatenate the remaining line to one string
                                 * (sucks but is compatible to the former version) */
        for (i = optind; i < argc; i++) {
            len += strlen(argv[i]);
            len++;
        }
        cbuf = calloc(len, sizeof(char));
        if (!cbuf) {
            fprintf(stderr, "Memory allocation failed.\n");
            return 1;
        }
        strcpy(cbuf, argv[optind]);

        if (argc > optind+1) {
            for (i = optind + 1; i < argc; i++) {
                strcat(cbuf, " ");
                strcat(cbuf, argv[i]); 
            }
        }

        if ((argc - optind) >= 1)
            count = 1;
        argv[optind] = cbuf;
    }

    sbuf = calloc (count, sizeof(EpicsStr));
    dbuf = calloc (count, sizeof(double));
    if(!sbuf || !dbuf) {
        fprintf(stderr, "Memory allocation failed\n");
        return 1;
    }

                                /*  ENUM? Special treatment */

    if (ca_field_type(pvs[0].chid) == DBR_ENUM) {

                                /* Get the ENUM strings */

        result = ca_array_get (DBR_GR_ENUM, 1, pvs[0].chid, &bufGrEnum);
        result = ca_pend_io(caTimeout);
        if (result == ECA_TIMEOUT) {
            fprintf(stderr, "Read operation timed out: ENUM data was not read.\n");
            return 1;
        }

        if (enumAsNr) {         /* Interpret values as numbers */

            for (i = 0; i < count; ++i) {
                dbuf[i] = epicsStrtod(*(argv+optind+i), &pend);
                if (*(argv+optind+i) == pend) { /* Conversion didn't work */
                    fprintf(stderr, "Enum index value '%s' is not a number.\n",
                            *(argv+optind+i));
                    return 1;
                }
                if (dbuf[i] >= bufGrEnum.no_str) {
                    fprintf(stderr, "Warning: enum index value '%s' may be too large.\n",
                            *(argv+optind+i));
                }
            }
            dbrType = DBR_DOUBLE;

        } else {                /* Interpret values as strings */

            for (i = 0; i < count; ++i) {
                epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));
                *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0';
                dbrType = DBR_STRING;

                                /* Compare to ENUM strings */
                for (len = 0; len < bufGrEnum.no_str; len++)
                    if (!strcmp(sbuf[i], bufGrEnum.strs[len]))
                        break;

                if (len >= bufGrEnum.no_str) {
                                         /* Not a string? Try as number */
                    dbuf[i] = epicsStrtod(sbuf[i], &pend);
                    if (sbuf[i] == pend || enumAsString) {
                        fprintf(stderr, "Enum string value '%s' invalid.\n", sbuf[i]);
                        return 1;
                    }
                    if (dbuf[i] >= bufGrEnum.no_str) {
                        fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", sbuf[i]);
                    }
                    dbrType = DBR_DOUBLE;
                }
            }
        }

    } else {                    /* Not an ENUM */

        if (charArrAsStr) {
            dbrType = DBR_CHAR;
            ebuf = calloc(len, sizeof(char));
            if(!ebuf) {
                fprintf(stderr, "Memory allocation failed\n");
                return 1;
            }
            count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1;
        } else {
            for (i = 0; i < count; ++i) {
                epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));
                *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0';
            }
            dbrType = DBR_STRING;
        }
    }

                                /* Read and print old data */
    if (format != terse) {
        printf("Old : ");
        result = caget(pvs, nPvs, format, 0, 0);
    }

                                /* Write new data */
    if (dbrType == DBR_STRING) pbuf = sbuf;
    else if (dbrType == DBR_CHAR) pbuf = ebuf;
    else pbuf = dbuf;

    if (request == callback) {
        /* Use callback version of put */
        pvs[0].status = ECA_NORMAL;   /* All ok at the moment */
        result = ca_array_put_callback (
            dbrType, count, pvs[0].chid, pbuf, put_event_handler, (void *) pvs);
    } else {
        /* Use standard put with defined timeout */
        result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
    }
    result = ca_pend_io(caTimeout);
    if (result == ECA_TIMEOUT) {
        fprintf(stderr, "Write operation timed out: Data was not written.\n");
        return 1;
    }
    if (request == callback) {   /* Also wait for callbacks */
        waitStatus = epicsEventWaitWithTimeout( epId, caTimeout );
        if (waitStatus)
            fprintf(stderr, "Write callback operation timed out\n");

        /* retrieve status from callback */
        result = pvs[0].status;
    }

    if (result != ECA_NORMAL) {
        fprintf(stderr, "Error occured writing data.\n");
        return 1;
    }

                                /* Read and print new data */
    if (format != terse)
        printf("New : ");

    result = caget(pvs, nPvs, format, 0, 0);

                                /* Shut down Channel Access */
    ca_context_destroy();

    return result;
}
Esempio n. 5
0
int main (int argc, char *argv[])
{
    int returncode = 0;
    int n;
    int result;                 /* CA result */
    IntFormatT outType;         /* Output type */

    int opt;                    /* getopt() current option */
    int digits = 0;             /* getopt() no. of float digits */

    int nPvs;                   /* Number of PVs */
    pv* pvs;                    /* Array of PV structures */

    LINE_BUFFER(stdout);        /* Configure stdout buffering */

    while ((opt = getopt(argc, argv, ":nhm:sSe:f:g:l:#:0:w:t:p:F:")) != -1) {
        switch (opt) {
        case 'h':               /* Print usage */
            usage();
            return 0;
        case 'n':               /* Print ENUM as index numbers */
            enumAsNr=1;
            break;
        case 't':               /* Select timestamp source(s) and type */
            tsSrcServer = 0;
            tsSrcClient = 0;
            {
                int i = 0;
                char c;
                while ((c = optarg[i++]))
                    switch (c) {
                    case 's': tsSrcServer = 1; break;
                    case 'c': tsSrcClient = 1; break;
                    case 'n': break;
                    case 'r': tsType = relative; break;
                    case 'i': tsType = incremental; break;
                    case 'I': tsType = incrementalByChan; break;
                    default :
                        fprintf(stderr, "Invalid argument '%c' "
                                "for option '-t' - ignored.\n", c);
                    }
            }
            break;
        case 'w':               /* Set CA timeout value */
            if(epicsScanDouble(optarg, &caTimeout) != 1)
            {
                fprintf(stderr, "'%s' is not a valid timeout value "
                        "- ignored. ('camonitor -h' for help.)\n", optarg);
                caTimeout = DEFAULT_TIMEOUT;
            }
            break;
        case '#':               /* Array count */
            if (sscanf(optarg,"%ld", &reqElems) != 1)
            {
                fprintf(stderr, "'%s' is not a valid array element count "
                        "- ignored. ('camonitor -h' for help.)\n", optarg);
                reqElems = 0;
            }
            break;
        case 'p':               /* CA priority */
            if (sscanf(optarg,"%u", &caPriority) != 1)
            {
                fprintf(stderr, "'%s' is not a valid CA priority "
                        "- ignored. ('camonitor -h' for help.)\n", optarg);
                caPriority = DEFAULT_CA_PRIORITY;
            }
            if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
            break;
        case 'm':               /* Select CA event mask */
            eventMask = 0;
            {
                int i = 0;
                char c, err = 0;
                while ((c = optarg[i++]) && !err)
                    switch (c) {
                    case 'v': eventMask |= DBE_VALUE; break;
                    case 'a': eventMask |= DBE_ALARM; break;
                    case 'l': eventMask |= DBE_LOG; break;
                    case 'p': eventMask |= DBE_PROPERTY; break;
                        default :
                            fprintf(stderr, "Invalid argument '%s' "
                                    "for option '-m' - ignored.\n", optarg);
                            eventMask = DBE_VALUE | DBE_ALARM;
                            err = 1;
                    }
            }
            break;
        case 's':               /* Select string dbr for floating type data */
            floatAsString = 1;
            break;
        case 'S':               /* Treat char array as (long) string */
            charArrAsStr = 1;
            break;
        case 'e':               /* Select %e/%f/%g format, using <arg> digits */
        case 'f':
        case 'g':
            if (sscanf(optarg, "%d", &digits) != 1)
                fprintf(stderr, 
                        "Invalid precision argument '%s' "
                        "for option '-%c' - ignored.\n", optarg, opt);
            else
            {
                if (digits>=0 && digits<=VALID_DOUBLE_DIGITS)
                    sprintf(dblFormatStr, "%%-.%d%c", digits, opt);
                else
                    fprintf(stderr, "Precision %d for option '-%c' "
                            "out of range - ignored.\n", digits, opt);
            }
            break;
        case 'l':               /* Convert to long and use integer format */
        case '0':               /* Select integer format */
            switch ((char) *optarg) {
            case 'x': outType = hex; break;    /* x print Hex */
            case 'b': outType = bin; break;    /* b print Binary */
            case 'o': outType = oct; break;    /* o print Octal */
            default :
                outType = dec;
                fprintf(stderr, "Invalid argument '%s' "
                        "for option '-%c' - ignored.\n", optarg, opt);
            }
            if (outType != dec) {
              if (opt == '0') outTypeI = outType;
              else            outTypeF = outType;
            }
            break;
        case 'F':               /* Store this for output and tool_lib formatting */
            fieldSeparator = (char) *optarg;
            break;
        case '?':
            fprintf(stderr,
                    "Unrecognized option: '-%c'. ('camonitor -h' for help.)\n",
                    optopt);
            return 1;
        case ':':
            fprintf(stderr,
                    "Option '-%c' requires an argument. ('camonitor -h' for help.)\n",
                    optopt);
            return 1;
        default :
            usage();
            return 1;
        }
    }

    nPvs = argc - optind;       /* Remaining arg list are PV names */

    if (nPvs < 1)
    {
        fprintf(stderr, "No pv name specified. ('camonitor -h' for help.)\n");
        return 1;
    }
                                /* Start up Channel Access */

    result = ca_context_create(ca_disable_preemptive_callback);
    if (result != ECA_NORMAL) {
        fprintf(stderr, "CA error %s occurred while trying "
                "to start channel access.\n", ca_message(result));
        return 1;
    }
                                /* Allocate PV structure array */

    pvs = calloc (nPvs, sizeof(pv));
    if (!pvs)
    {
        fprintf(stderr, "Memory allocation for channel structures failed.\n");
        return 1;
    }
                                /* Connect channels */

                                      /* Copy PV names from command line */
    for (n = 0; optind < argc; n++, optind++)
    {
        pvs[n].name   = argv[optind];
    }
                                      /* Create CA connections */
    returncode = create_pvs(pvs, nPvs, connection_handler);
    if ( returncode ) {
        return returncode;
    }
                                      /* Check for channels that didn't connect */
    ca_pend_event(caTimeout);
    for (n = 0; n < nPvs; n++)
    {
        if (!pvs[n].onceConnected)
            print_time_val_sts(&pvs[n], reqElems);
    }

                                /* Read and print data forever */
    ca_pend_event(0);

                                /* Shut down Channel Access */
    ca_context_destroy();

    return result;
}
Esempio n. 6
0
int main(int argc,char **argv)
{
    char   *pval;
    double sleepSecs = 0.0;
    int	    clearEvery = 0;
    int     indValue = 1;
    int     indNumberCallback = 1;

    while((argc>1) && (argv[1][0] == '-')) {
        int i;
        char option;
        int  narg;
        option = toupper((argv[1])[1]);
        pval = argv[2];
        argc -= 1; narg = 1;
        if(option=='S') {
            sscanf(pval,"%lf",&sleepSecs);
            argc -= 1; ++narg;
        } else if(option=='C') {
            sscanf(pval,"%d",&clearEvery);
            argc -= 1; ++narg;
        } else if(option=='V') {
            verbose = 1;
        } else {
            usageExit();
        }
        for(i=1; i<argc; i++) argv[i] = argv[i + narg];
    }

    if(argc != 4) usageExit();
    pvname = argv[1];
    pvalue1 = argv[2];
    pvalue2 = argv[3];
    pevent = epicsEventCreate(epicsEventEmpty);
    SEVCHK(ca_context_create(ca_enable_preemptive_callback),
        "ca_task_initialize");
    while(1) {
        SEVCHK(ca_search(pvname,&mychid),"ca_search_and_connect");
        if(ca_pend_io(3.0)!=ECA_NORMAL) {
            epicsThreadSleep(5.0);
            continue;
        }
        while(1) {
            epicsEventWaitStatus status;
            if(indValue==0) {
                indValue = 1; pvalue = pvalue2;
            } else {
                indValue = 0; pvalue=pvalue1;
            }
            if(++indNumberCallback >= MAXnumberCallback) indNumberCallback=0;
            numberCallback[indNumberCallback] = ++expectedCallback;
            status = ca_array_put_callback(DBR_STRING,1,mychid,
                pvalue,putCallback,&numberCallback[indNumberCallback]);
            if(status!=ECA_NORMAL) {
                printf("ca_array_put_callback %s\n",ca_message(status));
                epicsThreadSleep(2.0);
                continue;
            }
            if((clearEvery>0) 
            && ((expectedCallback % clearEvery)==0)) {
                ca_flush_io();
                epicsThreadSleep(sleepSecs);
                SEVCHK(ca_clear_channel(mychid),"ca_clear_channel");
                ca_flush_io();
                expectedCallback = 0;
                epicsThreadSleep(sleepSecs);
                if(verbose) {
                    printTime();
                    printf("Issued ca_clear_channel expectedCallback %d\n",
                        expectedCallback);
                }
                break;
            }
            ca_flush_io();
            if(verbose) {
                printTime();
                printf("Issued ca_put_callback expectedCallback %d\n",
                    expectedCallback);
            }
            while(1) {
                status = epicsEventWaitWithTimeout(pevent,10.0);
                if(status==epicsEventWaitTimeout) {
                    if(verbose) {
                        printTime();
                        printf("timeout after 10 seconds\n");
                    }
                    continue;
                }
                break;
            }
            if(status!=epicsEventWaitOK) {
                int i;
                printTime();
                printf("eventWait status %d\n",status);
                for(i=0; i<MAXnumberCallback; i++) numberCallback[i]=0;
            }
            epicsThreadSleep(sleepSecs);
        }
    }
    ca_task_exit();
    return(0);
}
Esempio n. 7
0
int caget (pv *pvs, int nPvs, OutputT format,
           chtype dbrType, unsigned long reqElems)
{
    unsigned int i;
    int n, result;

    for (n = 0; n < nPvs; n++) {

                                /* Set up pvs structure */
                                /* -------------------- */

                                /* Get natural type and array count */
        pvs[n].nElems  = ca_element_count(pvs[n].chid);
        pvs[n].dbfType = ca_field_type(pvs[n].chid);
        pvs[n].dbrType = dbrType;

                                /* Set up value structures */
        pvs[n].dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */
        if (dbr_type_is_ENUM(pvs[n].dbrType))             /* Enums honour -n option */
        {
            if (enumAsNr) pvs[n].dbrType = DBR_TIME_INT;
            else          pvs[n].dbrType = DBR_TIME_STRING;
        }

        if (reqElems == 0 || pvs[n].nElems < reqElems)    /* Adjust array count */
            pvs[n].reqElems = pvs[n].nElems;
        else
            pvs[n].reqElems = reqElems;

                                /* Issue CA request */
                                /* ---------------- */

        if (ca_state(pvs[n].chid) == cs_conn)
        {
            nConn++;
            pvs[n].onceConnected = 1;
                                   /* Allocate value structure */
            pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].reqElems));
            if(!pvs[n].value){
                fprintf(stderr,"Allocation failed\n");
                exit(1);
            }
            result = ca_array_get(pvs[n].dbrType,
                                  pvs[n].reqElems,
                                  pvs[n].chid,
                                  pvs[n].value);
            pvs[n].status = result;
        } else {
            pvs[n].status = ECA_DISCONN;
        }
    }
    if (!nConn) return 1;              /* No connection? We're done. */

                                /* Wait for completion */
                                /* ------------------- */

    result = ca_pend_io(caTimeout);
    if (result == ECA_TIMEOUT)
        fprintf(stderr, "Read operation timed out: PV data was not read.\n");

                                /* Print the data */
                                /* -------------- */

    for (n = 0; n < nPvs; n++) {

        switch (format) {
        case plain:             /* Emulate old caput behaviour */
            if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
            else                                               printf("%s", pvs[n].name);
            printf("%c", fieldSeparator);
        case terse:
            if (pvs[n].status == ECA_DISCONN)
                printf("*** not connected\n");
            else if (pvs[n].status == ECA_NORDACCESS)
                printf("*** no read access\n");
            else if (pvs[n].status != ECA_NORMAL)
                printf("*** CA error %s\n", ca_message(pvs[n].status));
            else if (pvs[n].value == 0)
                printf("*** no data available (timeout)\n");
            else
            {
                if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
                    dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
                    int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
                    char *d = calloc(dlen+1, sizeof(char));
                    if(!d){
                        fprintf(stderr,"Allocation failed\n");
                        exit(1);
                    }
                    epicsStrnEscapedFromRaw(d, dlen+1, (char*)s, strlen((char*)s));
                    printf("%s", d);
                    free(d);
                } else {
                    if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].reqElems, fieldSeparator);
                    for (i=0; i<pvs[n].reqElems; ++i) {
                        if (i) printf ("%c", fieldSeparator);
                        printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
                    }
                }
                printf("\n");
            }
            break;
        case all:
            print_time_val_sts(&pvs[n], reqElems);
            break;
        default :
            break;
        }
    }
    return 0;
}
Esempio n. 8
0
static void eventCallback(struct event_handler_args arg)
{
    caLink *pca = (caLink *)arg.usr;
    struct link *plink;
    size_t size;
    dbCommon *precord = 0;
    struct dbr_time_double *pdbr_time_double;
    dbCaCallback monitor = 0;
    void *userPvt = 0;

    assert(pca);
    epicsMutexMustLock(pca->lock);
    plink = pca->plink;
    if (!plink) goto done;
    monitor = pca->monitor;
    userPvt = pca->userPvt;
    precord = plink->value.pv_link.precord;
    if (arg.status != ECA_NORMAL) {
        if (precord) {
            if (arg.status != ECA_NORDACCESS &&
                arg.status != ECA_GETFAIL)
                errlogPrintf("dbCa: eventCallback record %s error %s\n",
                    precord->name, ca_message(arg.status));
        } else {
            errlogPrintf("dbCa: eventCallback error %s\n",
                ca_message(arg.status));
        }
        goto done;
    }
    assert(arg.dbr);
    size = arg.count * dbr_value_size[arg.type];
    if (arg.type == DBR_TIME_STRING &&
        ca_field_type(pca->chid) == DBR_ENUM) {
        assert(pca->pgetString);
        memcpy(pca->pgetString, dbr_value_ptr(arg.dbr, arg.type), size);
        pca->gotInString = TRUE;
    } else switch (arg.type){
    case DBR_TIME_STRING: 
    case DBR_TIME_SHORT: 
    case DBR_TIME_FLOAT:
    case DBR_TIME_ENUM:
    case DBR_TIME_CHAR:
    case DBR_TIME_LONG:
    case DBR_TIME_DOUBLE:
        assert(pca->pgetNative);
        memcpy(pca->pgetNative, dbr_value_ptr(arg.dbr, arg.type), size);
        pca->gotInNative = TRUE;
        break;
    default:
        errMessage(-1, "dbCa: eventCallback Logic Error\n");
        break;
    }
    pdbr_time_double = (struct dbr_time_double *)arg.dbr;
    pca->sevr = pdbr_time_double->severity;
    pca->stat = pdbr_time_double->status;
    memcpy(&pca->timeStamp, &pdbr_time_double->stamp, sizeof(epicsTimeStamp));
    if (precord) {
        struct pv_link *ppv_link = &plink->value.pv_link;

        if ((ppv_link->pvlMask & pvlOptCP) ||
            ((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0))
        scanOnce(precord);
    }
done:
    epicsMutexUnlock(pca->lock);
    if (monitor) monitor(userPvt);
}
Esempio n. 9
0
static void dbCaTask(void *arg)
{
    taskwdInsert(0, NULL, NULL);
    SEVCHK(ca_context_create(ca_enable_preemptive_callback),
        "dbCaTask calling ca_context_create");
    dbCaClientContext = ca_current_context ();
    SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
        "ca_add_exception_event");
    epicsEventSignal(startStopEvent);

    /* channel access event loop */
    while (TRUE){
        do {
            epicsEventMustWait(workListEvent);
        } while (dbCaCtl == ctlPause);
        while (TRUE) { /* process all requests in workList*/
            caLink *pca;
            short  link_action;
            int    status;

            epicsMutexMustLock(workListLock);
            if (!(pca = (caLink *)ellGet(&workList))){  /* Take off list head */
                epicsMutexUnlock(workListLock);
                if (dbCaCtl == ctlExit) goto shutdown;
                break; /* workList is empty */
            }
            link_action = pca->link_action;
            pca->link_action = 0;
            if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
            epicsMutexUnlock(workListLock);         /* Give back immediately */
            if (link_action & CA_CLEAR_CHANNEL) {   /* This must be first */
                dbCaLinkFree(pca);
                /* No alarm is raised. Since link is changing so what? */
                continue; /* No other link_action makes sense */
            }
            if (link_action & CA_CONNECT) {
                status = ca_create_channel(
                      pca->pvname,connectionCallback,(void *)pca,
                      CA_PRIORITY_DB_LINKS, &(pca->chid));
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_create_channel %s\n",
                        ca_message(status));
                    printLinks(pca);
                    continue;
                }
                dbca_chan_count++;
                status = ca_replace_access_rights_event(pca->chid,
                    accessRightsCallback);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask replace_access_rights_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                continue; /*Other options must wait until connect*/
            }
            if (ca_state(pca->chid) != cs_conn) continue;
            if (link_action & CA_WRITE_NATIVE) {
                assert(pca->pputNative);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutNative = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            if (link_action & CA_WRITE_STRING) {
                assert(pca->pputString);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutString = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            /*CA_GET_ATTRIBUTES before CA_MONITOR so that attributes available
             * before the first monitor callback                              */
            if (link_action & CA_GET_ATTRIBUTES) {
                status = ca_get_callback(DBR_CTRL_DOUBLE,
                    pca->chid, getAttribEventCallback, pca);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_get_callback %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_NATIVE) {
                size_t element_size;
    
                element_size = dbr_value_size[ca_field_type(pca->chid)];
                epicsMutexMustLock(pca->lock);
                pca->pgetNative = dbCalloc(pca->nelements, element_size);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(
                    ca_field_type(pca->chid)+DBR_TIME_STRING,
                    ca_element_count(pca->chid),
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_STRING) {
                epicsMutexMustLock(pca->lock);
                pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(DBR_TIME_STRING, 1,
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
        }
        SEVCHK(ca_flush_io(), "dbCaTask");
    }
shutdown:
    taskwdRemove(0);
    if (dbca_chan_count == 0)
        ca_context_destroy();
    else
        fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", dbca_chan_count);
    epicsEventSignal(startStopEvent);
}
Esempio n. 10
0
static void medmUpdateChannelCb(struct event_handler_args args) {
    Channel *pCh = (Channel *)ca_puser(args.chid);
    Boolean statusChanged = False;
    Boolean severityChanged = False;
    Boolean zeroAndNoneZeroTransition = False;
    Record *pr;
    double value;
    int nBytes;
    int allocBytes;

#if DEBUG_CHANNEL_CB || DEBUG_LARGE_ARRAY
    const char *pvname=ca_name(args.chid);
    print("medmUpdateChannelCb: %s\n",pvname);
    if(args.status != ECA_NORMAL) {
	char buf[80];
	envGetConfigParam(&EPICS_CA_MAX_ARRAY_BYTES,80,buf);
	buf[79]='\0';
	print("EPICS_CA_MAX_ARRAY_BYTES: %s\n",buf);
    }
#endif

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
  /* Same as for updateGraphicalInfoCb */
  /* Don't need to check for read access, checking ECA_NORMAL is enough */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(args.status != ECA_NORMAL) {
	medmPostMsg(0,"medmUpdateChannelCb: Bad status [%d] for %s: %s\n",
	  args.status,
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown",
	  ca_message(args.status));
	return;
    }
    if(!args.dbr) {
	medmPostMsg(0,"medmUpdateChannelCb: Invalid data for [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmUpdateChannelCb: "
	  "Invalid channel information for [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(pCh->chid != args.chid) {
	medmPostMsg(0,"medmUpdateChannelCb: chid from args [%x] "
	  "does not match chid from channel [%x]\n"
	  "  [%s]\n",
	  args.chid,
	  pCh->chid,
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    pr = pCh->pr;

  /* Allocate space for the data */
    nBytes = dbr_size_n(args.type, args.count);
    if(!pCh->data) {
        /* Allocate maximum space for the variable array data */
        if(pr->currentCount == -2) {
            allocBytes=dbr_size_n(args.type, pr->elementCount);
        } else {
            allocBytes=nBytes;
        }
      /* No previous data, allocate */
	pCh->data = (dataBuf *)malloc(allocBytes);
	pCh->size = allocBytes;
	if(!pCh->data) {
	    medmPostMsg(1,"medmUpdateChannelCb: Memory allocation error [%s]\n",
	      ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	    return;
	}
    } else if(pCh->size < nBytes) {
      /* Previous data exists but is too small
       * Free it and allocate it again */
	free((char *)pCh->data);
	pCh->data = (dataBuf *)malloc(nBytes);
	pCh->size = nBytes;
	if(pCh->data == NULL) {
	    medmPostMsg(1,"medmUpdateChannelCb: Memory reallocation error"
	      " [%s]\n",
	      ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	    return;
	}
    }
    pr->currentCount=args.count;

#ifdef __USING_TIME_STAMP__
  /* Copy the returned time stamp to the Record */
    pr->time = ((dataBuf *)args.dbr)->s.stamp;
#endif


  /* Set the array pointer in the Record to point to the value member of the
   *   appropriate struct stored in the Channel
   * (The returned data is not stored there yet) */
    switch (ca_field_type(args.chid)) {
    case DBF_STRING:
	pr->array = (XtPointer)pCh->data->s.value;
	break;
    case DBF_ENUM:
	pr->array = (XtPointer)&(pCh->data->e.value);
	break;
    case DBF_CHAR:
	pr->array = (XtPointer)&(pCh->data->c.value);
	break;
    case DBF_INT:
	pr->array = (XtPointer)&(pCh->data->i.value);
	break;
    case DBF_LONG:
	pr->array = (XtPointer)&(pCh->data->l.value);
	break;
    case DBF_FLOAT:
	pr->array = (XtPointer)&(pCh->data->f.value);
	break;
    case DBF_DOUBLE:
	pr->array = (XtPointer)&(pCh->data->d.value);
	break;
    default:
	break;
    }

  /* For strings and arrays copy the returned data to the Channel
   * (The space is allocated but the data is not stored otherwise) */
    if(ca_field_type(args.chid) == DBF_STRING ||
      ca_element_count(args.chid) > 1) {
	memcpy((void *)pCh->data, args.dbr, nBytes);
    }

  /* Copy the value from the returned data to the Record */
    switch (ca_field_type(args.chid)) {
    case DBF_STRING:
	value = 0.0;
	break;
    case DBF_ENUM:
	value = (double)((dataBuf *)(args.dbr))->e.value;
	break;
    case DBF_CHAR:
	value = (double)((dataBuf *)(args.dbr))->c.value;
	break;
    case DBF_INT:
	value = (double)((dataBuf *)(args.dbr))->i.value;
	break;
    case DBF_LONG:
	value = (double)((dataBuf *)(args.dbr))->l.value;
	break;
    case DBF_FLOAT:
	value = (double)((dataBuf *)(args.dbr))->f.value;
	break;
    case DBF_DOUBLE:
	value = ((dataBuf *)(args.dbr))->d.value;
#if DEBUG_SLIDER
	if(value > 150.0 || value < -150.0) {
	    print("medmUpdateChannelCb: %g\n",value);
	}
#endif
	break;
    default:
	value = 0.0;
	break;
    }

  /* Mark zero to nonzero transition */
    if(((value == 0.0) && (pr->value != 0.0)) ||
      ((value != 0.0) && (pr->value == 0.0)))
      zeroAndNoneZeroTransition = True;

  /* Mark status changed */
    if(pr->status != ((dataBuf *)(args.dbr))->d.status) {
	pr->status = ((dataBuf *)(args.dbr))->d.status;
	statusChanged = True;
    }

  /* Mark severity changed */
    if(pr->severity != ((dataBuf *)(args.dbr))->d.severity) {
	pr->severity = ((dataBuf *)(args.dbr))->d.severity;
	severityChanged = True;
    }

  /* Set the new value into the record */
    pr->value = value;

#if DEBUG_ERASE
    print("medmUpdateChannelCb: [%x]%s %g\n",
      pr, pr->name, pr->value);
#endif

  /* Call the update value callback if there is a monitored change */
    if(pCh->pr->updateValueCb) {
	if(pr->monitorValueChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorStatusChanged && statusChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorSeverityChanged && severityChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorZeroAndNoneZeroTransition &&
	  zeroAndNoneZeroTransition) {
	    pr->updateValueCb((XtPointer)pr);
	}
    }
}
Esempio n. 11
0
static void medmConnectEventCb(struct connection_handler_args args) {
    int status;
    Channel *pCh = (Channel *)ca_puser(args.chid);
    int count;

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmConnectEventCb: Invalid channel information\n");
	return;
    }

  /* Do a get every time a channel is connected or reconnected and has
   * read access.  The get will cause the graphical info callback to
   * be called */
    if(args.op == CA_OP_CONN_UP && ca_read_access(pCh->chid)) {
	status = ca_array_get_callback(
	  dbf_type_to_DBR_CTRL(ca_field_type(args.chid)),
	  1, args.chid, medmUpdateGraphicalInfoCb, NULL);
	if(status != ECA_NORMAL) {
	    medmPostMsg(0,"medmConnectEventCb: "
	      "ca_array_get_callback [%s]:\n %s\n",
	      ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
	      ca_message(status));
#if DEBUG_CONNECTION
# if 0
	    system("netstat | grep iocacis");
# endif
	    print("  pCh->chid %s args.chid\n",
	      pCh->chid == args.chid?"==":"!=");
	    print(
	      "  Channel Name: %s\n"
	      "  State: %s\n"
	      "  Native Type: %s\n"
	      "  Native Count: %hu\n"
	      "  Access: %s%s\n"
	      "  IOC: %s\n",
	      args.chid?ca_name(args.chid):"Unavailable",
	      args.chid?ca_state(args.chid) == cs_never_conn?"Never":
	      ca_state(args.chid) == cs_prev_conn?"Prev":
	      ca_state(args.chid) == cs_conn?"Conn":
	      ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
	      args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
	      args.chid?ca_element_count(args.chid):0,
	      args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
	      args.chid?(ca_write_access(args.chid)?"W":""):"",
	      args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	}
    }

  /* Handle four cases: connected or not and previously connected or not */
    if(args.op == CA_OP_CONN_UP) {
      /* Connected */
	if(pCh->previouslyConnected == False) {
	  /* Connected and not previously connected */
	  /* Set these first so they will be right for the updateValueCb */
	    pCh->pr->elementCount = ca_element_count(pCh->chid);
	    pCh->pr->dataType = ca_field_type(args.chid);
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	  /* Add the access-rights-change callback and the
	     significant-change (value, alarm or severity)
	     callback. Don't call the updateValueCb because
	     ca_replace_access_rights_event will call it. */
	    status = ca_replace_access_rights_event(
	      pCh->chid,medmReplaceAccessRightsEventCb);
	    if(status != ECA_NORMAL) {
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_replace_access_rights_event [%s]: %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
	    }
	    if(pCh->pr->currentCount == -2) {
                count=0;
            } else {
                count=ca_element_count(pCh->chid);
            }
#ifdef __USING_TIME_STAMP__
	    status = ca_add_array_event(
	      dbf_type_to_DBR_TIME(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#else
	    status = ca_add_array_event(
	      dbf_type_to_DBR_STS(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#endif
	    if(status != ECA_NORMAL) {
	      /* Set the pointer to NULL in case CA didn't.  We don't
                 want to use it or clear it later. */
#if DEBUG_CONNECTION
		if(!pCh->evid) {
		    print("medmConnectEventCb: ca_add_array_event: \n"
		      "  status[%d] != ECA_NORMAL and pCh->evid != NULL\n",
		      status);
		}
#endif
		pCh->evid = NULL;
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_add_array_event [%s]:\n %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
#if DEBUG_CONNECTION
# if 0
		system("netstat | grep iocacis");
# endif
		print("  pCh->chid %s args.chid\n",
		  pCh->chid == args.chid?"==":"!=");
		print(
		  "  Channel Name: %s\n"
		  "  State: %s\n"
		  "  Native Type: %s\n"
		  "  Native Count: %hu\n"
		  "  Access: %s%s\n"
		  "  IOC: %s\n",
		  args.chid?ca_name(args.chid):"Unavailable",
		  args.chid?ca_state(args.chid) == cs_never_conn?"Never":
		  ca_state(args.chid) == cs_prev_conn?"Prev":
		  ca_state(args.chid) == cs_conn?"Conn":
		  ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
		  args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
		  args.chid?ca_element_count(args.chid):0,
		  args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
		  args.chid?(ca_write_access(args.chid)?"W":""):"",
		  args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	    }
	  /* Set this one last so ca_replace_access_rights_event can
             use the old value */
	    pCh->previouslyConnected = True;
	} else {
	  /* Connected and previously connected */
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    } else {
      /* Not connected */
	if(pCh->previouslyConnected == False) {
	  /* Not connected and not previously connected */
	  /* Probably doesn't happen -- if CA can't connect, this
	   *   routine never gets called */
	    pCh->pr->connected = False;
	} else {
	  /* Not connected but previously connected */
	    pCh->pr->connected = False;
	    caTask.channelConnected--;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    }
}
Esempio n. 12
0
/* Find an unconnected PV and attempt to connect to it.  That should
 * restart the searches for all other unresolved PVs. */
void retryConnections(void)
{
    int i,j;
    const char *pvname=NULL;
    chid retryChid;
    int status;

#if DEBUG_RETRY
    print("retryConnections:\n");
    print(" freeListSize=%d freeListCount=%d\n",
      caTask.freeListSize,caTask.freeListCount);
    print(" pageSize=%d pageCount=%d\n",
      caTask.pageSize,caTask.pageCount);
    print(" nextpage=%d nextFree=%d\n",
      caTask.nextPage,caTask.nextFree);
    print(" channelCount=%d channelConnected=%d\n",
      caTask.channelCount,caTask.channelConnected);
    if(caTask.nextPage != caTask.pageCount-1) {
	print(" caTask.nextPage != caTask.pageCount-1\n");
    }
#else
  /* Check if all channels are connected */
    if(caTask.channelCount == caTask.channelConnected) {
	medmPostMsg(1,"retryConnections: All channels are connected\n");
	XBell(display, 50);
	return;
    }
#endif

  /* Find an unconnected PV */
    for(i=0; i < caTask.pageCount; i++) {
	int jmax=(i == caTask.nextPage)?caTask.nextFree:CA_PAGE_SIZE;
	for(j=0; j < jmax; j++) {
	    Channel *pCh=&caTask.pages[i][j];
	    if(pCh->chid && ca_state(pCh->chid) != cs_conn) {
		pvname=ca_name(pCh->chid);
		break;
	    }
	}
	if(pvname) break;
    }
#if DEBUG_RETRY
    print(" Found %s\n",pvname?pvname:"Not found");
    if(!pvname) return;
#else
    if(!pvname) {
	medmPostMsg(1,"retryConnections: Failed to find unconnected PV\n");
	return;
    }
#endif

  /* Search */
    status=ca_search_and_connect(pvname,&retryChid,NULL,NULL);
    if(status != ECA_NORMAL) {
	medmPostMsg(1,"retryConnections: ca_search failed for %s: %s\n",
	  pvname, ca_message(status));
    }

  /* Wait.  The searches will only continue for this time.  Keep the
   * time short as the interface is frozen, and most of the searches
   * occur at the start of the sequence.  Testing indicated:
   *
   * RETRY_TIMEOUT Searches
   *      30          15
   *       5          10
   *       3           9
   *       2           9
   *       1           8
   *
   * but this may vary owing to tuning and may change with new releases.
   */
    ca_pend_io(RETRY_TIMEOUT);

  /* Clear the channel */
    status = ca_clear_channel(retryChid);
    if(status != ECA_NORMAL) {
	medmPostMsg(1,"retryConnections: ca_clear_channel failed for %s: %s\n",
	  pvname, ca_message(status));
    }
}
Esempio n. 13
0
void popupPvInfo(DisplayInfo *displayInfo)
{
    DlElement *pE;
    Record **records;
    chid chId;
    int i, status;
    Record *pR;
    Channel *pCh;
    char descName[MAX_TOKEN_LENGTH];
    char *pDot;
    double connTimeout;

#if DEBUG_PVINFO
    XUngrabPointer(display,CurrentTime);
#endif

  /* Check if another call is in progress */
    if(pvInfo) {
	medmPostMsg(1,"popupPvInfo: "
	  "Another PV Info request is already in progress\n"
	  "  It is probably having problems\n"
	  "  Wait for it to finish\n");
	return;
    }

  /* Create the dialog box if it has not been created */
    if(!pvInfoS) createPvInfoDlg();

  /* Get the records */
    records = getPvInfoFromDisplay(displayInfo, &nPvInfoPvs, &pE);
    if(!records) return;
    pvInfoElement = pE;

  /* Allocate space */
    pvInfo = (PvInfo *)calloc(nPvInfoPvs, sizeof(PvInfo));
    if(!pvInfo) {
	medmPostMsg(1,"popupPvInfo: Memory allocation error\n");
	if(records) free(records);
	if(pvInfoS && XtIsManaged(pvInfoS)) return;
    }

  /* Loop over the records, initialize, and initiate search for DESC */
    for(i=0; i < nPvInfoPvs; i++) {
      /* Initialize */
	pvInfo[i].pvChid = NULL;
	pvInfo[i].pvOk = False;
	pvInfo[i].timeOk = False;
	pvInfo[i].descChid = NULL;
	pvInfo[i].descOk = False;
	strcpy(pvInfo[i].descVal, NOT_AVAILABLE);
#if defined(DBR_CLASS_NAME) && DO_RTYP
	pvInfo[i].rtypOk = False;
	strcpy(pvInfo[i].rtypVal, NOT_AVAILABLE);
#endif

      /* Check for a valid record */
	if(records[i]) {
	    pR = pvInfo[i].record = records[i];
	    pCh = getChannelFromRecord(pR);
	    if(!pCh) continue;
	    if(!pCh->chid) continue;
	    chId = pvInfo[i].pvChid = pCh->chid;
	} else continue;
	pvInfo[i].pvOk = True;

      /* Don't try the others unless the PV is connected */
	if(ca_state(chId) != cs_conn || !ca_read_access(chId))
	  continue;

      /* Construct the DESC name */
	strcpy(descName,ca_name(chId));
	pDot = strchr(descName,'.');
	if(pDot) {
	  /* Assume it is a name with a field and replace the field
	   * with DESC */
	    strcpy(pDot,".DESC");
	} else {
	  /* Append .DESC */
	    strcat(descName,".DESC");
	}
      /* Search for the DESC */
	status = ca_search(descName, &pvInfo[i].descChid);
	if(status == ECA_NORMAL) {
	    pvInfo[i].descOk = True;
	} else {
	    medmPostMsg(1,"popupPvInfo: DESC: ca_search for %s: %s\n",
	      descName, ca_message(status));
	}
    }

  /* Free the records, they are now stored in pvInfo */
    if(records) free(records);

  /* Wait for the searches (Timeouts should be uncommon) */
    status=ca_pend_io(CA_PEND_IO_TIME);
    if(status != ECA_NORMAL) {
	medmPostMsg(1,"popupPvInfo: Waited %g seconds.  "
	  "Did not find the DESC information (%s).\n",
	  CA_PEND_IO_TIME, descName);
    }

  /* Loop over the records and do the gets */
    nPvInfoCbs = 0;
    for(i=0; i < nPvInfoPvs; i++) {
	if(!pvInfo[i].pvOk) continue;

      /* Don't try the others unless the PV is connected */
	chId = pvInfo[i].pvChid;
	if(ca_state(chId) != cs_conn || !ca_read_access(chId))
	  continue;

      /* Get the DESC */
	if(ca_state(pvInfo[i].descChid) == cs_conn &&
	  ca_read_access(pvInfo[i].descChid)) {
	  /* Do the get */
	    status = ca_get_callback(DBR_STRING, pvInfo[i].descChid,
	      pvInfoDescGetCb, &pvInfo[i]);
	    if(status == ECA_NORMAL) {
		nPvInfoCbs++;
	    } else {
		pvInfo[i].descOk = False;
		medmPostMsg(1,"pvInfoConnectCb: DESC: ca_array_get_callback"
		  " for %s: %s\n",
		  ca_name(pvInfo[i].descChid), ca_message(status));
	    }
	} else {
	    pvInfo[i].descOk = False;
	}

      /* Get the time value as a string */
	status = ca_get_callback(DBR_TIME_STRING, chId, pvInfoTimeGetCb,
	  &pvInfo[i]);
	if(status == ECA_NORMAL) {
	    nPvInfoCbs++;
	} else {
	    medmPostMsg(1,"popupPvInfo: STAMP: ca_get_callback for %s: %s\n",
	      ca_name(chId), ca_message(status));
	}

#if defined(DBR_CLASS_NAME) && DO_RTYP
      /* Get the RTYP */
	status = ca_get_callback(DBR_CLASS_NAME, chId, pvInfoRtypGetCb,
	  &pvInfo[i]);
	if(status == ECA_NORMAL) {
	    nPvInfoCbs++;
	} else {
	    medmPostMsg(1,"popupPvInfo: RTYP: ca_get_callback for %s: %s\n",
	      ca_name(chId), ca_message(status));
	}
#endif
    }

  /* Add a timeout and poll if there are callbacks
   *   The timeout is a safety net and should never be called
   *   All callbacks should come back inside the EPICS_CA_CONN_TMO
   *   Wait for 2 times this */
    if(nPvInfoCbs) {
	ca_poll();     /* May not be really necessary here */
	status = envGetDoubleConfigParam(&EPICS_CA_CONN_TMO, &connTimeout);
	if (status == 0) pvInfoTime = (unsigned long)(2000.*connTimeout+.5);
	else pvInfoTime = PVINFO_TIMEOUT;
	pvInfoTimeoutId = XtAppAddTimeOut(appContext, pvInfoTime,
	  pvInfoTimeout, NULL);
	pvInfoTimerOn = True;
    } else {
	pvInfoWriteInfo();
    }

#if DEBUG_PVINFO
    print("popupPvInfo: nPvInfoCbs=%d timeout=%ld\n",
      nPvInfoCbs, nPvInfoCbs?pvInfoTime:0L);
#endif
}
Esempio n. 14
0
static int caAdd(char *name, Record *pr)
{
    Channel *pCh;
    int status;

    if((caTask.freeListCount < 1) && (caTask.nextFree >= CA_PAGE_SIZE)) {
      /* if not enough pages, increase number of pages */
	if(caTask.pageCount >= caTask.pageSize) {
	    caTask.pageSize += CA_PAGE_COUNT;
#if defined(__cplusplus) && !defined(__GNUG__)
	    caTask.pages = (Channel **)realloc((malloc_t)caTask.pages,
	      sizeof(Channel *)*caTask.pageSize);
#else
	    caTask.pages = (Channel **)realloc(caTask.pages,
	      sizeof(Channel *)*caTask.pageSize);
#endif
	    if(caTask.pages == NULL) {
		medmPostMsg(1,"caAdd: Memory allocation error\n");
		return -1;
	    }
	}
      /* add one more page */
	caTask.pages[caTask.pageCount] = (Channel *)malloc(sizeof(Channel) *
	  CA_PAGE_SIZE);
	if(caTask.pages[caTask.pageCount] == NULL) {
	    medmPostMsg(1,"caAdd: Memory allocation error\n");
	    return -1;
	}
	caTask.pageCount++;
	caTask.nextPage++;
	caTask.nextFree=0;
    }
    if(caTask.nextFree < CA_PAGE_SIZE) {
	pCh = &((caTask.pages[caTask.nextPage])[caTask.nextFree]);
	pCh->caId = caTask.nextPage * CA_PAGE_SIZE + caTask.nextFree;
	caTask.nextFree++;
    } else {
	int index;
	caTask.freeListCount--;
	index = caTask.freeList[caTask.freeListCount];
	pCh = &((caTask.pages[index/CA_PAGE_SIZE])[index % CA_PAGE_SIZE]);
	pCh->caId = index;
    }

    pCh->data = NULL;
    pCh->chid = NULL;
    pCh->evid = NULL;
    pCh->size = 0;
    pCh->pr = pr;
    pCh->previouslyConnected = False;

  /* Do the search */
    status = ca_search_and_connect(name, &(pCh->chid), medmConnectEventCb,
      pCh);
    if(status != ECA_NORMAL) {
	medmPostMsg(1,"caAdd: ca_search_and_connect failed: %s\n",
	  ca_message(status));
    } else {
      /* Cast to avoid warning from READONLY */
	pCh->pr->name = (char *)ca_name(pCh->chid);
    }
    caTask.channelCount++;
#if DEBUG_ADD
    print("caAdd: %3d name=%s\n",
      caTask.channelCount, name);
#endif
    return pCh->caId;
}