Merge branch '7.0' into PSI-7.0

Conflicts:
	modules/database/test/std/link/Makefile
	modules/libcom/src/osi/os/posix/osdMutex.c
	modules/libcom/src/osi/os/vxWorks/osdThread.h
This commit is contained in:
2021-03-24 14:45:02 +01:00
65 changed files with 1007 additions and 560 deletions
+3 -1
View File
@@ -120,7 +120,9 @@ static void ascarCallFunc(const iocshArgBuf *args)
}
/* asDumpHash */
static const iocshFuncDef asDumpHashFuncDef = {"asDumpHash",0,0};
static const iocshFuncDef asDumpHashFuncDef = {"asDumpHash",0,0,
"Show the contents of the hash table used "
"to locate UAGs and HAGs.\n"};
static void asDumpHashCallFunc(const iocshArgBuf *args)
{
asDumpHash();
+3
View File
@@ -19,7 +19,10 @@ BPT_DBD += bptTypeJdegC.dbd
BPT_DBD += bptTypeJdegF.dbd
BPT_DBD += bptTypeKdegC.dbd
BPT_DBD += bptTypeKdegF.dbd
ifneq (inc,$(strip $(MAKECMDGOALS)))
DBD += $(BPT_DBD)
endif
PROD_HOST += makeBpt
+24 -25
View File
@@ -339,7 +339,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
dbCommon *pcommon;
char *pbuffer = *poriginal;
if (!pfl || pfl->type == dbfl_type_rec)
if (!pfl)
field_type = paddr->field_type;
else
field_type = pfl->field_type;
@@ -349,7 +349,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
if( (*options) & DBR_STATUS ) {
unsigned short *pushort = (unsigned short *)pbuffer;
if (!pfl || pfl->type == dbfl_type_rec) {
if (!pfl) {
*pushort++ = pcommon->stat;
*pushort++ = pcommon->sevr;
} else {
@@ -383,7 +383,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
if( (*options) & DBR_TIME ) {
epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
if (!pfl || pfl->type == dbfl_type_rec) {
if (!pfl) {
*ptime++ = pcommon->time.secPastEpoch;
*ptime++ = pcommon->time.nsec;
} else {
@@ -904,22 +904,23 @@ long dbGet(DBADDR *paddr, short dbrType,
if (nRequest && *nRequest == 0)
return 0;
if (!pfl || pfl->type == dbfl_type_rec) {
if (!pfl) {
field_type = paddr->field_type;
no_elements = capacity = paddr->no_elements;
/* Update field info from record
* may modify paddr->pfield
*/
if (paddr->pfldDes->special == SPC_DBADDR &&
(prset = dbGetRset(paddr)) &&
prset->get_array_info) {
status = prset->get_array_info(paddr, &no_elements, &offset);
} else
offset = 0;
} else {
field_type = pfl->field_type;
no_elements = capacity = pfl->no_elements;
}
/* Update field info from record (if neccessary);
* may modify paddr->pfield.
*/
if (!dbfl_has_copy(pfl) &&
paddr->pfldDes->special == SPC_DBADDR &&
(prset = dbGetRset(paddr)) &&
prset->get_array_info) {
status = prset->get_array_info(paddr, &no_elements, &offset);
} else {
offset = 0;
}
@@ -951,7 +952,7 @@ long dbGet(DBADDR *paddr, short dbrType,
goto done;
}
if (!pfl || pfl->type == dbfl_type_rec) {
if (!dbfl_has_copy(pfl)) {
status = dbFastGetConvertRoutine[field_type][dbrType]
(paddr->pfield, pbuf, paddr);
} else {
@@ -964,11 +965,9 @@ long dbGet(DBADDR *paddr, short dbrType,
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
/* not used by dbFastConvert: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
localAddr.pfield = (char *) &pfl->u.v.field;
else
localAddr.pfield = (char *) pfl->u.r.field;
localAddr.pfield = dbfl_pfield(pfl);
status = dbFastGetConvertRoutine[field_type][dbrType]
(localAddr.pfield, pbuf, &localAddr);
}
@@ -979,6 +978,8 @@ long dbGet(DBADDR *paddr, short dbrType,
if (nRequest) {
if (no_elements < *nRequest)
*nRequest = no_elements;
if (capacity < *nRequest)
*nRequest = capacity;
n = *nRequest;
} else {
n = 1;
@@ -995,8 +996,8 @@ long dbGet(DBADDR *paddr, short dbrType,
}
/* convert data into the caller's buffer */
if (n <= 0) {
;/*do nothing*/
} else if (!pfl || pfl->type == dbfl_type_rec) {
; /*do nothing */
} else if (!dbfl_has_copy(pfl)) {
status = convert(paddr, pbuf, n, capacity, offset);
} else {
DBADDR localAddr = *paddr; /* Structure copy */
@@ -1008,11 +1009,9 @@ long dbGet(DBADDR *paddr, short dbrType,
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
/* not used by dbConvert, it uses the passed capacity instead: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
localAddr.pfield = (char *) &pfl->u.v.field;
else
localAddr.pfield = (char *) pfl->u.r.field;
localAddr.pfield = dbfl_pfield(pfl);
status = convert(&localAddr, pbuf, n, capacity, offset);
}
+17 -55
View File
@@ -52,14 +52,12 @@ typedef struct parseContext {
static void *dbChannelFreeList;
static void *chFilterFreeList;
static void *dbchStringFreeList;
void dbChannelExit(void)
{
freeListCleanup(dbChannelFreeList);
freeListCleanup(chFilterFreeList);
freeListCleanup(dbchStringFreeList);
dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
dbChannelFreeList = chFilterFreeList = NULL;
}
void dbChannelInit (void)
@@ -69,7 +67,6 @@ void dbChannelInit (void)
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
db_init_event_freelists();
}
@@ -449,28 +446,6 @@ static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppn
return status;
}
/* Stolen from dbAccess.c: */
static short mapDBFToDBR[DBF_NTYPES] =
{
/* DBF_STRING => */DBR_STRING,
/* DBF_CHAR => */DBR_CHAR,
/* DBF_UCHAR => */DBR_UCHAR,
/* DBF_SHORT => */DBR_SHORT,
/* DBF_USHORT => */DBR_USHORT,
/* DBF_LONG => */DBR_LONG,
/* DBF_ULONG => */DBR_ULONG,
/* DBF_INT64 => */DBR_INT64,
/* DBF_UINT64 => */DBR_UINT64,
/* DBF_FLOAT => */DBR_FLOAT,
/* DBF_DOUBLE => */DBR_DOUBLE,
/* DBF_ENUM, => */DBR_ENUM,
/* DBF_MENU, => */DBR_ENUM,
/* DBF_DEVICE => */DBR_ENUM,
/* DBF_INLINK => */DBR_STRING,
/* DBF_OUTLINK => */DBR_STRING,
/* DBF_FWDLINK => */DBR_STRING,
/* DBF_NOACCESS => */DBR_NOACCESS };
dbChannel * dbChannelCreate(const char *name)
{
const char *pname = name;
@@ -743,37 +718,24 @@ void dbChannelDelete(dbChannel *chan)
freeListFree(dbChannelFreeList, chan);
}
static void freeArray(db_field_log *pfl) {
if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
freeListFree(dbchStringFreeList, pfl->u.r.field);
} else {
free(pfl->u.r.field);
}
}
void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
/*
* Helper function to adjust no_elements, offset, and pfield
* when copying an array from a record.
*/
void dbChannelGetArrayInfo(dbChannel *chan,
void **pfield, long *no_elements, long *offset)
{
void *p;
struct dbCommon *prec = dbChannelRecord(chan);
if (pfl->type != dbfl_type_rec) return;
pfl->type = dbfl_type_ref;
pfl->stat = prec->stat;
pfl->sevr = prec->sevr;
pfl->time = prec->time;
pfl->field_type = chan->addr.field_type;
pfl->no_elements = chan->addr.no_elements;
pfl->field_size = chan->addr.field_size;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = pvt;
if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
p = freeListCalloc(dbchStringFreeList);
} else {
p = calloc(pfl->no_elements, pfl->field_size);
rset *prset;
if (dbChannelSpecial(chan) == SPC_DBADDR &&
(prset = dbGetRset(&chan->addr)) &&
prset->get_array_info)
{
void *pfieldsave = dbChannelField(chan);
/* it is expected that this call always succeeds */
prset->get_array_info(&chan->addr, no_elements, offset);
*pfield = dbChannelField(chan);
dbChannelField(chan) = pfieldsave;
}
if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
pfl->u.r.field = p;
}
/* FIXME: Do these belong in a different file? */
+4 -3
View File
@@ -65,8 +65,8 @@ typedef struct dbChannel {
/* Prototype for the channel event function that is called in filter stacks
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
* If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying
* data out of the associated record.
* Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data,
* as this indicates the data is still owned by the record.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
@@ -225,7 +225,8 @@ DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *p
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len);
DBCORE_API void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan,
void **pfield, long *no_elements, long *offset);
#ifdef __cplusplus
}
+36 -33
View File
@@ -668,27 +668,21 @@ int db_post_extra_labor (dbEventCtx ctx)
return DB_EVENT_OK;
}
/*
* DB_CREATE_EVENT_LOG()
*
* NOTE: This assumes that the db scan lock is already applied
* (as it copies data from the record)
*/
db_field_log* db_create_event_log (struct evSubscrip *pevent)
static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
{
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
if (pLog) {
struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
pLog->ctx = dbfl_context_event;
if (pevent->useValque) {
pLog->stat = prec->stat;
pLog->sevr = prec->sevr;
pLog->time = prec->time;
pLog->field_type = dbChannelFieldType(chan);
pLog->field_size = dbChannelFieldSize(chan);
pLog->no_elements = dbChannelElements(chan);
if (use_val) {
pLog->type = dbfl_type_val;
pLog->stat = prec->stat;
pLog->sevr = prec->sevr;
pLog->time = prec->time;
pLog->field_type = dbChannelFieldType(chan);
pLog->no_elements = dbChannelElements(chan);
/*
* use memcpy to avoid a bus error on
* union copy of char in the db at an odd
@@ -698,23 +692,46 @@ db_field_log* db_create_event_log (struct evSubscrip *pevent)
dbChannelField(chan),
dbChannelFieldSize(chan));
} else {
pLog->type = dbfl_type_rec;
pLog->type = dbfl_type_ref;
/* don't make a copy yet, just reference the field value */
pLog->u.r.field = dbChannelField(chan);
/* indicate field value still owned by record */
pLog->u.r.dtor = NULL;
/* no private data yet, may be set by a filter */
pLog->u.r.pvt = NULL;
}
}
return pLog;
}
/*
* DB_CREATE_EVENT_LOG()
*
* NOTE: This assumes that the db scan lock is already applied
* (as it calls rset->get_array_info)
*/
db_field_log* db_create_event_log (struct evSubscrip *pevent)
{
db_field_log *pLog = db_create_field_log(pevent->chan, pevent->useValque);
if (pLog) {
pLog->ctx = dbfl_context_event;
}
return pLog;
}
/*
* DB_CREATE_READ_LOG()
*
*/
db_field_log* db_create_read_log (struct dbChannel *chan)
{
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
db_field_log *pLog = db_create_field_log(chan,
dbChannelElements(chan) == 1 &&
dbChannelSpecial(chan) != SPC_DBADDR &&
dbChannelFieldSize(chan) <= sizeof(union native_value));
if (pLog) {
pLog->ctx = dbfl_context_read;
pLog->type = dbfl_type_rec;
}
return pLog;
}
@@ -737,20 +754,6 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
LOCKEVQUE (ev_que);
/*
* if we have an event on the queue and both the last
* event on the queue and the current event are emtpy
* (i.e. of type dbfl_type_rec), simply ignore duplicate
* events (saving empty events serves no purpose)
*/
if (pevent->npend > 0u &&
(*pevent->pLastLog)->type == dbfl_type_rec &&
pLog->type == dbfl_type_rec) {
db_delete_field_log(pLog);
UNLOCKEVQUE (ev_que);
return;
}
/*
* add to task local event que
*/
+20 -50
View File
@@ -14,11 +14,12 @@
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*
* based on dbConvert.c
* based on dbConvert.c, see copyNoConvert
* written by: Bob Dalesio, Marty Kraimer
*/
#include <string.h>
#include <assert.h>
#include "epicsTypes.h"
@@ -26,61 +27,30 @@
#include "dbAddr.h"
#include "dbExtractArray.h"
void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,
long nRequest, long no_elements, long offset, long increment)
void dbExtractArray(const void *pfrom, void *pto, short field_size,
long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
char *psrc = (char *) paddr->pfield;
long nUpperPart;
int i;
short srcSize = paddr->field_size;
short dstSize = srcSize;
char isString = (paddr->field_type == DBF_STRING);
const char *psrc = (char *) pfrom;
if (nRequest > no_elements) nRequest = no_elements;
if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;
if (increment == 1 && dstSize == srcSize) {
nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;
memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart);
if (nRequest > nUpperPart)
memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart));
if (isString)
for (i = 1; i <= nRequest; i++)
pdst[dstSize*i-1] = '\0';
} else {
for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) {
offset %= no_elements;
memcpy(pdst, &psrc[offset*srcSize], dstSize);
if (isString) pdst[dstSize-1] = '\0';
}
}
}
void dbExtractArrayFromBuf(const void *pfrom, void *pto,
short field_size, short field_type,
long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
char *psrc = (char *) pfrom;
int i;
short srcSize = field_size;
short dstSize = srcSize;
char isString = (field_type == DBF_STRING);
if (nRequest > no_elements) nRequest = no_elements;
if (offset > no_elements - 1) offset = no_elements - 1;
if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1;
/* assert preconditions */
assert(nRequest >= 0);
assert(no_elements >= 0);
assert(increment > 0);
assert(0 <= offset);
assert(offset < no_elements);
if (increment == 1) {
memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest);
if (isString)
for (i = 1; i <= nRequest; i++)
pdst[dstSize*i] = '\0';
long nUpperPart =
nRequest < no_elements - offset ? nRequest : no_elements - offset;
memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart);
if (nRequest > nUpperPart)
memcpy(pdst + (field_size * nUpperPart), psrc,
field_size * (nRequest - nUpperPart));
} else {
for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) {
memcpy(pdst, &psrc[offset*srcSize], dstSize);
if (isString) pdst[dstSize] = '\0';
for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) {
offset %= no_elements;
memcpy(pdst, psrc + (offset * field_size), field_size);
}
}
}
+30 -5
View File
@@ -22,11 +22,36 @@
extern "C" {
#endif
epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto,
long nRequest, long no_elements, long offset, long increment);
epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto,
short field_size, short field_type,
long nRequest, long no_elements, long offset, long increment);
/** @brief Make a copy of parts of an array.
*
* The source array may or may not be a record field.
*
* The increment parameter is used to support array filters; it
* means: copy only every increment'th element, starting at offset.
*
* The offset and no_elements parameters are used to support the
* circular buffer feature of record fields: elements before offset
* are treated as if they came right after no_elements.
*
* This function does not do any conversion on the array elements.
*
* Preconditions:
* nRequest >= 0, no_elements >= 0, increment > 0
* 0 <= offset < no_elements
* pto points to a buffer with at least field_size*nRequest bytes
* pfrom points to a buffer with exactly field_size*no_elements bytes
*
* @param pfrom Pointer to source array.
* @param pto Pointer to target array.
* @param field_size Size of an array element.
* @param nRequest Number of elements to copy.
* @param no_elements Number of elements in source array.
* @param offset Wrap-around point in source array.
* @param increment Copy only every increment'th element.
*/
epicsShareFunc void dbExtractArray(const void *pfrom, void *pto,
short field_size, long nRequest, long no_elements, long offset,
long increment);
#ifdef __cplusplus
}
+73 -28
View File
@@ -112,12 +112,13 @@ union anybuf {
long testdbVPutField(const char* pv, short dbrType, va_list ap)
{
DBADDR addr;
dbChannel *chan = dbChannelCreate(pv);
union anybuf pod;
long ret = S_dbLib_recNotFound;
if (dbNameToAddr(pv, &addr)) {
testFail("Missing PV \"%s\"", pv);
return S_dbLib_recNotFound;
if(!chan || (ret=dbChannelOpen(chan))) {
testFail("Channel error (%p, %ld) : %s", chan, ret, pv);
goto done;
}
switch(dbrType) {
@@ -125,14 +126,18 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
const char *uarg = va_arg(ap,char*);
strncpy(pod.valStr, uarg, sizeof(pod.valStr));
pod.valStr[sizeof(pod.valStr)-1] = '\0';
return dbPutField(&addr, dbrType, pod.valStr, 1);
ret = dbChannelPutField(chan, dbrType, pod.valStr, 1);
break;
}
/* The Type parameter takes into consideration
* the C language rules for promotion of argument types
* in variadic functions.
*/
#define OP(DBR,Type,mem) case DBR: {pod.val.mem = va_arg(ap,Type); break;}
#define OP(DBR,Type,mem) case DBR: \
pod.val.mem = va_arg(ap,Type); \
ret = dbChannelPutField(chan, dbrType, pod.bytes, 1); \
break;
OP(DBR_CHAR, int, int8);
OP(DBR_UCHAR, int, uInt8);
OP(DBR_SHORT, int, int16);
@@ -147,11 +152,15 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap)
#undef OP
default:
testFail("invalid DBR: dbPutField(\"%s\", %d, ...)",
addr.precord->name, dbrType);
return S_db_badDbrtype;
dbChannelName(chan), dbrType);
ret = S_db_badDbrtype;
break;
}
return dbPutField(&addr, dbrType, pod.bytes, 1);
done:
if(chan)
dbChannelDelete(chan);
return ret;
}
void testdbPutFieldOk(const char* pv, int dbrType, ...)
@@ -190,23 +199,35 @@ void testdbGetFieldEqual(const char* pv, int dbrType, ...)
void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
{
DBADDR addr;
dbChannel *chan = dbChannelCreate(pv);
db_field_log *pfl = NULL;
long nReq = 1;
union anybuf pod;
long status;
long status = S_dbLib_recNotFound;
if(dbNameToAddr(pv, &addr)) {
testFail("Missing PV \"%s\"", pv);
return;
if(!chan || (status=dbChannelOpen(chan))) {
testFail("Channel error (%p, %ld) : %s", chan, status, pv);
goto done;
}
status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);
if(ellCount(&chan->filters)) {
pfl = db_create_read_log(chan);
if (!pfl) {
testFail("can't db_create_read_log w/ %s", pv);
goto done;
}
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
status = dbChannelGetField(chan, dbrType, pod.bytes, NULL, &nReq, pfl);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
return;
goto done;
} else if(nReq==0) {
testFail("dbGetField(\"%s\", %d, ...) -> zero length", pv, dbrType);
return;
goto done;
}
switch(dbrType) {
@@ -236,35 +257,56 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
default:
testFail("dbGetField(\"%s\", %d) -> unsupported dbf", pv, dbrType);
}
done:
db_delete_field_log(pfl);
if(chan)
dbChannelDelete(chan);
}
void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf)
{
DBADDR addr;
dbChannel *chan = dbChannelCreate(pv);
long status;
if (dbNameToAddr(pv, &addr)) {
testFail("Missing PV \"%s\"", pv);
return;
if(!chan || (status=dbChannelOpen(chan))) {
testFail("Channel error (%p, %ld) : %s", chan, status, pv);
goto done;
}
status = dbPutField(&addr, dbrType, pbuf, count);
status = dbChannelPutField(chan, dbrType, pbuf, count);
testOk(status==0, "dbPutField(\"%s\", dbr=%d, count=%lu, ...) -> %ld", pv, dbrType, count, status);
done:
if(chan)
dbChannelDelete(chan);
}
void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw)
{
DBADDR addr;
dbChannel *chan = dbChannelCreate(pv);
db_field_log *pfl = NULL;
const long vSize = dbValueSize(dbfType);
const long nStore = vSize * nRequest;
long status;
long status = S_dbLib_recNotFound;
char *gbuf, *gstore;
const char *pbuf = pbufraw;
if(dbNameToAddr(pv, &addr)) {
testFail("Missing PV \"%s\"", pv);
return;
if(!chan || (status=dbChannelOpen(chan))) {
testFail("Channel error (%p, %ld) : %s", chan, status, pv);
goto done;
}
if(ellCount(&chan->filters)) {
pfl = db_create_read_log(chan);
if (!pfl) {
testFail("can't db_create_read_log w/ %s", pv);
goto done;
}
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
gbuf = gstore = malloc(nStore);
@@ -273,7 +315,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
return;
}
status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL);
status = dbChannelGetField(chan, dbfType, gbuf, NULL, &nRequest, pfl);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
@@ -318,7 +360,10 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
testOk(match, "dbGetField(\"%s\", dbrType=%d, nRequest=%ld ...) match", pv, dbfType, nRequest);
}
done:
free(gstore);
if(chan)
dbChannelDelete(chan);
}
dbCommon* testdbRecordPtr(const char* pv)
+35 -27
View File
@@ -57,20 +57,31 @@ union native_value {
struct db_field_log;
typedef void (dbfl_freeFunc)(struct db_field_log *pfl);
/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */
/*
* A db_field_log has one of two types:
*
* dbfl_type_ref - Reference to value
* Used for variable size (array) data types. Meta-data
* is stored in the field log, but value data is stored externally.
* Only the dbfl_ref side of the data union is valid.
*
* dbfl_type_val - Internal value
* Used to store small scalar data. Meta-data and value are
* present in this structure and no external references are used.
* Only the dbfl_val side of the data union is valid.
*/
typedef enum dbfl_type {
dbfl_type_rec = 0,
dbfl_type_val,
dbfl_type_ref
} dbfl_type;
/* Context of db_field_log: event = subscription update, read = read reply */
typedef enum dbfl_context {
dbfl_context_read = 0,
dbfl_context_read,
dbfl_context_event
} dbfl_context;
#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")
#define dbflTypeStr(t) (t==dbfl_type_val?"val":"ref")
struct dbfl_val {
union native_value field; /* Field value */
@@ -82,6 +93,8 @@ struct dbfl_val {
* db_delete_field_log(). Any code which changes a dbfl_type_ref
* field log to another type, or to reference different data,
* must explicitly call the dtor function.
* If the dtor is NULL and no_elements > 0, then this means the array
* data is still owned by a record. See the macro dbfl_has_copy below.
*/
struct dbfl_ref {
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
@@ -89,8 +102,11 @@ struct dbfl_ref {
void *field; /* Field value */
};
/*
* Note that field_size may be larger than MAX_STRING_SIZE.
*/
typedef struct db_field_log {
unsigned int type:2; /* type (union) selector */
unsigned int type:1; /* type (union) selector */
/* ctx is used for all types */
unsigned int ctx:1; /* context (operation type) */
/* the following are used for value and reference types */
@@ -98,8 +114,8 @@ typedef struct db_field_log {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
short field_type; /* DBF type of data */
short field_size; /* Data size */
long no_elements; /* No of array elements */
short field_size; /* Size of a single element */
long no_elements; /* No of valid array elements */
union {
struct dbfl_val v;
struct dbfl_ref r;
@@ -107,27 +123,19 @@ typedef struct db_field_log {
} db_field_log;
/*
* A db_field_log will in one of three types:
*
* dbfl_type_rec - Reference to record
* The field log stores no data itself. Data must instead be taken
* via the dbChannel* which must always be provided when along
* with the field log.
* For this type only the 'type' and 'ctx' members are used.
*
* dbfl_type_ref - Reference to outside value
* Used for variable size (array) data types. Meta-data
* is stored in the field log, but value data is stored externally
* (see struct dbfl_ref).
* For this type all meta-data members are used. The dbfl_ref side of the
* data union is used.
*
* dbfl_type_val - Internal value
* Used to store small scalar data. Meta-data and value are
* present in this structure and no external references are used.
* For this type all meta-data members are used. The dbfl_val side of the
* data union is used.
* Whether a db_field_log* owns the field data. If this is the case, then the
* db_field_log is fully decoupled from the record: there is no need to lock
* the record when accessing the data, nor to call any rset methods (like
* get_array_info) because this has already been done when we made the copy. A
* special case here is that of no (remaining) data (i.e. no_elements==0). In
* this case, making a copy is redundant, so we have no dtor. But conceptually
* the db_field_log still owns the (empty) data.
*/
#define dbfl_has_copy(p)\
((p) && ((p)->type==dbfl_type_val || (p)->u.r.dtor || (p)->no_elements==0))
#define dbfl_pfield(p)\
((p)->type==dbfl_type_val ? &p->u.v.field : p->u.r.field)
#ifdef __cplusplus
}
@@ -34,8 +34,10 @@ static void dbDumpPathCallFunc(const iocshArgBuf *args)
static const iocshArg dbDumpRecordArg2 = { "interest level",iocshArgInt};
static const iocshArg * const dbDumpRecordArgs[] =
{&argPdbbase, &argRecType, &dbDumpRecordArg2};
static const iocshFuncDef dbDumpRecordFuncDef =
{"dbDumpRecord",3,dbDumpRecordArgs};
static const iocshFuncDef dbDumpRecordFuncDef = {"dbDumpRecord",3,dbDumpRecordArgs,
"Dump information about the recordTypeName with 'interest level' details.\n"
"Example: dbDumpRecord ai 2\n"
"If last argument(s) are missing, dump all recordType information in the database.\n"};
static void dbDumpRecordCallFunc(const iocshArgBuf *args)
{
dbDumpRecord(*iocshPpdbbase,args[1].sval,args[2].ival);
@@ -45,7 +47,10 @@ static void dbDumpRecordCallFunc(const iocshArgBuf *args)
static const iocshArg dbDumpMenuArg1 = { "menuName",iocshArgString};
static const iocshArg * const dbDumpMenuArgs[] = {
&argPdbbase, &dbDumpMenuArg1};
static const iocshFuncDef dbDumpMenuFuncDef = {"dbDumpMenu",2,dbDumpMenuArgs};
static const iocshFuncDef dbDumpMenuFuncDef = {"dbDumpMenu",2,dbDumpMenuArgs,
"Dump information about the available menuNames and choices defined withing each menuName.\n"
"Example: dbDumpMenu pdbbase menuAlarmStat \n"
"If last argument(s) are missing, dump all menuNames information in the database.\n"};
static void dbDumpMenuCallFunc(const iocshArgBuf *args)
{
dbDumpMenu(*iocshPpdbbase,args[1].sval);
@@ -54,8 +59,10 @@ static void dbDumpMenuCallFunc(const iocshArgBuf *args)
/* dbDumpRecordType */
static const iocshArg * const dbDumpRecordTypeArgs[] =
{&argPdbbase, &argRecType};
static const iocshFuncDef dbDumpRecordTypeFuncDef =
{"dbDumpRecordType",2,dbDumpRecordTypeArgs};
static const iocshFuncDef dbDumpRecordTypeFuncDef = {"dbDumpRecordType",2,dbDumpRecordTypeArgs,
"Dump information about available fields in the recortTypeName sorted by index and name.\n"
"Example: dbDumpRecordType pdbbase calcout\n"
"If last argument(s) are missing, dump fields information for all records in the database.\n"};
static void dbDumpRecordTypeCallFunc(const iocshArgBuf *args)
{
dbDumpRecordType(*iocshPpdbbase,args[1].sval);
@@ -65,7 +72,11 @@ static void dbDumpRecordTypeCallFunc(const iocshArgBuf *args)
static const iocshArg dbDumpFieldArg2 = { "fieldName",iocshArgString};
static const iocshArg * const dbDumpFieldArgs[] =
{&argPdbbase, &argRecType,&dbDumpFieldArg2};
static const iocshFuncDef dbDumpFieldFuncDef = {"dbDumpField",3,dbDumpFieldArgs};
static const iocshFuncDef dbDumpFieldFuncDef = {"dbDumpField",3,dbDumpFieldArgs,
"Dump information about the fieldName in the recordTypeName.\n"
"Example: dbDumpField pdbbase calcout A\n"
"If last argument(s) are missing, dump information\n"
"about all fieldName in all recordTypeName in the database.\n"};
static void dbDumpFieldCallFunc(const iocshArgBuf *args)
{
dbDumpField(*iocshPpdbbase,args[1].sval,args[2].sval);
@@ -74,7 +85,11 @@ static void dbDumpFieldCallFunc(const iocshArgBuf *args)
/* dbDumpDevice */
static const iocshArg * const dbDumpDeviceArgs[] = {
&argPdbbase, &argRecType};
static const iocshFuncDef dbDumpDeviceFuncDef = {"dbDumpDevice",2,dbDumpDeviceArgs};
static const iocshFuncDef dbDumpDeviceFuncDef = {"dbDumpDevice",2,dbDumpDeviceArgs,
"Dump device support information for the recordTypeName.\n"
"Example: dbDumpDevice pdbbase ai\n"
"If last argument(s) are missing, dump device support\n"
"information for all records in the database.\n"};
static void dbDumpDeviceCallFunc(const iocshArgBuf *args)
{
dbDumpDevice(*iocshPpdbbase,args[1].sval);
@@ -82,7 +97,9 @@ static void dbDumpDeviceCallFunc(const iocshArgBuf *args)
/* dbDumpDriver */
static const iocshArg * const dbDumpDriverArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs};
static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs,
"Dump device support information.\n"
"Example: dbDumpDriver pdbbase\n"};
static void dbDumpDriverCallFunc(const iocshArgBuf *args)
{
dbDumpDriver(*iocshPpdbbase);
@@ -98,7 +115,10 @@ static void dbDumpLinkCallFunc(const iocshArgBuf *args)
/* dbDumpRegistrar */
static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs};
static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs,
"Dump list of registered functions including ones for subroutine records,\n"
"and ones that can be invoked from iocsh.\n"
"Example: dbDumpRegistrar pdbbase\n"};
static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
{
dbDumpRegistrar(*iocshPpdbbase);
@@ -106,7 +126,9 @@ static void dbDumpRegistrarCallFunc(const iocshArgBuf *args)
/* dbDumpFunction */
static const iocshArg * const dbDumpFunctionArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs};
static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs,
"Dump list of registered subroutine functions.\n"
"Example: dbDumpFunction pddbase\n"};
static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
{
dbDumpFunction(*iocshPpdbbase);
@@ -114,7 +136,9 @@ static void dbDumpFunctionCallFunc(const iocshArgBuf *args)
/* dbDumpVariable */
static const iocshArg * const dbDumpVariableArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs};
static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs,
"Dump list of variables used in the database.\n"
"Example: dbDumpVariable pddbase\n"};
static void dbDumpVariableCallFunc(const iocshArgBuf *args)
{
dbDumpVariable(*iocshPpdbbase);
@@ -124,8 +148,7 @@ static void dbDumpVariableCallFunc(const iocshArgBuf *args)
static const iocshArg dbDumpBreaktableArg1 = { "tableName",iocshArgString};
static const iocshArg * const dbDumpBreaktableArgs[] =
{&argPdbbase,&dbDumpBreaktableArg1};
static const iocshFuncDef dbDumpBreaktableFuncDef =
{"dbDumpBreaktable",2,dbDumpBreaktableArgs};
static const iocshFuncDef dbDumpBreaktableFuncDef = {"dbDumpBreaktable",2,dbDumpBreaktableArgs};
static void dbDumpBreaktableCallFunc(const iocshArgBuf *args)
{
dbDumpBreaktable(*iocshPpdbbase,args[1].sval);
@@ -145,8 +168,7 @@ static void dbPvdDumpCallFunc(const iocshArgBuf *args)
static const iocshArg dbPvdTableSizeArg0 = { "size",iocshArgInt};
static const iocshArg * const dbPvdTableSizeArgs[1] =
{&dbPvdTableSizeArg0};
static const iocshFuncDef dbPvdTableSizeFuncDef =
{"dbPvdTableSize",1,dbPvdTableSizeArgs};
static const iocshFuncDef dbPvdTableSizeFuncDef = {"dbPvdTableSize",1,dbPvdTableSizeArgs};
static void dbPvdTableSizeCallFunc(const iocshArgBuf *args)
{
dbPvdTableSize(args[0].ival);
@@ -154,8 +176,7 @@ static void dbPvdTableSizeCallFunc(const iocshArgBuf *args)
/* dbReportDeviceConfig */
static const iocshArg * const dbReportDeviceConfigArgs[] = {&argPdbbase};
static const iocshFuncDef dbReportDeviceConfigFuncDef = {
"dbReportDeviceConfig",1,dbReportDeviceConfigArgs};
static const iocshFuncDef dbReportDeviceConfigFuncDef = {"dbReportDeviceConfig",1,dbReportDeviceConfigArgs};
static void dbReportDeviceConfigCallFunc(const iocshArgBuf *args)
{
dbReportDeviceConfig(*iocshPpdbbase,stdout);
+2 -2
View File
@@ -301,11 +301,11 @@ static void makeSubstitutions(inputData * const inputPvt,
char *pstart;
char *pend;
int cmdind=-1;
int i;
size_t i;
for (i = 0; i < NELEMENTS(cmdNames); i++) {
if (strstr(command, cmdNames[i])) {
cmdind = i;
cmdind = (int)i;
}
}
if (cmdind < 0) goto endcmd;
@@ -20,35 +20,43 @@
#include "miscIocRegister.h"
/* iocInit */
static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL};
static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL,
"Initializes the various epics components and starts the IOC running.\n"};
static void iocInitCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocInit());
}
/* iocBuild */
static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL};
static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL,
"First step of the IOC initialization, puts the IOC into a ready-to-run (quiescent) state.\n"
"Needs iocRun() to make the IOC live.\n"};
static void iocBuildCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocBuild());
}
/* iocRun */
static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL};
static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL,
"Bring the IOC out of its initial quiescent state to the running state.\n"
"See more: iocBuild, iocPause"};
static void iocRunCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocRun());
}
/* iocPause */
static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL};
static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL,
"Brings a running IOC to a quiescent state with all record processing frozen.\n"
"See more: iocBuild, iocRub, iocInit"};
static void iocPauseCallFunc(const iocshArgBuf *args)
{
iocshSetError(iocPause());
}
/* coreRelease */
static const iocshFuncDef coreReleaseFuncDef = {"coreRelease",0,NULL};
static const iocshFuncDef coreReleaseFuncDef = {"coreRelease",0,NULL,
"Print release information for iocCore.\n"};
static void coreReleaseCallFunc(const iocshArgBuf *args)
{
coreRelease ();
@@ -75,7 +83,11 @@ void miscIocRegister(void)
#ifndef SYSTEM_UNAVAILABLE
static const iocshArg systemArg0 = { "command string",iocshArgString};
static const iocshArg * const systemArgs[] = {&systemArg0};
static const iocshFuncDef systemFuncDef = {"system",1,systemArgs};
static const iocshFuncDef systemFuncDef = {"system",1,systemArgs,
"Send command string to the system command interpreter for execution.\n"
"Not available on all OSs.\n"
"To enable this command, add registrar(iocshSystemCommand) to an application dbd file,\n"
"or include system.dbd\n"};
static void systemCallFunc(const iocshArgBuf *args)
{
iocshSetError(system(args[0].sval));
@@ -20,7 +20,12 @@
/* casr */
static const iocshArg casrArg0 = { "level",iocshArgInt};
static const iocshArg * const casrArgs[1] = {&casrArg0};
static const iocshFuncDef casrFuncDef = {"casr",1,casrArgs};
static const iocshFuncDef casrFuncDef = {"casr",1,casrArgs,
"Channel Access Server Report with following levels:\n"
" 0 - servers protocol version level and summary for each attached client\n"
" 1 - extends report with information about connected clients and beacons\n"
" 2 - extends report with specific channel names and UDP search requests\n"
" 3+ - expert\n"};
static void casrCallFunc(const iocshArgBuf *args)
{
casr(args[0].ival);
+39 -73
View File
@@ -13,16 +13,14 @@
#include <stdio.h>
#include <freeList.h>
#include <dbAccess.h>
#include <dbExtractArray.h>
#include <db_field_log.h>
#include <dbLock.h>
#include <recSup.h>
#include <epicsExit.h>
#include <special.h>
#include <chfPlugin.h>
#include <epicsExport.h>
#include "chfPlugin.h"
#include "dbAccessDefs.h"
#include "dbExtractArray.h"
#include "db_field_log.h"
#include "dbLock.h"
#include "epicsExit.h"
#include "freeList.h"
#include "epicsExport.h"
typedef struct myStruct {
epicsInt32 start;
@@ -46,6 +44,8 @@ static void * allocPvt(void)
myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
if (!my) return NULL;
/* defaults */
my->start = 0;
my->incr = 1;
my->end = -1;
return (void *) my;
@@ -77,8 +77,6 @@ static void freeArray(db_field_log *pfl)
static long wrapArrayIndices(long *start, const long increment, long *end,
const long no_elements)
{
long len = 0;
if (*start < 0) *start = no_elements + *start;
if (*start < 0) *start = 0;
if (*start > no_elements) *start = no_elements;
@@ -87,85 +85,53 @@ static long wrapArrayIndices(long *start, const long increment, long *end,
if (*end < 0) *end = 0;
if (*end >= no_elements) *end = no_elements - 1;
if (*end - *start >= 0) len = 1 + (*end - *start) / increment;
return len;
if (*end - *start >= 0)
return 1 + (*end - *start) / increment;
else
return 0;
}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
{
myStruct *my = (myStruct*) pvt;
struct dbCommon *prec;
rset *prset;
int must_lock;
long start = my->start;
long end = my->end;
long nTarget = 0;
long nTarget;
void *pTarget;
long offset = 0;
long nSource = dbChannelElements(chan);
long capacity = nSource;
void *pdst;
long nSource = pfl->no_elements;
void *pSource = pfl->u.r.field;
switch (pfl->type) {
case dbfl_type_val:
/* Only filter arrays */
/* TODO Treat scalars as arrays with 1 element */
break;
case dbfl_type_rec:
/* Extract from record */
if (dbChannelSpecial(chan) == SPC_DBADDR &&
nSource > 1 &&
(prset = dbGetRset(&chan->addr)) &&
prset->get_array_info)
{
void *pfieldsave = dbChannelField(chan);
prec = dbChannelRecord(chan);
dbScanLock(prec);
prset->get_array_info(&chan->addr, &nSource, &offset);
nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
pfl->type = dbfl_type_ref;
pfl->stat = prec->stat;
pfl->sevr = prec->sevr;
pfl->time = prec->time;
pfl->field_type = dbChannelFieldType(chan);
pfl->field_size = dbChannelFieldSize(chan);
pfl->no_elements = nTarget;
if (nTarget) {
pdst = freeListCalloc(my->arrayFreeList);
if (pdst) {
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = my->arrayFreeList;
offset = (offset + start) % dbChannelElements(chan);
dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity,
offset, my->incr);
pfl->u.r.field = pdst;
}
}
dbScanUnlock(prec);
dbChannelField(chan) = pfieldsave;
}
break;
/* Extract from buffer */
case dbfl_type_ref:
pdst = NULL;
nSource = pfl->no_elements;
nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
pfl->no_elements = nTarget;
if (nTarget) {
/* Copy the data out */
void *psrc = pfl->u.r.field;
pdst = freeListCalloc(my->arrayFreeList);
if (!pdst) break;
offset = start;
dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,
nTarget, nSource, offset, my->incr);
must_lock = !pfl->u.r.dtor;
if (must_lock) {
dbScanLock(dbChannelRecord(chan));
dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
}
if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
if (nTarget) {
nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
if (nTarget > 0) {
/* copy the data */
pTarget = freeListCalloc(my->arrayFreeList);
if (!pTarget) break;
/* must do the wrap-around with the original no_elements */
offset = (offset + start) % pfl->no_elements;
dbExtractArray(pSource, pTarget, pfl->field_size,
nTarget, pfl->no_elements, offset, my->incr);
if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
pfl->u.r.field = pTarget;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = my->arrayFreeList;
pfl->u.r.field = pdst;
}
/* adjust no_elements (even if zero elements remain) */
pfl->no_elements = nTarget;
if (must_lock)
dbScanUnlock(dbChannelRecord(chan));
break;
}
return pfl;
+32 -9
View File
@@ -12,21 +12,44 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <chfPlugin.h>
#include <dbLock.h>
#include <db_field_log.h>
#include <epicsExport.h>
#include "chfPlugin.h"
#include "db_field_log.h"
#include "dbExtractArray.h"
#include "dbLock.h"
#include "epicsExport.h"
/*
* The size of the data is different for each channel, and can even
* change at runtime, so a freeList doesn't make much sense here.
*/
static void freeArray(db_field_log *pfl) {
free(pfl->u.r.field);
}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
epicsTimeStamp now;
epicsTimeGetCurrent(&now);
/* If string or array, must make a copy (to ensure coherence between time and data) */
if (pfl->type == dbfl_type_rec) {
dbScanLock(dbChannelRecord(chan));
dbChannelMakeArrayCopy(pvt, pfl, chan);
dbScanUnlock(dbChannelRecord(chan));
/* If reference and not already copied,
must make a copy (to ensure coherence between time and data) */
if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) {
void *pTarget = calloc(pfl->no_elements, pfl->field_size);
void *pSource = pfl->u.r.field;
if (pTarget) {
long offset = 0;
long nSource = pfl->no_elements;
dbScanLock(dbChannelRecord(chan));
dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
dbExtractArray(pSource, pTarget, pfl->field_size,
nSource, pfl->no_elements, offset, 1);
pfl->u.r.field = pTarget;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = pvt;
dbScanUnlock(dbChannelRecord(chan));
}
}
pfl->time = now;
+4 -1
View File
@@ -67,13 +67,16 @@ sub toDeclaration {
my $name = $this->name;
my $macro_name = "${name}_NUM_CHOICES";
my @choices = map {
sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]);
sprintf " %-31s /**< \@brief State string \"%s\" */",
@{$_}[0], escapeCcomment(@{$_}[1]);
} $this->choices;
my $num = scalar @choices;
return "#ifndef $macro_name\n" .
"/** \@brief Enumerated type from menu $name */\n" .
"typedef enum {\n" .
join(",\n", @choices) .
"\n} $name;\n" .
"/** \@brief Number of states defined for menu $name */\n" .
"#define $macro_name $num\n" .
"#endif\n\n";
}
+3 -3
View File
@@ -185,7 +185,7 @@ sub toDeclaration {
my $name = $this->C_name;
my $result = sprintf " %-19s %-12s", $ctype, "$name;";
my $prompt = $this->attribute('prompt');
$result .= "/* $prompt */" if defined $prompt;
$result .= "/**< \@brief $prompt */" if defined $prompt;
return $result;
}
@@ -217,7 +217,7 @@ sub toDeclaration {
my $size = $this->attribute('size');
my $result = sprintf " %-19s %-12s", 'char', "${name}[${size}];";
my $prompt = $this->attribute('prompt');
$result .= "/* $prompt */" if defined $prompt;
$result .= "/**< \@brief $prompt */" if defined $prompt;
return $result;
}
@@ -540,7 +540,7 @@ sub toDeclaration {
my $extra = $this->attribute('extra');
my $result = sprintf " %-31s ", "$extra;";
my $prompt = $this->attribute('prompt');
$result .= "/* $prompt */" if defined $prompt;
$result .= "/**< \@brief $prompt */" if defined $prompt;
return $result;
}
+9 -4
View File
@@ -132,10 +132,15 @@ sub toDeclaration {
$_->toDeclaration
} $this->fields;
my $name = $this->name;
$name .= "Record" unless $name eq "dbCommon";
return "typedef struct $name {\n" .
join("\n", @fields) .
"\n} $name;\n\n";
my $doc = $name;
if ($name ne 'dbCommon') {
$name .= 'Record';
$doc .= ' record type.';
}
return "/** \@brief Declaration of $doc */\n" .
"typedef struct $name {\n" .
join("\n", @fields) .
"\n} $name;\n\n";
}
1;
+5 -1
View File
@@ -11,6 +11,8 @@
use FindBin qw($Bin);
use lib ("$Bin/../../lib/perl");
use strict;
use EPICS::Getopts;
use File::Basename;
use DBD;
@@ -57,7 +59,9 @@ if ($opt_D) {
print map { "$_:\n" } @uniqfiles;
} else {
open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n";
print OUTFILE "/* $outbase generated from $inbase */\n\n",
print OUTFILE "/** \@file $outbase\n",
" * \@brief Declarations generated from $inbase\n",
" */\n\n",
"#ifndef $guard_name\n",
"#define $guard_name\n\n";
my $menus = $dbd->menus;
@@ -61,13 +61,19 @@ if ($opt_D) { # Output dependencies only, to stdout
print "$outfile: ", join(" \\\n ", @uniqfiles), "\n\n";
print map { "$_:\n" } @uniqfiles;
} else {
our ($rn, $rtyp) = each %{$rtypes};
my $rtn = $rn;
$rtn .= 'Record' if $rn ne 'dbCommon';
open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n";
print OUTFILE "/* $outbase generated from $inbase */\n\n",
print OUTFILE "/** \@file $outbase\n",
" * \@brief Declarations for the \@ref $rtn \"$rn\" record type.\n",
" *\n",
" * This header was generated from $inbase\n",
" */\n\n",
"#ifndef $guard_name\n",
"#define $guard_name\n\n";
our ($rn, $rtyp) = each %{$rtypes};
print OUTFILE $rtyp->toCdefs;
my @menu_fields = grep {