Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Major differences between vxWorks and Unix/Linux
■ vxWorks has no programs but many threads (called "tasks").►The whole IOC is one "program".►Parts of the IOC (modules, libraries, threads) are not independent.► If any part of the "program" crashes, the whole IOC does.
■ vxWorks has no users.►Everything runs as "root". (To be exact: in kernel space)►Everybody can do everything.
■ vxWorks is optimized for speed – not for safety.►You can overwrite memory, stack, interrupt tables, …► If you want something save you must make it save.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Consequences of the "one program" concept
■ All functions exist in the same "space".►Name clashes may appear between different modules (libraries).►Use unique names (with prefix) for global functions!●Wrong: config, test, read_bi●Right: drvXyConfig, fooTest, devAbc_read_bi
►Or make functions static.
■ vxWorks has no main function.■ Every function (including the shell) can call any other function.►You don’t start programs from the shell, you call functions.►When name clash happens, you might call the wrong function.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Consequences of multi threading
■ Any problem in one thread affects the whole IOC.■ System resources are global to the whole IOC.►Memory►File handles►Semaphores
■ Ending a thread does not clean up system resources.►The programmer (that's you!) must close files, free memory, etc.
■Global data needs protection against concurrent access.►Global variables►VME access
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Boon and bane of unlimited memory access
■ Pro: Functions and threads can easily …►exchange large amounts of data by reference (pointers).►access any hardware register (e.g. VME bus).
■ Con: Functions and threads can easily …►overrun allocated memory or stack size (esp. with arrays)►overwrite system tables. (e.g. interrupt handler table at NULL)►overwrite program code.►modify global variables of other modules (e.g. drivers).
Global variables are EVIL!
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Accessing the vxWorks shell at SLS
■ Type rmc iocname, e.g. rmc MTEST-VME-T1.►The SLS specific command rmc stands for "remote minicom".► It does ssh to a central server.► It starts minicom on the server.►The server is connected to the DEBUG port of the IOC.
■ You must be on the same network as the IOC.■ You may need your AFS password or the slsop password.■ If the IOC is connected to local Linux PC, use minicom.►Serial line settings: 9600 baud, 8N1, no hardware handshake
■Windows: hyperterm.exe (buggy) or Terminal.exe
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
vxWorks help
■Online help: http://vxworks.web.psi.ch► Important for beginners:
VxWorks Programmer's Guide, Chapter 2●All about tasks, semaphores, watchdog timers, interrupts
►Always helpful:vxWorks Reference Manual●All vxWorks system functions
■ Run-time help: Type help on the vxWorks shell.■ Separate talk on vxWorks debugging?
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
XTEST-VME-ID1 > help
help Print this listioHelp Print I/O utilities help infodbgHelp Print debugger help infonfsHelp Print nfs help infonetHelp Print network help infospyHelp Print task histogrammer help infotimexHelp Print execution timer help infoh [n] Print (or set) shell historyi [task] Summary of tasks' TCBsti task Complete info on TCB for tasksp adr,args... Spawn a task, pri=100, opt=0x19, stk=20000taskSpawn name,pri,opt,stk,adr,args... Spawn a tasktd task Delete a taskts task Suspend a tasktr task Resume a taskd [adr[,nunits[,width]]] Display memorym adr[,width] Modify memorymRegs [reg[,task]] Modify a task's registers interactivelypc [task] Return task's program counter
Type <CR> to continue, Q<CR> to stop:
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Calling functions from the vxWorks shell
■ Never call your main function main!►Use a specific name, the name you would give a program on Linux.
■ The shell can pass up to 10 integer or string arguments.► float or double shell arguments don't work on PPC architectures.►No check is done by the shell.►Check all arguments for sanity (numeric ranges, NULL strings, …).
■ The shell can call functions in a separate task► sp function, arg1, …
► repeatedly: repeat n, function, arg1, …►periodically: period seconds, function, arg1, …
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Examples
■ Setting or creating global variablesdrvXyDebug = 1str = "This is a string"
■ Calling functionsprintf (“String: %s, number: %d\n”, str, drvXyDebug)
►Note: Outermost parentheses are optional
■ Things that do not work►C constructs (non-functions) like: if, switch, for, while, …►Floating point: printf “%g\n”, 3.1415►More than 10 parameters
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Why global variables are evil (1)
■Global variables with the same name in different modules are the same piece of memory.►Problem: Two different modules may mutually overwrite their values.►Solution 1: Make variable local to one source file with static.►Solution 2: Prefix global variable name with module name.
/* internal variable */int card_count;
/* external variable */int debug=0;
/* internal variable */static int card_count;
/* external variable */int drvXyDebug=0;
Wrong Right
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Why global variables are evil (2)
■ All instances (of threads, drivers, SNL programs …) share the same global variable.►Problem: Two instances mutually overwrite their values.►Solution: Wrap variables in a struct, allocate one struct per instance.
Wrong Right
/* values for one card */static char* addr;static int ivec;
/* linked list */struct drvPriv { struct drvPriv *next; char* addr; int ivec;} drvPriv;static drvPriv *first=NULL;
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Debug and error messages are vital
■ Fail early and loud!■Make messages descriptive.►What happened where under which circumstances?●Bad: "error read"●Good: "drvXyReadInteger card 4 signal 2: read timeout after 5000 msec"
■Write error and debug messages to stderr.■Make debug messages switchable. (perhaps multiple levels)►global switch: int drvXyDebug=0; ►message: if (drvXyDebug>=2) fprintf(stderr, …);
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Be paranoid!
■ Error checking is the key to a stable system.►Stability is limited by the weakest point!
■ Check arguments to API functions (esp. shell functions)►Never trust a user! Not even yourself.
■ Always check pointer arguments for validity.►Writing to NULL overwrites the interrupt handler table!
■ Check results of system functions (malloc, fopen, …)►System functions may fail and return NULL or ERROR.►Using these values unchecked may crash the system much later.
■ Check for "impossible" values (e.g. in case constructs)
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Subroutine record sub
■ 12 input links INPA … INPL, 12 input fields A … L ►Record copies from links to fields before calling user function.►Either use input link or write directly to input field.► Input fields are all of type double.
■ User function can use A … L and writes result to VAL.■ SNAM field contains name of user function.■ INAM field contains name of optional init function.■ Functions get pointer to record and have access to all fields.►Field names are lower case: a … l, val
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Subroutine record user function
■ Inputs are in fields a … l, output goes to val (all double)■ Example: accumulate A*B to VAL
#include <subRecord.h>int subAccu (struct subRecord* record) { record->val = record->val + record->a * record->b; return 0;}
■ Specify name of function in SNAM field of record.record (sub, "$(NAME)") { field (SNAM, "subAccu") field (INPA, "$(INPUT)") field (INPB, "$(SCALE)")}
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Subroutine record initialization
■Optional init functionint subAccuInit (subRecord* record) { record->val = 1.0; return 0;}
■ Specify init function name in INAM field.record (sub, "$(NAME)") { field (SNAM, "subAccu") field (INAM, "subAccuInit") ...}
■ Init function runs only once at boot time.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Advanced: Asynchronous subroutine record
■ If function takes long time to complete...►Run calculation in separate work thread with low priority.●Setup thread in init function.●Store data for inter-thread communication in dpvt field.
►Trigger work thread from record function.►Return 1 from record function to signal: calculation not yet complete.►Re-process record when calculation completes.●Use callbackRequestProcessCallback.● pact field is 0 in first run and 1 in second run.
►Return 0 from record function to signal: calculation complete.►Return other value (e.g. ERROR or errno) to signal failure.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Asynchronous subroutine stub#include <subRecord.h>#include <callback.h>#include <taskLib.h>#include <semLib.h>#include <errno.h>
/* private data for record (stored in dpvt field) */typedef struct { int status; /* error status */ double val; /* result */ SEM_ID trigger; /* trigger for work thread */ CALLBACK cb; /* callback for re-processing */} asyncSubPriv;
void myAsyncSubThread(struct subRecord* record); int myAsyncSub(struct subRecord* record);int myAsyncSubInit(struct subRecord* record);
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Asynchronous subroutine work threadvoid myAsyncSubThread(struct subRecord* record) {
asyncSubPriv* priv = record->dpvt; /* get private data */
while (1) { /* loop forever */ semTake(priv->trigger, WAIT_FOREVER); /* wait */
/* do calculations */ /* leave result in priv->val */ /* leave error status in priv->status */
/* re-process record */ callbackRequestProcessCallback( &priv->cb, record->prio, record); }}
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Asynchronous subroutine user functionint myAsyncSub(struct subRecord* record) { asyncSubPriv* priv = record->dpvt; /* get private data */
if (priv == NULL) { return ERROR; } /* INAM missing */
if (record->pact == 0) { /* first run */ semGive(priv->trigger); /* trigger work thread */ return 1; /* signal: not yet done */ }
/*second run */ if (priv->status) { /* error in work thread */ return priv->status; }
record->val = priv->val; /* update record */ return 0; /* signal: done */ }
add error messages here
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Asynchronous subroutine init functionint myAsyncSubInit(struct subRecord* record) { int tid; SEM_ID trigger;
asyncSubPriv* priv = malloc(sizeof(asyncSubPriv)); if (priv == NULL) { return errno; }
priv->trigger = semBCreate(SEM_Q_FIFO, SEM_EMPTY); if (priv->trigger == NULL) { return errno; }
tid = taskSpawn("asyncSub", 200, VX_FP_TASK, 10000, (FUNCPTR) myAsyncSubThread, (int) record, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (tid == ERROR) { return errno; }
record->dpvt = priv; return 0;}
add error messages here
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
General subroutine record genSub (compared to sub)
■ All inputs and outputs are arrays of user defined type.► Input links INPA … INPU and fields A … U►Output fields VALA … VALU and links OUTA … OUTU
■ Input/output data types FTA … FTU, FTVA … FTVU►One of CHAR, SHORT, LONG, ULONG, FLOAT, DOUBLE, …
■ Input/output element count NOA … NOU, NOVA … NOVU►Always set FT* and NO* fields of all used inputs and outputs!
■ SNAM and INAM fields similar to sub record. ►Asynchronous user function is not supported.
■ The genSub record must be loaded: require "SynApps"
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
General subroutine record user function
■ Input and output fields a … u, vala … valu are void*.►Fields are pointers to arrays, even if element count is 1.►Cast void* to correct pointer type.●This easily crashes the IOC if ft* and no* fields are wrong!●Always check field type and size!●Do not process if type or size is wrong. Exit with error message.
■ Danger of crashing IOC is much higher than with sub record!■ Checking every time the record processes is expensive.►Check only once in init function (when IOC boots)!►Do not process record after check failed!
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
General subroutine record init function
■ Check all data types and element counts.►Field types are one of menuFtypeSHORT, menuFtypeDOUBLE, …►Print descriptive error message if check fails!
■ Initialize any other private data (buffers, etc…)■ Assign structure to dpvt field only if all checks succeed.► If no private data is needed, set dpvt to a dummy value.
■ Check dpvt field at start of user function.■ Do not process if dpvt is not set.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Soft device support
■ Available for "standard" I/O records►ai, bi, mbbi, waveform, …
■Makes a new DTYP choice available►Just like "Soft Channel" and "Raw Soft Channel"
■Only one input (INP) and one output (VAL)■ Examples:►Timestamp for stringin (INP contains format string)►File read for waveform (INP contains file name)►FFT for waveform (INP points to other waveform)► Integration for waveform (INP points to other waveform)
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Writing device support
■Write record init and read function■ Define a global device support function table
struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read;} devIntegrateWaveform = …
■Write dbd file to make function table knowndevice(waveform, CONSTANT, devIntegrateWaveform, "integrate")
the two essential functions
device support table name
record type DTYP stringLink type, CONSTANT means: "constant or link to record"
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example soft device support: Integrate waveform#include <recGbl.h>#include <devSup.h>#include <alarm.h>#include <dbAccess.h>#include <waveformRecord.h>
long devIntegrateWaveformInit(waveformRecord *record){ switch (record->inp.type) { case (PV_LINK): case (DB_LINK): case (CA_LINK): break;
default: recGblRecordError(S_db_badField, record, "devIntegrateWaveform (init_record) Illegal INP field"); return S_db_badField; } return 0;}
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example soft device support: Integrate waveformlong devIntegrateWaveformRead(waveformRecord *record){ long status, n, i;
n = record->nelm; status = dbGetLink(&record->inp, record->ftvl, record->bptr, 0, &n); if (status) { recGblSetSevr(record, READ_ALARM, INVALID_ALARM); return status; }
record->nord = n; switch (record->ftvl) { case DBF_DOUBLE: { double sum = 0.0; for (i=0; i<n; i++) { sum += ((double*)(record->bptr))[i]; ((double*)(record->bptr))[i] = sum; } break; }
/* case ... */ } return 0;}
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example soft device support: Integrate waveformstruct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read;} devIntegrateWaveform = { 5, NULL, NULL, devIntegrateWaveformInit, NULL, devIntegrateWaveformRead};
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
State Notation Language
■ State machine implementation for EPICS►Do something when event happens► "Events" are CA monitors (record changes) or timeout► "Do something" can be any C-code
■ C-like syntax►Understands many C functions and statements►Escapes to "real" C-code for special occasions
■ Easy to use CA interface►pvPut, pvGet, monitor
■ Any number of input and output records
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Using SNLprogram coolingswitchint cooling;assign cooling to "{DEV}:COOLING";double temp;assign temp to "{DEV}:TEMP";monitor temp;ss coolingswitch { state cold { when (temp>25.3) { cooling = 1; pvPut(cooling); } state hot } state hot { when (temp<22.0) { cooling = 0; pvPut(cooling); } state cold }}
state "cold"
start
state "hot"
[temp>25.3°] /cooling on
[temp<22°] /cooling off
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Including C-code into SNL
■ Escape single line with %%...►especially #include
■ Escape block with %{...}%
■ Avoid accessing "global" SNL variables from within escaped C code.► Implementation depends on
"+r" flag
program calculator%%#include <math.h>%{ void myCalc( double i1, double i2, double* o1, double* o2) { *o1 = sin(i1 + i2); *o2 = cos(i1 – i2); }}%
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
"Abusing" SNLfor calculations
double in1;double in2;double out1;double out2;assign in1 to "{DEV}:INPUT1";assign in2 to "{DEV}:INPUT2";assign out1 to "{DEV}:OUTPUT1";assign out2 to "{DEV}:OUTPUT2";monitor in1;monitor in2;evflag newInput;sync in1 to newInput;sync in2 to newInput; ss calculator { state idle { when (efTestAndClear(newInput)) { myCalc(in1, in2, &out1, &out2); pvPut(out1); pvPut(out2); } state idle }}
idle
start
[newInput] / myCalc()
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Contents
■ vxWorks intro►Major differences between vxWorks and Unix/Linux►Using the vxWorks shell►Programming techniques
■ Calling C code from EPICS►Subroutine records sub and genSub►Soft device support►State notation language
■ Compiling C code for IOCs►Using driver.makefile and require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
The problem of compiling EPICS code
■We have many different EPICS versions in use.►3.13.2, 3.13.9, 3.13.10, 3.14.8, (3.14.10)
■We have different operating systems ►2 versions of vxWorks, 3 versions of Linux, Windows
■We have 2 different VME boards types in use.►MVME2300, MVME5100
■Other systems►Embedded Linux on Virtex 4, Cosylab microIOC, …
■We want to run "the same" code on all systems.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Differences between EPICS 3.13 and 3.14
■ EPICS 3.14 is designed to be independent of vxWorks►Use OSI functions instead of vxWorks functions.►Use EPICS registry instead of vxWorks symbol table.►More complex build mechanism to build "host"-IOCs.
■ Incompatibilities between 3.13 and 3.14►New OSI functions are not available for 3.13.►Registry calls must be added all over the place.● for device support, sub/genSub functions, snl state machines
►Makefile uses different variable names and mechanisms.(And make is a very complicated programming language.)
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
The solution: driver.makefile
■ It is a sophisticated Makefile that builds the same code► for all EPICS versions (3.13 and 3.14)► for all operating system versions (except Windows at the moment)
■ It builds a module that can be loaded with require■ In many cases, it finds out what to do automatically►No need to write a complex Makefile► In special cases, it can be configured
■Originally designed for drivers, device support and new record types, it can be used for sub/genSub and SNL code, too.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
The two flavours of modules
■Global module►Commonly used code (device
driver, record type, …)► Installed into global driver pool
with make install●Can be used by everyone●Gets version number from CVS tag
►CVS location: G/DRV/►Can be loaded with require
■ Local module►Locally used code (SNL,
sub/genSub functions, …)► Installed to IOC boot directory
with swit●No interference with other modules●Does not need version numbers
►CVS location: A, X, F, P►Can be loaded with require
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example global module: hytec drivers
■ CVS location: G/DRV/hytec■ Needs CVS tags with versions like hytec_1_4_2►Untagged test versions are also supported.
■ Install to driver pool with make install■ Can be loaded with require "hytec"►or require "hytec","1"►or require "hytec","1.4"►or require "hytec","1.4.2"►or require "hytec","test"
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example local module: genSub function
■ CVS location: X/ID/GAP►genSub function file: X/ID/GAP/src/e_to_gap.c
■ Tell project GNUmakefile to build the code in src/ioc: build swit –Vbuild clean: make -C src $@
■ Install to IOC with swit together with other project files.■ Can be loaded with require "GAP"
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Using driver.makefile
■ In your source directory, create a one line Makefileinclude /ioc/tools/driver.makefile
■ Running make "automagically" builds a loadable module.►Detects all .c, .cc, .C, .cpp, .st, .stt, and .dbd files in directory.►Generates module name from directory name.►Builds for all EPICS versions.►Builds only for vxWorks by default (but can build for Linux, too).►Finds dependencies on other modules (drivers).►Levels out many differences between 3.13 and 3.14
■ If this is too much magic, you can configure it!
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Configuring driver.makefile
■ Source code list, dbd file list►Default is all files in current directory►Overwrite:SOURCES += file1.ccSOURCES += subdir/file2.cDBDS += xxx.dbd
■Why overwriting?►Files are not all in the same directory as the Makefile.►Not all files should be used.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Configuring driver.makefile
■ Project (module) name►Default name is directory name► If directory name is src or snl, default is name of parent directory►Overwrite: PROJECT = othername
■Why overwriting?► I don't like directory name.►Directory name contains illegal characters like – or space.● only alphanumeric plus underscore allowed
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Configuring driver.makefile
■ EPICS versions to build►Default is (3.13.2), 3.13.9, 3.13.10, 3.14.8, (3.14.10)●May change over time and depends on machine
►Exclude versions:EXCLUDE_VERSIONS = 3.14EXCLUDE_VERSIONS = 3.13.2
■Why excluding versions?►Code does not compile for all EPICS versions.►Code is not necessary for all EPICS versions.
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Configuring driver.makefile
■Operating system class►Default is vxWorks only (all versions)●Reason: backward compatibility with old vxWorks depended drivers.
►Overwrite: BUILDCLASSES = Linux (only for Linux)BUILDCLASSES += Linux (for vxWorks and Linux)
■Why overwriting?►Module should be used on other OS than vxWorks.● genSub or SNL code for Linux IOCs
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Configuring driver.makefile
■ Header file installation►Default is not to install any headers●Exception: generated header files for new record types
►Overwrite: HEADERS += file.h
■Why overwriting?►Module is a lower level driver on that other drivers may depend●For example asyn or ipac
►Only important for global modules● Local modules are not installed for use by others
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Make targets
■ make, make build►Builds a loadable module for each EPICS/OS combination
■ make 3.14, make 3.13.2►Builds only for certain EPICS versions
■ make install, make install.3.13► Installs global module to driver pool
■ make uninstall►Cleanly (!) removes global module from driver pool
■ make help►Prints some help
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Loading modules: require
■ require is an SLS extension.■ It is used in the IOC startup script to load modules.■ It checks if a module is already loaded.►Already loaded with compatible version is OK.►Already loaded with incompatible version stops booting.
■ It recursively solves dependencies on other modules.■ It loads the library and dbd file and initializes the module.► Initialize means: make functions etc, available to the shell►Uses ld and dbLoadDatabase to load the files
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Using require
■ require "xxx"►Loads latest version of library ● xxxLib, xxxLib.munch, libxxx.so, or xxx.dll
►Loads dbd file xxx.dbd►3.14: Calls init function xxx_registerRecordDeviceDriver
■ require "xxx","2.1"►Loads version 2.1 of library and dbd file (only for global modules)● xxxLib-2.1, xxxLib-2.1.munch, libxxx-2.1.so, or xxx-2.1.dll
■ require "xxx","test"►Loads test (untagged) version of library and dbd file
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Driver pool location
■ Location of global module libraries: ► $INSTBASE/iocBoot/<EPICS_VERSION>/<ARCH>► /work/iocBoot/R3.13.10/T2-ppc604► /psi-xfel/prod/iocBoot/R3.14.8/SL5-x86
■ Location of dbd files:► $INSTBASE/iocBoot/<EPICS_VERSION>/dbd
■ Location of headers:► $INSTBASE/iocBoot/<EPICS_VERSION>/include
Advanced EPICS Training, Dirk Zimoch 2009
Writing C code for IOCsWriting C code for IOCs
Example of link system in driver poolmotorLib -> motorLib-6.2.5motorLib-4 -> motorLib-4.963.0motorLib-4.74 -> motorLib-4.74.1motorLib-4.74.1motorLib-4.96 -> motorLib-4.96.1motorLib-4.96.1motorLib-4.962 -> motorLib-4.962.0motorLib-4.962.0motorLib-4.963 -> motorLib-4.963.0motorLib-4.963.0motorLib-6 -> motorLib-6.2.5motorLib-6.2 -> motorLib-6.2.5motorLib-6.2.5motorLib-test
Top Related