Wir schaffen Wissen heute fr morgen Paul Scherrer

  • Slides: 39
Download presentation
Wir schaffen Wissen – heute für morgen Paul Scherrer Institut Dirk Zimoch Running user

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

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

Major differences between vx. Works and Unix/Linux • vx. Works has no programs but

Major differences between vx. Works and Unix/Linux • vx. Works 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. • vx. Works has no users. – Everything runs as "root". (To be exact: in kernel space) – Everybody can do everything. • vx. Works 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

Consequences of the "one program" concept • All functions exist in the same "space".

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: drv. Xy. Config, foo. Test, dev. Abc_read_bi – Or make functions static. • vx. Works 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. Advanced EPICS Training, Dirk Zimoch 2009

Consequences of multi threading • Any problem in one thread affects the whole IOC.

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

Boon and bane of unlimited memory access • Pro: Functions and threads can easily

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

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

vx. Works help • Important for beginners: Vx. Works Programmer's Guide, Chapter 2 –

vx. Works help • Important for beginners: Vx. Works Programmer's Guide, Chapter 2 – All about tasks, semaphores, watchdog timers, interrupts • Always helpful: vx. Works Reference Manual – All vx. Works system functions • Run-time help: Type help on the vx. Works shell. Advanced EPICS Training, Dirk Zimoch 2009

XTEST-VME-ID 1 > help io. Help dbg. Help nfs. Help net. Help spy. Help

XTEST-VME-ID 1 > help io. Help dbg. Help nfs. Help net. Help spy. Help timex. Help h i ti sp task. Spawn td ts tr d m m. Regs pc Print this list Print I/O utilities help info Print debugger help info Print nfs help info Print network help info Print task histogrammer help info Print execution timer help info [n] Print (or set) shell history [task] Summary of tasks' TCBs task Complete info on TCB for task adr, args. . . Spawn a task, pri=100, opt=0 x 19, stk=20000 name, pri, opt, stk, adr, args. . . Spawn a task Delete a task Suspend a task Resume a task [adr[, nunits[, width]]] Display memory adr[, width] Modify memory [reg[, task]] Modify a task's registers interactively [task] Return task's program counter Type <CR> to continue, Q<CR> to stop: Advanced EPICS Training, Dirk Zimoch 2009

Calling functions from the vx. Works shell • Never call your main function main!

Calling functions from the vx. Works 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, arg 1, … – repeatedly: repeat n, function, arg 1, … – periodically: period seconds, function, arg 1, … Advanced EPICS Training, Dirk Zimoch 2009

Examples • Setting or creating global variables drv. Xy. Debug = 1 str =

Examples • Setting or creating global variables drv. Xy. Debug = 1 str = "This is a string" • Calling functions printf (“String: %s, number: %dn”, str, drv. Xy. Debug) – Note: Outermost parentheses are optional • Things that do not work – Non-functions C constructs: if, switch, for, while, … – Floating point: printf “%gn”, 3. 1415 – More than 10 parameters Advanced EPICS Training, Dirk Zimoch 2009

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

Why global variables are evil (1) • Global variables with the same name in

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. Wron internal g variable /* int card_count; Right */ /* internal variable */ static int card_count; /* external variable */ int debug=0; /* external variable */ int drv. Xy. Debug=0; Advanced EPICS Training, Dirk Zimoch 2009

Why global variables are evil (2) • All instances (of threads, drivers, SNL programs

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. Wron g /* values for one card */ static char* addr; static int ivec; Right /* linked list */ struct drv. Priv { struct drv. Priv *next; char* addr; int ivec; } drv. Priv; static drv. Priv *first=NULL; Advanced EPICS Training, Dirk Zimoch 2009

Debug and error messages are vital • Fail early and loud! • Be descriptive.

Debug and error messages are vital • Fail early and loud! • Be descriptive. – What happened where under which circumstances? • Bad: • Good: "error read" "drv. Xy. Read. Integer 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 drv. Xy. Debug=0; – message: if (drv. Xy. Debug>=2) fprintf(stderr, …); Advanced EPICS Training, Dirk Zimoch 2009

Be paranoid! • Error checking is the key to a stable system. – Stability

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) Advanced EPICS Training, Dirk Zimoch 2009

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

Subroutine record sub • 12 input links INPA … INPL, 12 input fields A

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 Advanced EPICS Training, Dirk Zimoch 2009

Subroutine record user function • Inputs are in fields a … l, output goes

Subroutine record user function • Inputs are in fields a … l, output goes to val (all double) • Example: accumulate A*B to VAL #include <sub. Record. h> int sub. Accu(struct sub. Record* record) { record->val = record->val + record->a * record->b; return 0; } • Specify name of function in SNAM field of record (sub, "$(NAME)") { field (SNAM, "sub. Accu") field (INPA, "$(INPUT)") field (INPB, "$(SCALE)") } Advanced EPICS Training, Dirk Zimoch 2009

Subroutine record initialization • Optional init function int sub. Accu. Init (sub. Record* record)

Subroutine record initialization • Optional init function int sub. Accu. Init (sub. Record* record) { record->val = 1. 0; return 0; } • Specify init function name in INAM field. record (sub, "$(NAME)") { field (SNAM, "sub. Accu") field (INAM, "sub. Accu. Init"). . . } • Init function runs only once at boot time. Advanced EPICS Training, Dirk Zimoch 2009

Advanced: Asynchronous subroutine record • If function takes long time to complete. . .

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 callback. Request. Process. Callback. • 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. Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine stub #include #include <sub. Record. h> <callback. h> <task. Lib. h> <sem.

Asynchronous subroutine stub #include #include <sub. Record. h> <callback. h> <task. Lib. h> <sem. Lib. h> <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 */ } async. Sub. Priv; void my. Async. Sub. Thread(struct sub. Record* record); int my. Async. Sub. Init(struct sub. Record* record); Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine work thread void my. Async. Sub. Thread(struct sub. Record* record) { async.

Asynchronous subroutine work thread void my. Async. Sub. Thread(struct sub. Record* record) { async. Sub. Priv* priv = record->dpvt; /* get private data */ while (1) { /* loop forever */ sem. Take(priv->trigger, WAIT_FOREVER); /* wait */ /* do calculations */ /* leave result in priv->val */ /* leave error status in priv->status */ /* re-process record */ callback. Request. Process. Callback( &priv->cb, record->prio, record); } } Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine user function int my. Async. Sub(struct sub. Record* record) { async. Sub.

Asynchronous subroutine user function int my. Async. Sub(struct sub. Record* record) { async. Sub. Priv* priv = record->dpvt; /* get private data */ if (priv == NULL) { fprintf (stderr, "my. Asyn. Sub %s: record not initialized " "(INAM not set)n", record->name); return ERROR; } if (record->pact == 0) { /* first run */ sem. Give(priv->trigger); /* trigger work thread */ return 1; /* signal: not yet done */ } Take care of useful error messages /*second run */ if (priv->status) { /* error in work thread */ fprintf (stderr, "my. Asyn. Sub %s: terrible failure: %sn", record->name, my. Error. String[priv->status]); return priv->status; } record->val = priv->val; /* update record */ return 0; /* signal: done */ } Advanced EPICS Training, Dirk Zimoch 2009

Asynchronous subroutine init function int my. Async. Sub. Init(struct sub. Record* record) { int

Asynchronous subroutine init function int my. Async. Sub. Init(struct sub. Record* record) { int tid; SEM_ID trigger; async. Sub. Priv* priv = malloc(sizeof(async. Sub. Priv)); trigger = sem. BCreate(SEM_Q_FIFO, SEM_EMPTY); tid = task. Spawn("async. Sub", 200, VX_FP_TASK, 10000, (FUNCPTR) my. Async. Sub. Thread, (int) record, 0, 0, 0); if (!priv || !trigger || tid == ERROR ) { fprintf (stderr, "my. Async. Sub. Init %s: Out of memoryn", record->name); return errno; } priv->trigger = trigger; record->dpvt = priv; return 0; } Don't forget useful error message here Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record gen. Sub (compared to sub) • The gen. Sub record is

General subroutine record gen. Sub (compared to sub) • The gen. Sub record is part of of Syn. Apps, 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. Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record user function • Input and output fields a … u, vala

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! Advanced EPICS Training, Dirk Zimoch 2009

General subroutine record init function • Check all data types and element counts. –

General subroutine record init function • Check all data types and element counts. – Field types are menu. Ftype. SHORT, menu. Ftype. DOUBLE, … – 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! Advanced EPICS Training, Dirk Zimoch 2009

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

Soft device support • Available for "standard" I/O records – ai, bi, mbbi, waveform,

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 soft device support • Write two functions: init_record and read – Very similar

Writing soft device support • Write two functions: init_record and read – Very similar to sub record • Define a global device support function table struct { long number; DEVSUPFUN report; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read; } dev. Integrate. Waveform = … • Write dbd file to make function table known device support table name device(waveform, CONSTANT, dev. Integrate. Waveform, "integrate") record type Link type, CONSTANT means: "constant or link to record" DTYP string Advanced EPICS Training, Dirk Zimoch 2009

Example soft device support: Integrate waveform #include #include <rec. Gbl. h> <dev. Sup. h>

Example soft device support: Integrate waveform #include #include <rec. Gbl. h> <dev. Sup. h> <alarm. h> <db. Access. h> <waveform. Record. h> long dev. Integrate. Waveform. Init(waveform. Record *record) { switch (record->inp. type) { case (PV_LINK): case (DB_LINK): case (CA_LINK): break; default: rec. Gbl. Record. Error(S_db_bad. Field, record, "dev. Integrate. Waveform (init_record) Illegal INP field"); return S_db_bad. Field; } return 0; } Advanced EPICS Training, Dirk Zimoch 2009

Example soft device support: Integrate waveform long dev. Integrate. Waveform. Read(waveform. Record *record) {

Example soft device support: Integrate waveform long dev. Integrate. Waveform. Read(waveform. Record *record) { long status, n, i; n = record->nelm; status = db. Get. Link(&record->inp, record->ftvl, record->bptr, 0, &n); if (status) { rec. Gbl. Set. Sevr(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; } */ Advanced EPICS Training, Dirk Zimoch 2009

Example soft device support: Integrate waveform #include <epics. Export. h> struct { long number;

Example soft device support: Integrate waveform #include <epics. Export. h> struct { long number; DEVSUPFUN report; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read; } dev. Integrate. Waveform = { 5, NULL, dev. Integrate. Waveform. Init, NULL, dev. Integrate. Waveform. Read }; Put in the two functions you wrote epics. Export. Address (dtyp, dev. Integrate. Waveform); Advanced EPICS Training, Dirk Zimoch 2009

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux –

Contents • vx. Works intro – Major differences between vx. Works and Unix/Linux – Using the vx. Works shell – Programming techniques • Calling C code from EPICS – Subroutine records sub and gen. Sub – Soft device support – State notation language Advanced EPICS Training, Dirk Zimoch 2009

State Notation Language • State machine implementation for EPICS – Do something when event

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 – pv. Put, pv. Get, monitor • Any number of input and output records Advanced EPICS Training, Dirk Zimoch 2009

Simple SNL Example program coolingswitch int cooling; assign cooling to "{DEV}: COOLING"; double temp;

Simple SNL Example program coolingswitch int cooling; assign cooling to "{DEV}: COOLING"; double temp; assign temp to "{DEV}: TEMP"; monitor temp; start state "cold" emp>25. 3°] / cooling on [temp<22°] / cooling off ss coolingswitch { state cold { when (temp>25. 3) { cooling = 1; pv. Put(cooling); } state hot { when (temp<22. 0) { cooling = 0; pv. Put(cooling); } state cold } state "hot" } Advanced EPICS Training, Dirk Zimoch 2009

Including C-code into SNL • Escape single line with %%. . . – especially

Including C-code into SNL • Escape single line with %%. . . – especially #include program calculator %%#include <math. h> %{ void my. Calc( double i 1, double i 2, double* o 1, double* o 2) { *o 1 = sin(i 1 + i 2); *o 2 = cos(i 1 – i 2); } • Escape block with %{. . . }% • Avoid accessing "global" SNL variables from within escaped C code. – Implementation depends on "+r" flag }% Advanced EPICS Training, Dirk Zimoch 2009

"Abusing" SNL for calculations start idle [new. Input] / my. Calc() double in 1;

"Abusing" SNL for calculations start idle [new. Input] / my. Calc() double in 1; in 2; out 1; out 2; assign in 1 to "{DEV}: INPUT 1"; in 2 to "{DEV}: INPUT 2"; out 1 to "{DEV}: OUTPUT 1"; out 2 to "{DEV}: OUTPUT 2" monitor in 1; monitor in 2; evflag new. Input; sync in 1 to new. Input; sync in 2 to new. Input; ss calculator { state idle { when (ef. Test. And. Clear(new. Input)) { my. Calc(in 1, in 2, &out 1, &out 2); pv. Put(out 1); pv. Put(out 2); } state idle } } Advanced EPICS Training, Dirk Zimoch 2009