Пример #1
0
int tpn(const char *pname, const char *pvalue)
{
    struct dbChannel *chan;
    tpnInfo *ptpnInfo;
    processNotify *ppn = NULL;

    chan = dbChannel_create(pname);
    if (!chan) {
        printf("Channel couldn't be created\n");
        return 1;
    }

    ppn = calloc(1, sizeof(processNotify));
    if (!ppn) {
        printf("calloc failed\n");
        dbChannelDelete(chan);
        return -1;
    }
    ppn->requestType = putProcessRequest;
    ppn->chan = chan;
    ppn->putCallback = putCallback;
    ppn->doneCallback = doneCallback;

    ptpnInfo = calloc(1, sizeof(tpnInfo));
    if (!ptpnInfo) {
        printf("calloc failed\n");
        free(ppn);
        dbChannelDelete(chan);
        return -1;
    }
    ptpnInfo->ppn = ppn;
    ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
    strncpy(ptpnInfo->buffer, pvalue, 80);
    ptpnInfo->buffer[79] = 0;

    ppn->usrPvt = ptpnInfo;
    epicsThreadCreate("tpn", epicsThreadPriorityHigh,
        epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
    return 0;
}
Пример #2
0
static void tpnThread(void *pvt)
{
    tpnInfo *ptpnInfo = (tpnInfo *) pvt;
    processNotify *ppn = (processNotify *) ptpnInfo->ppn;

    dbProcessNotify(ppn);
    epicsEventWait(ptpnInfo->callbackDone);
    dbNotifyCancel(ppn);
    epicsEventDestroy(ptpnInfo->callbackDone);
    dbChannelDelete(ppn->chan);
    free(ppn);
    free(ptpnInfo);
}
Пример #3
0
static long del_record(dbCommon *pcommon) {
    stringinRecord *prec = (stringinRecord *)pcommon;
    DBLINK *plink = &prec->inp;
    devPvt *pdevPvt = (devPvt *)prec->dpvt;

    if (plink->type == CONSTANT) return 0;
    assert(plink->type == PN_LINK);

    dbNotifyCancel(&pdevPvt->pn);
    dbChannelDelete(pdevPvt->pn.chan);
    free(pdevPvt);

    plink->type = PV_LINK;
    return 0;
}
Пример #4
0
struct dbChannel * dbChannel_create(const char *pname)
{
    dbChannel *chan = dbChannelCreate(pname);

    if (!chan)
        return NULL;

    if (INVALID_DB_REQ(dbChannelExportType(chan)) ||
        dbChannelOpen(chan)) {
        dbChannelDelete(chan);
        return NULL;
    }

    return chan;
}
Пример #5
0
int gft(const char *pname)
{
    char tgf_buffer[MAX_ELEMS*MAX_STRING_SIZE + sizeof(struct dbr_ctrl_double)];
    struct dbChannel *chan;
    struct dbCommon *precord;
    long elements;
    short type;
    int i;

    chan = dbChannel_create(pname);
    if (!chan) {
        printf("Channel couldn't be created\n");
        return 1;
    }

    precord = dbChannelRecord(chan);
    elements = dbChannelElements(chan);
    type = dbChannelExportCAType(chan);

    printf("   Record Name: %s\n", precord->name);
    printf("Record Address: 0x%p\n", precord);
    printf("   Export Type: %d\n", type);
    printf(" Field Address: 0x%p\n", dbChannelField(chan));
    printf("    Field Size: %d\n", dbChannelFieldSize(chan));
    printf("   No Elements: %ld\n", elements);

    if (elements > MAX_ELEMS)
        elements = MAX_ELEMS;

    for (i = 0; i <= LAST_BUFFER_TYPE; i++) {
        if (type == 0) {
            if ((i != DBR_STRING) && (i != DBR_STS_STRING) &&
                (i != DBR_TIME_STRING) && (i != DBR_GR_STRING) &&
                (i != DBR_CTRL_STRING))
                continue;
        }
        if (dbChannel_get(chan, i, tgf_buffer, elements, NULL) < 0)
            printf("\t%s Failed\n", dbr_text[i]);
        else
            ca_dump_dbr(i, elements, tgf_buffer);
    }

    dbChannelDelete(chan);
    return 0;
}
Пример #6
0
/*
 * TPF
 * Test put field
 */
int pft(const char *pname, const char *pvalue)
{
    struct dbChannel *chan;
    struct dbCommon *precord;
    long elements;
    short type;
    char buffer[500];
    short shortvalue;
    long longvalue;
    float floatvalue;
    unsigned char charvalue;
    double doublevalue;

    chan = dbChannel_create(pname);
    if (!chan) {
        printf("Channel couldn't be created\n");
        return 1;
    }

    precord = dbChannelRecord(chan);
    elements = dbChannelElements(chan);
    type = dbChannelExportCAType(chan);

    printf("   Record Name: %s\n", precord->name);
    printf("Record Address: 0x%p\n", precord);
    printf("   Export Type: %d\n", type);
    printf(" Field Address: 0x%p\n", dbChannelField(chan));
    printf("    Field Size: %d\n", dbChannelFieldSize(chan));
    printf("   No Elements: %ld\n", elements);

    if (dbChannel_put(chan, DBR_STRING,pvalue, 1) < 0)
        printf("\n\t failed ");
    if (dbChannel_get(chan, DBR_STRING,buffer, 1, NULL) < 0)
        printf("\n\tfailed");
    else
        ca_dump_dbr(DBR_STRING,1, buffer);

    if (type <= DBF_STRING || type == DBF_ENUM)
        return 0;

    if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
        if (dbChannel_put(chan, DBR_SHORT,&shortvalue, 1) < 0)
            printf("\n\t SHORT failed ");
        if (dbChannel_get(chan, DBR_SHORT,buffer, 1, NULL) < 0)
            printf("\n\t SHORT GET failed");
        else
            ca_dump_dbr(DBR_SHORT,1, buffer);
    }
    if (sscanf(pvalue, "%ld", &longvalue) == 1) {
        if (dbChannel_put(chan, DBR_LONG,&longvalue, 1) < 0)
            printf("\n\t LONG failed ");
        if (dbChannel_get(chan, DBR_LONG,buffer, 1, NULL) < 0)
            printf("\n\t LONG GET failed");
        else
            ca_dump_dbr(DBR_LONG,1, buffer);
    }
    if (epicsScanFloat(pvalue, &floatvalue) == 1) {
        if (dbChannel_put(chan, DBR_FLOAT,&floatvalue, 1) < 0)
            printf("\n\t FLOAT failed ");
        if (dbChannel_get(chan, DBR_FLOAT,buffer, 1, NULL) < 0)
            printf("\n\t FLOAT GET failed");
        else
            ca_dump_dbr(DBR_FLOAT,1, buffer);
    }
    if (epicsScanFloat(pvalue, &floatvalue) == 1) {
        doublevalue = floatvalue;
        if (dbChannel_put(chan, DBR_DOUBLE,&doublevalue, 1) < 0)
            printf("\n\t DOUBLE failed ");
        if (dbChannel_get(chan, DBR_DOUBLE,buffer, 1, NULL) < 0)
            printf("\n\t DOUBLE GET failed");
        else
            ca_dump_dbr(DBR_DOUBLE,1, buffer);
    }
    if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
        charvalue = (unsigned char) shortvalue;
        if (dbChannel_put(chan, DBR_CHAR,&charvalue, 1) < 0)
            printf("\n\t CHAR failed ");
        if (dbChannel_get(chan, DBR_CHAR,buffer, 1, NULL) < 0)
            printf("\n\t CHAR GET failed");
        else
            ca_dump_dbr(DBR_CHAR,1, buffer);
    }
    if (sscanf(pvalue, "%hd", &shortvalue) == 1) {
        if (dbChannel_put(chan, DBR_ENUM,&shortvalue, 1) < 0)
            printf("\n\t ENUM failed ");
        if (dbChannel_get(chan, DBR_ENUM,buffer, 1, NULL) < 0)
            printf("\n\t ENUM GET failed");
        else
            ca_dump_dbr(DBR_ENUM,1, buffer);
    }
    printf("\n");
    dbChannelDelete(chan);
    return (0);
}
Пример #7
0
static void check(short dbr_type) {
    dbChannel *pch;
    db_field_log *pfl, *pfl2;
    dbAddr valaddr;
    dbAddr offaddr;
    const char *offname = NULL, *valname = NULL, *typname = NULL;
    epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19};
    epicsInt32 *ar10_0_1 = ar;
    epicsInt32 ar10_4_1[10] = {14,15,16,17,18,19,10,11,12,13};
    epicsInt32 ar5_0_1[10] = {12,13,14,15,16};
    epicsInt32 ar5_3_1[10] = {15,16,17,18,19};
    epicsInt32 ar5_5_1[10] = {17,18,19,10,11};
    epicsInt32 ar5_9_1[10] = {11,12,13,14,15};
    epicsInt32 ar5_0_2[10] = {12,14,16};
    epicsInt32 ar5_3_2[10] = {15,17,19};
    epicsInt32 ar5_5_2[10] = {17,19,11};
    epicsInt32 ar5_9_2[10] = {11,13,15};
    epicsInt32 ar5_0_3[10] = {12,15};
    epicsInt32 ar5_3_3[10] = {15,18};
    epicsInt32 ar5_5_3[10] = {17,10};
    epicsInt32 ar5_9_3[10] = {11,14};
    epicsInt32 off = 0;

    switch (dbr_type) {
    case DBR_LONG:
        offname = "x.OFF";
        valname = "x.VAL";
        typname = "long";
        break;
    case DBR_DOUBLE:
        offname = "y.OFF";
        valname = "y.VAL";
        typname = "double";
        break;
    case DBR_STRING:
        offname = "z.OFF";
        valname = "z.VAL";
        typname = "string";
        break;
    default:
        testDiag("Invalid data type %d", dbr_type);
    }

    (void) dbNameToAddr(offname, &offaddr);

    (void) dbNameToAddr(valname, &valaddr);
    (void) dbPutField(&valaddr, DBR_LONG, ar, 10);

    /* Default: should not change anything */

    testHead("Ten %s elements from rec, increment 1, full size (default)", typname);
    createAndOpen(valname, "{\"arr\":{}}", "(default)", &pch, 1);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
    TEST1(10, 0, 1, "no offset");
    TEST1(10, 4, 1, "wrapped");
    dbChannelDelete(pch);

    testHead("Ten %s elements from rec, increment 1, out-of-bound start parameter", typname);
    createAndOpen(valname, "{\"arr\":{\"s\":-500}}", "out-of-bound start", &pch, 1);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
    TEST1(10, 4, 1, "wrapped");
    dbChannelDelete(pch);

    testHead("Ten %s elements from rec, increment 1, out-of-bound end parameter", typname);
    createAndOpen(valname, "{\"arr\":{\"e\":500}}", "out-of-bound end", &pch, 1);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
    TEST1(10, 4, 1, "wrapped");
    dbChannelDelete(pch);

    testHead("Ten %s elements from rec, increment 1, zero increment parameter", typname);
    createAndOpen(valname, "{\"arr\":{\"i\":0}}", "zero increment", &pch, 1);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
    TEST1(10, 4, 1, "wrapped");
    dbChannelDelete(pch);

    testHead("Ten %s elements from rec, increment 1, invalid increment parameter", typname);
    createAndOpen(valname, "{\"arr\":{\"i\":-30}}", "invalid increment", &pch, 1);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);
    TEST1(10, 4, 1, "wrapped");
    dbChannelDelete(pch);

#define TEST5(Incr, Left, Right, Type) \
    testHead("Five %s elements from rec, increment " #Incr ", " Type " addressing", typname); \
    createAndOpen(valname, "{\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
                  "(" #Left ":" #Incr ":" #Right ")", &pch, 1); \
    testOk(pch->final_type == valaddr.field_type, \
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
    testOk(pch->final_no_elements == 4 / Incr + 1, \
           "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
    TEST1(5, 0, Incr, "no offset"); \
    TEST1(5, 3, Incr, "from upper block"); \
    TEST1(5, 5, Incr, "wrapped"); \
    TEST1(5, 9, Incr, "from lower block"); \
    dbChannelDelete(pch);

    /* Contiguous block of 5 */

    TEST5(1,  2,  6, "regular");
    TEST5(1, -8,  6, "left side from-end");
    TEST5(1,  2, -4, "right side from-end");
    TEST5(1, -8, -4, "both sides from-end");

    /* 5 elements with increment 2 */

    TEST5(2,  2,  6, "regular");
    TEST5(2, -8,  6, "left side from-end");
    TEST5(2,  2, -4, "right side from-end");
    TEST5(2, -8, -4, "both sides from-end");

    /* 5 elements with increment 3 */

    TEST5(3,  2,  6, "regular");
    TEST5(3, -8,  6, "left side from-end");
    TEST5(3,  2, -4, "right side from-end");
    TEST5(3, -8, -4, "both sides from-end");

    /* From buffer (plugin chain) */

#define TEST5B(Incr, Left, Right, Type) \
    testHead("Five %s elements from buffer, increment " #Incr ", " Type " addressing", typname); \
    createAndOpen(valname, "{\"arr\":{},\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \
                  "(" #Left ":" #Incr ":" #Right ")", &pch, 2); \
    testOk(pch->final_type == valaddr.field_type, \
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \
    testOk(pch->final_no_elements == 4 / Incr + 1, \
           "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \
    TEST1(5, 0, Incr, "no offset"); \
    dbChannelDelete(pch);

    /* Contiguous block of 5 */

    TEST5B(1,  2,  6, "regular");
    TEST5B(1, -8,  6, "left side from-end");
    TEST5B(1,  2, -4, "right side from-end");
    TEST5B(1, -8, -4, "both sides from-end");

    /* 5 elements with increment 2 */

    TEST5B(2,  2,  6, "regular");
    TEST5B(2, -8,  6, "left side from-end");
    TEST5B(2,  2, -4, "right side from-end");
    TEST5B(2, -8, -4, "both sides from-end");

    /* 5 elements with increment 3 */

    TEST5B(3,  2,  6, "regular");
    TEST5B(3, -8,  6, "left side from-end");
    TEST5B(3,  2, -4, "right side from-end");
    TEST5B(3, -8, -4, "both sides from-end");
}
Пример #8
0
static void check(short dbr_type) {
    dbChannel *pch;
    db_field_log *pfl;
    dbAddr valaddr;
    dbAddr offaddr;
    const char *offname = NULL, *valname = NULL, *typname = NULL;
    epicsInt32 buf[26];
    long off, req;
    int i;

    switch (dbr_type) {
    case DBR_LONG:
        offname = "i32.OFF";
        valname = "i32.VAL";
        typname = "long";
        break;
    case DBR_DOUBLE:
        offname = "f64.OFF";
        valname = "f64.VAL";
        typname = "double";
        break;
    case DBR_STRING:
        offname = "c40.OFF";
        valname = "c40.VAL";
        typname = "string";
        break;
    default:
        testDiag("Invalid data type %d", dbr_type);
    }

    (void) dbNameToAddr(offname, &offaddr);
    (void) dbNameToAddr(valname, &valaddr);

    testHead("Ten %s elements", typname);

    /* Fill the record's array field with data, 10..19 */

    epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19};
    (void) dbPutField(&valaddr, DBR_LONG, ar, 10);

    /* Open a channel to it, make sure no filters present */

    createAndOpen(valname, &pch);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);

    /* TEST1 sets the record's OFF field, then requests 10 elements from the channel,
     * passing in a transparent db_field_log and converting the data to LONG on the way in.
     * It checks that it got back the expected data and the right number of elements.
     */

#define TEST1(Size, Offset, Text, Expected) \
    testDiag("Reading from offset = %d (%s)", Offset, Text); \
    off = Offset; req = 10; \
    memset(buf, 0, sizeof(buf)); \
    (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
    pfl = db_create_read_log(pch); \
    testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \
    testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
    testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
    if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
        for (i=0; i<Size; i++) \
            testDiag("Element %d expected %d got %d", i, Expected[i], buf[i]); \
    db_delete_field_log(pfl);

    const epicsInt32 res_10_0[] = {10,11,12,13,14,15,16,17,18,19};
    TEST1(10, 0, "no offset", res_10_0);

    const epicsInt32 res_10_4[] = {14,15,16,17,18,19,10,11,12,13};
    TEST1(10, 4, "wrapped", res_10_4);

    /* Partial array */

    testHead("Five %s elements", typname);
    off = 0;    /* Reset offset for writing the next buffer */
    (void) dbPutField(&offaddr, DBR_LONG, &off, 1);
    (void) dbPutField(&valaddr, DBR_LONG, &ar[5], 5);

    createAndOpen(valname, &pch);
    testOk(pch->final_type == valaddr.field_type,
           "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type);
    testOk(pch->final_no_elements == valaddr.no_elements,
           "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements);

    const epicsInt32 res_5_0[] = {15,16,17,18,19};
    TEST1(5, 0, "no offset", res_5_0);

    const epicsInt32 res_5_3[] = {18,19,15,16,17};
    TEST1(5, 3, "wrapped", res_5_3);

    /* TEST2 sets the record's OFF field, then requests 15 elements from the channel
     * but passes in a db_field_log with alternate data, converting that data to LONG.
     * It checks that it got back the expected data and the right number of elements.
     */

#define TEST2(Size, Offset, Text, Expected) \
    testDiag("Reading from offset = %d (%s)", Offset, Text); \
    off = Offset; req = 15; \
    memset(buf, 0, sizeof(buf)); \
    (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
    pfl = db_create_read_log(pch); \
    pfl->type = dbfl_type_ref; \
    pfl->field_type = DBF_CHAR; \
    pfl->field_size = 1; \
    pfl->no_elements = 26; \
    pfl->u.r.dtor = freeArray; \
    pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \
    testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
    testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
    if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
        for (i=0; i<Size; i++) \
            testDiag("Element %d expected '%c' got '%c'", i, Expected[i], buf[i]); \
    db_delete_field_log(pfl);

    testHead("Fifteen letters from field-log instead of %s", typname);

    const epicsInt32 res_15[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
        'm', 'n', 'o'};
    TEST2(15, 0, "no offset", res_15);
    TEST2(15, 10, "ignored", res_15);

    dbChannelDelete(pch);
}
Пример #9
0
dbChannel * dbChannelCreate(const char *name)
{
    const char *pname = name;
    DBENTRY dbEntry;
    dbChannel *chan = NULL;
    char *cname;
    dbAddr *paddr;
    dbFldDes *pflddes;
    long status;
    short dbfType;

    if (!name || !*name || !pdbbase)
        return NULL;

    status = pvNameLookup(&dbEntry, &pname);
    if (status)
        goto finish;

    chan = freeListCalloc(dbChannelFreeList);
    if (!chan)
        goto finish;
    cname = malloc(strlen(name) + 1);
    if (!cname)
        goto finish;

    strcpy(cname, name);
    chan->name = cname;
    ellInit(&chan->filters);
    ellInit(&chan->pre_chain);
    ellInit(&chan->post_chain);

    paddr = &chan->addr;
    pflddes = dbEntry.pflddes;
    dbfType = pflddes->field_type;

    paddr->precord = dbEntry.precnode->precord;
    paddr->pfield = dbEntry.pfield;
    paddr->pfldDes = pflddes;
    paddr->no_elements = 1;
    paddr->field_type = dbfType;
    paddr->field_size = pflddes->size;
    paddr->special = pflddes->special;
    paddr->dbr_field_type = mapDBFToDBR[dbfType];

    if (paddr->special == SPC_DBADDR) {
        struct rset *prset = dbGetRset(paddr);

        /* Let record type modify paddr */
        if (prset && prset->cvt_dbaddr) {
            status = prset->cvt_dbaddr(paddr);
            if (status)
                goto finish;
            dbfType = paddr->field_type;
        }
    }

    /* Handle field modifiers */
    if (*pname) {
        if (*pname == '$') {
            /* Some field types can be accessed as char arrays */
            if (dbfType == DBF_STRING) {
                paddr->no_elements = paddr->field_size;
                paddr->field_type = DBF_CHAR;
                paddr->field_size = 1;
                paddr->dbr_field_type = DBR_CHAR;
            } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
                /* Clients see a char array, but keep original dbfType */
                paddr->no_elements = PVNAME_STRINGSZ + 12;
                paddr->field_size = 1;
                paddr->dbr_field_type = DBR_CHAR;
            } else {
                status = S_dbLib_fieldNotFound;
                goto finish;
            }
            pname++;
        }

        if (*pname == '[') {
            status = parseArrayRange(chan, pname, &pname);
            if (status) goto finish;
        }

        /* JSON may follow */
        if (*pname == '{') {
            status = chf_parse(chan, &pname);
            if (status) goto finish;
        }

        /* Make sure there's nothing else */
        if (*pname) {
            status = S_dbLib_fieldNotFound;
            goto finish;
        }
    }

finish:
    if (status && chan) {
        dbChannelDelete(chan);
        chan = NULL;
    }
    dbFinishEntry(&dbEntry);
    return chan;
}