diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 90ceb77e4..366721455 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -19,6 +19,26 @@ --> +

Type-safe Device and Driver Support Tables

+ +

Type-safe versions of the device and driver support structures dset +and drvet have been added to the devSup.h and drvSup.h headers +respectively. The original structure definitions have not been changed so +existing support modules will still build normally, but older modules can be +modified and new code written to be compatible with both.

+ +

The old structure definitions will be replaced by the new ones if the macros +USE_TYPED_DSET and/or USE_TYPED_DRVET are defined when the +appropriate header is included. The best place to define these is in the +Makefile, as with the USE_TYPED_RSET macro that was introduced in +Base-3.16.1 and described below. See the comments in devSup.h for a brief usage +example, or look at +this commit to the ipac module to see a module conversion.

+ +

A helper function DBLINK* dbGetDevLink(dbCommon *prec) has also been +added to devSup.h which fetches a pointer to the INP or OUT field of the +record.

+

RTEMS build configuration update, running tests under QEMU

This release includes the ability to run the EPICS unit tests built for a diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index e255fff55..143c427da 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -702,6 +702,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry) pdbentry->precnode = ppvt->recnode; } +struct link* dbGetDevLink(struct dbCommon* prec) +{ + DBLINK *plink = 0; + DBENTRY entry; + dbInitEntryFromRecord(prec, &entry); + if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) { + plink = (DBLINK*)entry.pfield; + } + dbFinishEntry(&entry); + return plink; +} + long dbValueSize(short dbr_type) { /* sizes for value associated with each DBR request type */ diff --git a/src/ioc/db/dbScan.h b/src/ioc/db/dbScan.h index 028d09ec8..d483a0c30 100644 --- a/src/ioc/db/dbScan.h +++ b/src/ioc/db/dbScan.h @@ -19,6 +19,7 @@ #include "menuScan.h" #include "shareLib.h" #include "compilerDependencies.h" +#include "devSup.h" #ifdef __cplusplus extern "C" { @@ -33,9 +34,7 @@ extern "C" { #define MIN_PHASE SHRT_MIN /*definitions for I/O Interrupt Scanning */ -struct ioscan_head; - -typedef struct ioscan_head *IOSCANPVT; +/* IOSCANPVT now defined in devSup.h */ typedef struct event_list *EVENTPVT; struct dbCommon; diff --git a/src/ioc/dbStatic/devSup.h b/src/ioc/dbStatic/devSup.h index bd900cae4..73dba198c 100644 --- a/src/ioc/dbStatic/devSup.h +++ b/src/ioc/dbStatic/devSup.h @@ -6,7 +6,11 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* devSup.h Device Support */ +/** @file devSup.h + * + * @brief Device support routines + */ + /* * Author: Marty Kraimer * Date: 6-1-90 @@ -21,6 +25,111 @@ /* structures defined elsewhere */ struct dbCommon; struct devSup; +typedef struct ioscan_head *IOSCANPVT; +struct link; /* aka DBLINK */ + +/** Type safe version of 'struct dset' + * + * Recommended usage: + * + * In Makefile: + @code + USR_CFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET + @endcode + * + * In C source file: + @code + #include + #include // For IOCSCANPVT + ... + #include // defines epicsExportSharedSymbols + ... + static long init_record(dbCommon *prec); + static long get_iointr_info(int detach, dbCommon *prec, IOCSCANPVT* pscan); + static long longin_read(longinRecord *prec); + + const struct { + dset common; + long (*read)(longinRecord *prec); + } devLiDevName = { + { + 5, // 4 from dset + 1 from longinRecord + NULL, + NULL, + &init_record, + &get_iointr_info + }, + &longin_read + }; + epicsExportAddress(dset, devLiDevName); + @endcode + */ +typedef struct typed_dset { + /** Number of function pointers which follow. + * The value depends on the recordtype, but must be >=4 */ + long number; + /** Called from dbior() */ + long (*report)(int lvl); + /** Called twice during iocInit(). + * First with @a after = 0 before init_record() or array field allocation. + * Again with @a after = 1 after init_record() has finished. + */ + long (*init)(int after); + /** Called once per record instance */ + long (*init_record)(struct dbCommon *prec); + /** Called when SCAN="I/O Intr" on startup, or after SCAN is changed. + * + * Caller must assign the third arguement (IOCSCANPVT*). eg. + @code + struct mpvt { + IOSCANPVT drvlist; + }; + ... + // init_record() routine calls + scanIoInit(&pvt->drvlist); + ... + static long get_ioint_info(int detach, struct dbCommon *prec, IOCSCANPVT* pscan) { + if(prec->dpvt) + *pscan = &((mypvt*)prec->dpvt)->drvlist; + @endcode + * + * When a particular record instance can/will only used a single scan list, + * the @a detach argument can be ignored. + * + * If this is not the case, then the following should be noted. + * + get_ioint_info() is called with @a detach = 0 to fetch the scan list to + * which this record will be added. + * + get_ioint_info() is called later with @a detach = 1 to fetch the scan + * list from which this record should be removed. + * + Calls will be balanced, so a call with @a detach = 0 will be followed + * by one with @a detach = 1. + * + * @note get_ioint_info() will be called during IOC shutdown if the + * dsxt::del_record() extended callback is defined. (from 3.15.0.1) + */ + long (*get_ioint_info)(int detach, struct dbCommon *prec, IOSCANPVT* pscan); + /* Any further functions are specified by the record type. */ +} typed_dset; + +/** Device support extension table. + * + * Optional routines to allow run-time address modifications to be communicated + * to device support, which must register a struct dsxt by calling devExtend() + * from its init() routine. + */ +typedef struct dsxt { + /** Optional, called to offer device support a new record to control. + * + * Routine may return a non-zero error code to refuse record. + */ + long (*add_record)(struct dbCommon *precord); + /** Optional, called to remove record from device support control. + * + * Routine return a non-zero error code to refuse record removal. + */ + long (*del_record)(struct dbCommon *precord); + /* Only future Base releases may extend this table. */ +} dsxt; #ifdef __cplusplus extern "C" { @@ -29,6 +138,8 @@ extern "C" { typedef long (*DEVSUPFUN)(); /* ptr to device support function*/ #endif +#ifndef USE_TYPED_DSET + typedef struct dset { /* device support entry table */ long number; /*number of support routines*/ DEVSUPFUN report; /*print report*/ @@ -38,11 +149,15 @@ typedef struct dset { /* device support entry table */ /*other functions are record dependent*/ } dset; -typedef struct dsxt { /* device support extension table */ - long (*add_record)(struct dbCommon *precord); - long (*del_record)(struct dbCommon *precord); - /* Recordtypes are *not* allowed to extend this table */ -} dsxt; +#else +typedef typed_dset dset; +#endif /* USE_TYPED_DSET */ + +/** Fetch INP or OUT link (or NULL if record type has neither). + * + * Recommended for use in device support init_record() + */ +epicsShareFunc struct link* dbGetDevLink(struct dbCommon* prec); epicsShareExtern dsxt devSoft_DSXT; /* Allow anything table */ diff --git a/src/ioc/dbStatic/drvSup.h b/src/ioc/dbStatic/drvSup.h index 5778038e7..193d57482 100644 --- a/src/ioc/dbStatic/drvSup.h +++ b/src/ioc/dbStatic/drvSup.h @@ -6,7 +6,10 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* drvSup.h Driver Support */ +/** @file drvSup.h + * + * @brief Driver support routines. + */ /* * Author: Marty Kraimer @@ -18,16 +21,38 @@ #include "errMdef.h" -typedef long (*DRVSUPFUN) (); /* ptr to driver support function*/ +/** Driver entry table */ +typedef struct typed_drvet { + /** Number of function pointers which follow. Must be >=2 */ + long number; + /** Called from dbior() */ + long (*report)(int lvl); + /** Called during iocInit() */ + long (*init)(void); + /* Any further functions are driver-specific */ +} typed_drvet; + +#ifdef USE_TYPED_DRVET + +typedef typed_drvet drvet; + +#else + +/* These interfaces may eventually get deprecated */ + +typedef long (*DRVSUPFUN) (); /* ptr to driver support function */ + +typedef struct drvet { /* driver entry table */ + long number; /* number of support routines */ + DRVSUPFUN report; /* print report */ + DRVSUPFUN init; /* init support */ + /* Any further functions are driver-specific */ +} drvet; -typedef struct drvet { /* driver entry table */ - long number; /*number of support routines*/ - DRVSUPFUN report; /*print report*/ - DRVSUPFUN init; /*init support*/ - /*other functions are device dependent*/ -}drvet; #define DRVETNUMBER ( (sizeof(struct drvet) -sizeof(long))/sizeof(DRVSUPFUN) ) +#endif /* USE_TYPED_DRVET */ + #define S_drv_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/ #define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/ diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c index 7225beb1c..09ff40942 100644 --- a/src/std/rec/test/linkInitTest.c +++ b/src/std/rec/test/linkInitTest.c @@ -7,11 +7,14 @@ #include #include "dbAccess.h" +#include "devSup.h" #include "alarm.h" #include "dbUnitTest.h" #include "errlog.h" #include "epicsThread.h" +#include "longinRecord.h" + #include "testMain.h" void recTestIoc_registerRecordDeviceDriver(struct dbBase *); @@ -28,12 +31,21 @@ static void startTestIoc(const char *dbfile) eltc(1); } +/* testing here instead of ioc/db/test as xRecord has no INP/OUT */ +static void testdbGetDevLink(void) +{ + longinRecord *rec = (longinRecord*)testdbRecordPtr("li1"); + testOk1(dbGetDevLink((dbCommon*)rec) == &rec->inp); +} + static void testLongStringInit() { testDiag("testLongStringInit"); startTestIoc("linkInitTest.db"); + testdbGetDevLink(); + { const char buf[] = "!----------------------------------------------!"; testdbGetArrFieldEqual("longstr1.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf); @@ -230,7 +242,7 @@ void testInt64Inputs(void) MAIN(linkInitTest) { - testPlan(77); + testPlan(78); testLongStringInit(); testCalcInit();