Advanced EPICS Training, Dirk Zimoch 2009 Writing C code for IOCs.

58
Advanced EPICS Training, Dirk Zimoch 2009 Writing C code for IOCs
  • date post

    19-Dec-2015
  • Category

    Documents

  • view

    229
  • download

    1

Transcript of Advanced EPICS Training, Dirk Zimoch 2009 Writing C code for IOCs.

Advanced EPICS Training, Dirk Zimoch 2009

Writing C code for IOCs

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