Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS...

39
Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 200 9 Running user C-Code on IOCs With special attention to vxWorks

Transcript of Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS...

Page 1: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Wir schaffen Wissen – heute für morgen

Paul Scherrer InstitutDirk Zimoch

Advanced EPICS Training, Dirk Zimoch 2009

Running user C-Code on IOCs

With special attention to vxWorks

Page 2: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 3: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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.

Page 4: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Consequences of the "one program" concept

• All functions exist in the same "space".– Name clashes may happen between different 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.

• Any function (including the shell) can call any other function.– You don’t start programs from the shell, you call functions.– When a name clash happens, you might call the wrong

function.

Page 5: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 6: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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!

Page 7: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 8: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

vxWorks help

• 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.

Page 9: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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:

Page 10: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Calling functions from the vxWorks shell

• Never call your main function main!– Use a name you would give to 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. Don't use them.– No check is done by the shell.– Check all arguments for sanity (numeric ranges, NULL

strings, …) in your function.

• The shell can call functions in a separate task– sp function, arg1, …

– repeatedly: repeat n, function, arg1, …– periodically: period seconds, function, arg1, …

Page 11: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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– Non-functions C constructs: if, switch, for, while, …– Floating point: printf “%g\n”, 3.1415– More than 10 parameters

Page 12: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 13: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Why global variables are evil (1)

• Global variables with the same name in different modules are the same piece of memory.– Problem: Two modules may mutually overwrite their values.– Solution 1: Make variable local to 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

Page 14: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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 allocated struct per instance.

Make liked list and store only hook in a static variable.

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;

Page 15: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Debug and error messages are vital

• Fail early and loud!

• Be 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, …);

Page 16: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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 later.

• Check for "cannot be" values (e.g. in case constructs)

Page 17: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 18: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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.– All inputs and result are of type double.

• User function can use A … L and writes result to VAL.

• Field SNAM contains name of user function.

• Field INAM 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

Page 19: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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)")}

Page 20: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Subroutine record initialization

• Optional init function

int 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.

Page 21: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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.• Field pact 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.

Page 22: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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);

Page 23: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine work thread

void 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); }}

Page 24: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine user function

int myAsyncSub(struct subRecord* record) { asyncSubPriv* priv = record->dpvt; /* get private data */

if (priv == NULL) { fprintf (stderr, "myAsynSub %s: record not initialized " "(INAM not set)\n", record->name); return ERROR; }

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 */ fprintf (stderr, "myAsynSub %s: terrible failure: %s\n", record->name, myErrorString[priv->status]); return priv->status; }

record->val = priv->val; /* update record */ return 0; /* signal: done */ }

Take care of useful error messages

Page 25: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine init function

int myAsyncSubInit(struct subRecord* record) { int tid; SEM_ID trigger;

asyncSubPriv* priv = malloc(sizeof(asyncSubPriv)); trigger = semBCreate(SEM_Q_FIFO, SEM_EMPTY); tid = taskSpawn("asyncSub", 200, VX_FP_TASK, 10000, (FUNCPTR) myAsyncSubThread, (int) record, 0, 0, 0, 0, 0, 0, 0, 0, 0);

if (!priv || !trigger || tid == ERROR ) { fprintf (stderr, "myAsyncSubInit %s: Out of memory\n", record->name); return errno; }

priv->trigger = trigger; record->dpvt = priv; return 0;}

Don't forget useful error message here

Page 26: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record genSub (compared to sub)

• The genSub record is part of of SynApps, not EPICS base.

• 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 fields!

• Fields SNAM and INAM similar to sub record. – Asynchronous user function is not supported.

Page 27: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record user function

• Input and output fields a … u, vala … valu are void*.– 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.

• Fields are pointers to arrays, even if element count is 1.

• Checking every time the record processes is expensive.– Check only once in init function (when IOC boots).– Do not process record if check failed.

• Danger of crashing IOC is much higher than with sub record!

Page 28: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record init function

• Check all data types and element counts.– Field types are 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.– Even if no private data is needed, set dpvt to a dummy

value if check succeeds.

• Check dpvt field at start of user function.

• Never process the record if dpvt is not set!

Page 29: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 30: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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)

Page 31: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Writing soft device support

• Write two functions: init_record and read– Very similar to sub record

• Define a global device support function tablestruct { 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")

device support table name

record type DTYP stringLink type, CONSTANT means: "constant or link to record"

Page 32: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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;}

Page 33: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Example soft device support: Integrate waveform

long 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 ... (other DBF types) */ } return 0;}

Page 34: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Example soft device support: Integrate waveform

#include <epicsExport.h>

struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read;} devIntegrateWaveform = { 5, NULL, NULL, devIntegrateWaveformInit, NULL, devIntegrateWaveformRead};

epicsExportAddress (dtyp, devIntegrateWaveform);

Put in the two functions you wrote

Page 35: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 36: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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

Page 37: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

Simple SNL Example

program coolingswitch

int 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

Page 38: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

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); }}%

Page 39: Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Advanced EPICS Training, Dirk Zimoch 2009 Running user C-Code on IOCs With special.

Advanced EPICS Training, Dirk Zimoch 2009

"Abusing" SNL for 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()