diff --git a/src/sequencer/Makefile b/src/sequencer/Makefile index 62888d534..adc7b674a 100644 --- a/src/sequencer/Makefile +++ b/src/sequencer/Makefile @@ -1,10 +1,16 @@ # -# $Id$ +# Makefile,v 1.2 1995/06/27 15:25:35 wright Exp # # Lowest Level Directroy Makefile # by Janet Anderson # -# $Log$ +# Makefile,v +# Revision 1.2 1995/06/27 15:25:35 wright +# Brought over Andy's sequencer 1.9 files, compiled and created new seq and snc. +# +# Revision 1.1 1994/09/07 19:26:37 jba +# New file +# # EPICS=../../.. diff --git a/src/sequencer/Makefile.Unix b/src/sequencer/Makefile.Unix index 016dde6ec..f9b1b0e9e 100644 --- a/src/sequencer/Makefile.Unix +++ b/src/sequencer/Makefile.Unix @@ -11,11 +11,11 @@ YACC = $(EYACC) USR_LDLIBS = -ll YACCOPT = -d -v -SRCS.c = ../parse.c ../phase2.c ../gen_ss_code.c \ - ../gen_tables.c sncVersion.c snc.c +SRCS.c = ../snc_main.c ../parse.c ../phase2.c ../gen_ss_code.c \ + ../gen_tables.c sncVersion.c snc.c -OBJS = parse.o phase2.o gen_ss_code.o \ - gen_tables.o sncVersion.o snc.o +OBJS = snc_main.o parse.o phase2.o gen_ss_code.o \ + gen_tables.o sncVersion.o snc.o PROD = snc @@ -24,7 +24,7 @@ include $(EPICS)/config/RULES.Unix # # The generated lex file includes snc.h # -snc_lex.c: snc.h +snc_lex.c: snc.h ../snc_lex.l snc.o: snc_lex.c diff --git a/src/sequencer/Makefile.Vx b/src/sequencer/Makefile.Vx index 63cb2b0c6..3cd1dec1d 100644 --- a/src/sequencer/Makefile.Vx +++ b/src/sequencer/Makefile.Vx @@ -6,19 +6,23 @@ USR_CFLAGS = SRCS.c = \ ../seq_main.c ../seq_ca.c ../seq_qry.c ../seq_task.c \ - ../seq_mac.c ../seq_prog.c + ../seq_mac.c ../seq_prog.c ../seq_if.c -LIBOBJS = \ +OBJS = \ seq_main.o seq_ca.o seq_qry.o seq_task.o \ - seq_mac.o seq_prog.o seqVersion.o + seq_mac.o seq_prog.o seq_if.o seqVersion.o -LIBNAME = seq +PROD = seq include $(EPICS)/config/RULES.Vx clean:: @$(RM) seqVersion.c +seq: $(OBJS) + $(RM) $@ + $(LINK.c) $@ $(OBJS) $(LDLIBS) + seqVersion.c: ../Version $(RM) seqVersion.c sh ../makeSeqVersion ../Version > seqVersion.c diff --git a/src/sequencer/Version b/src/sequencer/Version index 01d6c0f87..39c0fc0a5 100755 --- a/src/sequencer/Version +++ b/src/sequencer/Version @@ -1,2 +1,3 @@ -1.8.3 +1.9.0(3.12.1) + diff --git a/src/sequencer/chmod.sh b/src/sequencer/chmod.sh index 25249c6a3..6ab9339a0 100644 --- a/src/sequencer/chmod.sh +++ b/src/sequencer/chmod.sh @@ -1,5 +1,5 @@ #!/bin/sh -# epics/release $Id$ +# epics/release chmod.sh,v 1.1.1.1 1995/08/15 03:15:26 epicss Exp # Author: Roger A. Cole (LANL) # Date: 08-20-91 # diff --git a/src/sequencer/gen_ss_code.c b/src/sequencer/gen_ss_code.c index 51493a7f5..b9172fcfe 100644 --- a/src/sequencer/gen_ss_code.c +++ b/src/sequencer/gen_ss_code.c @@ -2,19 +2,20 @@ GTA PROJECT AT division Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - - $Id$ + gen_ss_code.c,v 1.2 1995/06/27 15:25:43 wright Exp DESCRIPTION: gen_ss_code.c -- routines to generate state set code ENVIRONMENT: UNIX HISTORY: 19nov91,ajk Changed find_var() to findVar(). 28apr92,ajk Implemented efClear() & efTestAndClear(). +01mar94,ajk Changed table generation to the new structures defined + in seqCom.h. ***************************************************************************/ #include #include "parse.h" #include "cadef.h" -#include -#include +#include +#include /*+************************************************************************ * NAME: gen_ss_code @@ -29,6 +30,7 @@ * * NOTES: All inputs are external globals. *-*************************************************************************/ +/*#define DEBUG 1*/ #define EVENT_STMT 1 #define ACTION_STMT 2 @@ -50,7 +52,7 @@ gen_ss_code() printf("\f/* Code for state \"%s\" in state set \"%s\" */\n", sp->value, ssp->value); - /* Generate delay processing function */ + /* Generate function to set up for delay processing */ gen_delay_func(sp, ssp); /* Generate event processing function */ @@ -64,9 +66,64 @@ gen_ss_code() /* Generate exit handler code */ gen_exit_handler(); } + /* Generate a function for each state that sets up delay processing: + * This function gets called prior to the event function to guarantee + * that the initial delay value specified in delay() calls are used. + * Each delay() call is assigned a unique id. The maximum number of + * delays is recorded in the state set structure. + */ +gen_delay_func(sp, ssp) +Expr *ssp; +Expr *sp; +{ + Expr *tp; + int eval_delay(); + + printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n", + sp->value, ssp->value); + printf("static D_%s_%s(ssId, pVar)\n", ssp->value, sp->value); + printf("SS_ID\tssId;\n"); + printf("struct UserVar\t*pVar;\n{\n"); + + /* For each transition: */ + for (tp = sp->left; tp != NULL; tp = tp->next) + { + print_line_num(tp->line_num, tp->src_file); + traverseExprTree(tp, E_FUNC, "delay", eval_delay, sp); + } + printf("}\n"); +} + +/* Evaluate the expression within a delay() function and generate + * a call to seq_delayInit(). Adds ssId, delay id parameters and cast to float. + * Example: seq_delayInit(ssId, 1, (float)()); + */ +eval_delay(ep, sp) +Expr *ep; +Expr *sp; +{ + Expr *epf; + int delay_id; + extern char *stype[]; + +#ifdef DEBUG + fprintf("stderr, "eval_delay: type=%s\n", stype[ep->type]); +#endif DEBUG + + /* Generate 1-st part of function w/ 1-st 2 parameters */ + delay_id = (int)ep->right; /* delay id was previously assigned */ + printf("\tseq_delayInit(ssId, %d, (", delay_id); + + /* Evaluate & generate the 3-rd parameter (an expression) */ + eval_expr(EVENT_STMT, ep->left, sp, 0); + + /* Complete the function call */ + printf("));\n"); +} -/* Generate action processing functions: + + /* Generate action processing functions: Each state has one action routine. It's name is derived from the state set name and the state name. */ @@ -78,17 +135,20 @@ Expr *ssp; /* Parent state set */ Expr *ap; int trans_num; extern char *prog_name; + extern line_num; + /* Action function declaration */ printf("\n/* Action function for state \"%s\" in state set \"%s\" */\n", sp->value, ssp->value); - /* action function declaration with ss_ptr as parameter */ - printf("static void A_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value); - printf("SPROG\t*sprog;\n"); - printf("SSCB\t*ss_ptr;\n"); - printf("struct UserVar\t*var_ptr;\n{\n"); + printf("static A_%s_%s(ssId, pVar, transNum)\n", ssp->value, sp->value); + printf("SS_ID\tssId;\n"); + printf("struct UserVar\t*pVar;\n"); + printf("short\ttransNum;\n{\n"); + /* "switch" statment based on the transition number */ - printf("\tswitch(ss_ptr->trans_num)\n\t{\n"); + printf("\tswitch(transNum)\n\t{\n"); trans_num = 0; + line_num = 0; /* For each transition ("when" statement) ... */ for (tp = sp->left; tp != NULL; tp = tp->next) { @@ -97,7 +157,11 @@ Expr *ssp; /* Parent state set */ /* For each action statement insert action code */ for (ap = tp->right; ap != NULL; ap = ap->next) { - print_line_num(ap->line_num, ap->src_file); + if (line_num != ap->line_num) + { + print_line_num(ap->line_num, ap->src_file); + line_num = ap->line_num; + } /* Evaluate statements */ eval_expr(ACTION_STMT, ap, sp, 2); } @@ -122,18 +186,21 @@ Expr *ssp; printf("\n/* Event function for state \"%s\" in state set \"%s\" */\n", sp->value, ssp->value); - printf("static int E_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value); - printf("SPROG\t*sprog;\n"); - printf("SSCB\t*ss_ptr;\n"); - printf("struct UserVar\t*var_ptr;\n{\n"); + printf("static E_%s_%s(ssId, pVar, pTransNum, pNextState)\n", + ssp->value, sp->value); + printf("SS_ID\tssId;\n"); + printf("struct UserVar\t*pVar;\n"); + printf("short\t*pTransNum, *pNextState;\n{\n"); trans_num = 0; /* For each transition generate an "if" statement ... */ for (tp = sp->left; tp != NULL; tp = tp->next) { print_line_num(tp->line_num, tp->src_file); printf("\tif ("); - eval_expr(EVENT_STMT, tp->left, sp, 0); - /* an event triggered, set next state */ + if (tp->left == 0) + printf("TRUE"); + else + eval_expr(EVENT_STMT, tp->left, sp, 0); printf(")\n\t{\n"); /* index is the transition number (0, 1, ...) */ index = state_block_index_from_name(ssp, tp->value); @@ -146,8 +213,8 @@ Expr *ssp; printf("\t\t/* state %s does not exist */\n", tp->value); } - printf("\t\tss_ptr->next_state = %d;\n", index); - printf("\t\tss_ptr->trans_num = %d;\n", trans_num); + printf("\t\t*pNextState = %d;\n", index); + printf("\t\t*pTransNum = %d;\n", trans_num); printf("\t\treturn TRUE;\n\t}\n"); trans_num++; } @@ -173,32 +240,6 @@ char *state_name; } return -1; /* State name non-existant */ } - -/* Generate delay processing function for a state */ -gen_delay_func(sp, ssp) -Expr *sp; -Expr *ssp; -{ - Expr *tp; - int eval_delay(); - - printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n", - sp->value, ssp->value); - printf("static void D_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value); - printf("SPROG\t*sprog;\n"); - printf("SSCB\t*ss_ptr;\n"); - printf("struct UserVar\t*var_ptr;\n{\n"); - - /* For each transition ... */ - for (tp = sp->left; tp != NULL; tp = tp->next) - { - print_line_num(tp->line_num, tp->src_file); - traverseExprTree(tp, E_FUNC, "delay", eval_delay, sp); - } - printf("}\n"); - - return; -} /* Evaluate an expression. */ eval_expr(stmt_type, ep, sp, level) @@ -210,6 +251,8 @@ int level; /* indentation level */ Expr *epf; int nparams; extern int reent_opt; + extern int line_num; + if (ep == 0) return; @@ -218,17 +261,20 @@ int level; /* indentation level */ case E_CMPND: indent(level); printf("{\n"); + line_num += 1; for (epf = ep->left; epf != 0; epf = epf->next) { eval_expr(stmt_type, epf, sp, level+1); } indent(level); printf("}\n"); + line_num += 1; break; case E_STMT: indent(level); eval_expr(stmt_type, ep->left, sp, 0); printf(";\n"); + line_num += 1; break; case E_IF: case E_WHILE: @@ -239,6 +285,7 @@ int level; /* indentation level */ printf("while ("); eval_expr(stmt_type, ep->left, sp, 0); printf(")\n"); + line_num += 1; epf = ep->right; if (epf->type == E_CMPND) eval_expr(stmt_type, ep->right, sp, level); @@ -254,6 +301,7 @@ int level; /* indentation level */ printf("; "); eval_expr(stmt_type, ep->right->left, sp, 0); printf(")\n"); + line_num += 1; epf = ep->right->right; if (epf->type == E_CMPND) eval_expr(stmt_type, epf, sp, level); @@ -263,6 +311,7 @@ int level; /* indentation level */ case E_ELSE: indent(level); printf("else\n"); + line_num += 1; epf = ep->left; /* Is it "else if" ? */ if (epf->type == E_IF || epf->type == E_CMPND) @@ -271,12 +320,15 @@ int level; /* indentation level */ eval_expr(stmt_type, ep->left, sp, level+1); break; case E_VAR: +#ifdef DEBUG + fprintf(stderr, "E_VAR: %s\n", ep->value); +#endif DEBUG if(reent_opt) { /* Make variables point to allocated structure */ Var *vp; vp = (Var *)ep->left; if (vp->type != V_NONE && vp->type != V_EVFLAG) - printf("(var_ptr->%s)", ep->value); + printf("(pVar->%s)", ep->value); else printf("%s", ep->value); } @@ -292,13 +344,16 @@ int level; /* indentation level */ case E_BREAK: indent(level); printf("break;\n"); + line_num += 1; break; case E_FUNC: +#ifdef DEBUG + fprintf(stderr, "E_FUNC: %s\n", ep->value); +#endif DEBUG if (special_func(stmt_type, ep, sp)) break; printf("%s(", ep->value); - for (epf = ep->left, nparams = 0; epf != 0; - epf = epf->next, nparams++) + for (epf = ep->left, nparams = 0; epf != 0; epf = epf->next, nparams++) { if (nparams > 0) printf(" ,"); @@ -337,6 +392,7 @@ int level; /* indentation level */ break; case E_TEXT: printf("%s\n", ep->left); + line_num += 1; break; default: if (stmt_type == EVENT_STMT) @@ -355,16 +411,22 @@ int level; } /* func_name_to_code - convert function name to a code */ enum fcode { F_DELAY, F_EFSET, F_EFTEST, F_EFCLEAR, F_EFTESTANDCLEAR, - F_PVGET, F_PVPUT, + F_PVGET, F_PVPUT, F_PVTIMESTAMP, F_PVASSIGN, F_PVMONITOR, F_PVSTOPMONITOR, F_PVCOUNT, F_PVINDEX, F_PVSTATUS, F_PVSEVERITY, F_PVFLUSH, F_PVERROR, F_PVGETCOMPLETE, - F_PVCONNECTED, F_PVCHANNELCOUNT, F_PVCONNECTCOUNT, F_NONE }; + F_PVASSIGNED, F_PVCONNECTED, + F_PVCHANNELCOUNT, F_PVCONNECTCOUNT, F_PVASSIGNCOUNT, + F_PVDISCONNECT, F_SEQLOG, F_MACVALUEGET, F_OPTGET, + F_NONE }; char *fcode_str[] = { "delay", "efSet", "efTest", "efClear", "efTestAndClear", - "pvGet", "pvPut", + "pvGet", "pvPut", "pvTimeStamp", "pvAssign", "pvMonitor", "pvStopMonitor", "pvCount", "pvIndex", "pvStatus", "pvSeverity", "pvFlush", "pvError", "pvGetComplete", - "pvConnected", "pvChannelCount", "pvConnectCount", NULL }; + "pvAssigned", "pvConnected", + "pvChannelCount", "pvConnectCount", "pvAssignCount", + "pvDisconnect", "seqLog", "macValueGet", "optGet", + NULL }; enum fcode func_name_to_code(fname) char *fname; @@ -382,9 +444,11 @@ char *fname; /* Process special function (returns TRUE if this is a special function) Checks for one of the following special functions: - - event flag functions - - process variable functions + - event flag functions, e.g. pvSet() + - process variable functions, e.g. pvPut() - delay() + - macVauleget() + - seqLog() */ special_func(stmt_type, ep, sp) int stmt_type; /* ACTION_STMT or EVENT_STMT */ @@ -392,113 +456,206 @@ Expr *ep; /* ptr to function in the expression */ Expr *sp; /* current State struct */ { char *fname; /* function name */ - Expr *ep1; /* 1-st parameter */ + Expr *ep1, *ep2, *ep3; /* parameters */ Chan *cp; Var *vp; enum fcode func_code; - int ndelay; + int delay_id; fname = ep->value; func_code = func_name_to_code(fname); if (func_code == F_NONE) return FALSE; /* not a special function */ - ep1 = ep->left; /* ptr to 1-st parameters */ - if ( (ep1 != 0) && (ep1->type == E_VAR) ) - { - vp = (Var *)findVar(ep1->value); - cp = vp->chan; - } - else - { - vp = 0; - cp = 0; - } - +#ifdef DEBUG + fprintf(stderr, "special_func: func_code=%d\n", func_code); +#endif DEBUG switch (func_code) { + case F_DELAY: + delay_id = (int)ep->right; + printf("seq_delay(ssId, %d)", delay_id); + return TRUE; + case F_EFSET: case F_EFTEST: case F_EFCLEAR: case F_EFTESTANDCLEAR: - if (vp->type != V_EVFLAG) - { - fprintf(stderr, "Line %d: ", ep->line_num); - fprintf(stderr, - "Parameter to \"%s\" must be an event flag\n", fname); - } - else if (func_code == F_EFSET && stmt_type == EVENT_STMT) - { - fprintf(stderr, "Line %d: ", ep->line_num); - fprintf(stderr, - "efSet() cannot be used as an event.\n"); - } - else - { - printf("%s(%s)", fname, vp->name); - } + /* Event flag funtions */ + gen_ef_func(stmt_type, ep, sp, fname); return TRUE; case F_PVPUT: case F_PVGET: + case F_PVTIMESTAMP: case F_PVGETCOMPLETE: case F_PVSTATUS: case F_PVSEVERITY: case F_PVCONNECTED: + case F_PVASSIGNED: case F_PVMONITOR: case F_PVSTOPMONITOR: case F_PVCOUNT: case F_PVINDEX: - /* DB functions requiring a channel structure */ - if (cp == 0) - { - fprintf(stderr, "Line %d: ", ep->line_num); - fprintf(stderr, - "Parameter to \"%s\" must be DB variable.\n", fname); - } - else - { - printf("%s(%d)", fname, cp->index); - } + case F_PVDISCONNECT: + case F_PVASSIGN: + /* DB functions requiring a channel id */ + gen_pv_func(stmt_type, ep, sp, fname, func_code); return TRUE; case F_PVFLUSH: case F_PVERROR: case F_PVCHANNELCOUNT: case F_PVCONNECTCOUNT: - /* DB functions not requiring a channel structure */ - printf("%s()", fname); + case F_PVASSIGNCOUNT: + /* DB functions NOT requiring a channel structure */ + printf("seq_%s(ssId)", fname); return TRUE; - case F_DELAY: - /* Test for delay: "test_delay(delay_id)" */ - printf("test_delay(%d)", (int)ep->right); + case F_SEQLOG: + case F_MACVALUEGET: + case F_OPTGET: + /* Any funtion that requires adding ssID as 1st parameter. + * Note: name is changed by prepending "seq_". */ + printf("seq_%s(ssId", fname); + /* now fill in user-supplied paramters */ + for (ep1 = ep->left; ep1 != 0; ep1 = ep1->next) + { + printf(", "); + eval_expr(stmt_type, ep1, sp, 0); + } + printf(") "); return TRUE; default: - return FALSE; /* not a special function */ + /* Not a special function */ + return FALSE; } } -/* Evaluate delay expression. */ -eval_delay(ep, sp) -Expr *ep; /* ptr to expression */ -Expr *sp; /* ptr to current State struct */ +/* Generate code for all event flag functions */ +gen_ef_func(stmt_type, ep, sp, fname, func_code) +int stmt_type; /* ACTION_STMT or EVENT_STMT */ +Expr *ep; /* ptr to function in the expression */ +Expr *sp; /* current State struct */ +char *fname; /* function name */ +enum fcode func_code; { - Expr *epf; - int delay_id; - extern char *stype[]; + Expr *ep1, *ep2, *ep3; + Var *vp; + Chan *cp; + + ep1 = ep->left; /* ptr to 1-st parameters */ + if ( (ep1 != 0) && (ep1->type == E_VAR) ) + vp = (Var *)findVar(ep1->value); + else + vp = 0; + if (vp == 0 || vp->type != V_EVFLAG) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Parameter to \"%s\" must be an event flag\n", fname); + } + else if (func_code == F_EFSET && stmt_type == EVENT_STMT) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "efSet() cannot be used as an event.\n"); + } + else + { + printf("seq_%s(ssId, %s)", fname, vp->name); + } + + return; +} + +/* Generate code for pv functions requiring a database variable. + * The channel id (index into channel array) is substituted for the variable + */ +gen_pv_func(stmt_type, ep, sp, fname) +int stmt_type; /* ACTION_STMT or EVENT_STMT */ +Expr *ep; /* ptr to function in the expression */ +Expr *sp; /* current State struct */ +char *fname; /* function name */ +{ + Expr *ep1, *ep2, *ep3; + Var *vp; + Chan *cp; + int index; + + ep1 = ep->left; /* ptr to 1-st parameter in the function */ + if (ep1 == 0) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Function \"%s\" requires a parameter.\n", fname); + return; + } + + vp = 0; + if (ep1->type == E_VAR) + { + vp = (Var *)findVar(ep1->value); + } + else if (ep1->type == E_SUBSCR) + { /* Form should be: [] */ + ep2 = ep1->left; /* variable */ + ep3 = ep1->right; /* subscript */ + if ( ep2->type == E_VAR ) + { + vp = (Var *)findVar(ep2->value); + } + } + + if (vp == 0) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Parameter to \"%s\" is not a defined variable.\n", fname); + cp=0; + } + + else + { #ifdef DEBUG - fprintf(stderr, "eval_delay: type=%s\n", stype[ep->type]); -#endif + fprintf(stderr, "gen_pv_func: var=%s\n", ep1->value); +#endif DEBUG + cp = vp->chan; + index = cp->index; + } - delay_id = (int)ep->right; - printf("\tstart_delay(%d, ", delay_id); + if ( (vp != 0) && (cp == 0) ) + { + fprintf(stderr, "Line %d: ", ep->line_num); + fprintf(stderr, + "Parameter to \"%s\" must be DB variable.\n", fname); + index=-1; + } - /* Output each parameter */ - eval_expr(EVENT_STMT, ep->left, sp, 0); + printf("seq_%s(ssId, %d", fname, index); - printf(");\n"); + if (ep1->type == E_SUBSCR) /* subscripted variable? */ + { /* e.g. pvPut(xyz[i+2]); => seq_pvPut(ssId, 3 + (i+2)); */ + printf(" + ("); + /* evalute the subscript expression */ + eval_expr(stmt_type, ep3, sp, 0); + printf(")"); + } + + /* Add any additional parameter(s) */ + ep1 = ep1->next; + while (ep1 != 0) + { + printf(", "); + eval_expr(stmt_type, ep1, sp, 0); + ep1 = ep1->next; + } + + /* Close the parameter list */ + printf(") \n"); + + return; } /* Generate exit handler code */ gen_exit_handler() @@ -507,9 +664,9 @@ gen_exit_handler() Expr *ep; printf("/* Exit handler */\n"); - printf("static void exit_handler(sprog, var_ptr)\n"); - printf("SPROG\t*sprog;\n"); - printf("struct UserVar\t*var_ptr;\n{\n"); + printf("static exit_handler(ssId, pVar)\n"); + printf("int\tssId;\n"); + printf("struct UserVar\t*pVar;\n{\n"); for (ep = exit_code_list; ep != 0; ep = ep->next) { eval_expr(EXIT_STMT, ep, 0, 1); diff --git a/src/sequencer/gen_tables.c b/src/sequencer/gen_tables.c index 123ba051b..87e5f4928 100644 --- a/src/sequencer/gen_tables.c +++ b/src/sequencer/gen_tables.c @@ -3,18 +3,23 @@ Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - $Id$ + gen_tables.c,v 1.2 1995/06/27 15:25:45 wright Exp + DESCRIPTION: Generate tables for run-time sequencer. See also: phase2.c & gen_ss_code.c ENVIRONMENT: UNIX HISTORY: 28apr92,ajk Implemented new event flag mode. +01mar94,ajk Implemented new interface to sequencer (see seqCom.h). +01mar94,ajk Implemented assignment of array elements to db channels. +17may94,ajk removed old event flag (-e) option. ***************************************************************************/ +/*#define DEBUG 1*/ #include #include "parse.h" #include -#include +#include /*+************************************************************************ * NAME: gen_tables @@ -30,8 +35,6 @@ * NOTES: All inputs are external globals. *-*************************************************************************/ -int nstates; /* total # states in all state sets */ - gen_tables() { extern Expr *ss_list; /* state sets (from parse) */ @@ -45,11 +48,14 @@ gen_tables() /* Generate State Blocks */ gen_state_blocks(); - /* Generate State Set control blocks as an array */ - gen_sscb_array(); + /* Generate State Set Blocks */ + gen_ss_array(); + + /* generate program parameter string */ + gen_prog_params(); /* Generate state program table */ - gen_state_prog_table(); + gen_prog_table(); return; } @@ -58,254 +64,250 @@ gen_db_blocks() { extern Chan *chan_list; Chan *cp; - int nchan; + int nchan, elem_num; printf("\n/* Database Blocks */\n"); - printf("static CHAN db_channels[NUM_CHANNELS] = {\n"); + printf("static struct seqChan seqChan[NUM_CHANNELS] = {\n"); nchan = 0; for (cp = chan_list; cp != NULL; cp = cp->next) { - /* Only process db variables */ - if (cp->db_name != NULL) - { - if (nchan > 0) - printf(",\n"); - fill_db_block(cp, nchan); +#ifdef DEBUG + fprintf(stderr, "gen_db_blocks: index=%d, num_elem=%d\n", + cp->index, cp->num_elem); +#endif DEBUG + + if (cp->num_elem == 0) + { /* Variable assigned to single pv */ + fill_db_block(cp, 0); nchan++; } + else + { /* Variable assigned to multiple pv's */ + for (elem_num = 0; elem_num < cp->num_elem; elem_num++) + { + fill_db_block(cp, elem_num); + nchan++; + } + } } - printf("\n};\n"); + printf("};\n"); return; } -/* Fill in a db block with data (all elements for "CHAN" struct) */ -fill_db_block(cp, index) +/* Fill in a db block with data (all elements for "seqChan" struct) */ +fill_db_block(cp, elem_num) Chan *cp; -int index; +int elem_num; { Var *vp; - char *get_type_string, *put_type_string, *postfix; + char *type_string, *suffix, elem_str[20], *db_name; extern char *prog_name; - extern int reent_opt; - int size, ev_flag, count; + extern int reent_opt; + extern int num_events; + int size, count, ef_num, mon_flag; + char *db_type_str(); vp = cp->var; - /* Convert variable type to a DB request type */ - switch (vp->type) + + /* Figure out text needed to handle subscripts */ + if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP) + sprintf(elem_str, "[%d]", elem_num); + else if (vp->class == VC_ARRAY2) + sprintf(elem_str, "[%d][0]", elem_num); + else + sprintf(elem_str, ""); + + if (vp->type == V_STRING) + suffix = "[0]"; + else + suffix = ""; + + /* Pick up other db info */ + + if (cp->num_elem == 0) { - case V_SHORT: - get_type_string = "DBR_STS_INT"; - put_type_string = "DBR_INT"; - size = sizeof(short); - break; - case V_INT: - case V_LONG: - /* Assume "long" & "int" are same size */ - get_type_string = "DBR_STS_LONG"; - put_type_string = "DBR_LONG"; - size = sizeof(int); - break; - case V_CHAR: - get_type_string = "DBR_STS_CHAR"; - put_type_string = "DBR_CHAR"; - size = sizeof(char); - break; - case V_FLOAT: - get_type_string = "DBR_STS_FLOAT"; - put_type_string = "DBR_FLOAT"; - size = sizeof(float); - break; - case V_DOUBLE: - get_type_string = "DBR_STS_DOUBLE"; - put_type_string = "DBR_DOUBLE"; - size = sizeof(double); - break; - case V_STRING: - get_type_string = "DBR_STS_STRING"; - put_type_string = "DBR_STRING"; - size = MAX_STRING_SIZE; - break; + db_name = cp->db_name; + mon_flag = cp->mon_flag; + ef_num = cp->ef_num; + } + else + { + db_name = cp->db_name_list[elem_num]; + mon_flag = cp->mon_flag_list[elem_num]; + ef_num = cp->ef_num_list[elem_num]; } - /* fill in the CHAN structure */ - printf("\t%d, ", index); /* index for this channel */ + if (db_name == NULL) + db_name = ""; /* not assigned */ - printf("\"%s\", ", cp->db_name);/* unexpanded db channel name */ + /* Now, fill in the dbCom structure */ - printf("(char *)0, "); /* ch'l name after macro expansion */ + printf(" \"%s\", ", db_name);/* unexpanded db channel name */ /* Ptr or offset to user variable */ - printf("(char *)"); - if (vp->type == V_STRING || cp->count > 0) - postfix = "[0]"; - else - postfix = ""; + printf("(void *)"); if (reent_opt) - printf("OFFSET(struct UserVar, %s%s), ", vp->name, postfix); + printf("OFFSET(struct UserVar, %s%s%s), ", vp->name, elem_str, suffix); else - printf("&%s%s, ", vp->name, postfix); /* variable ptr */ + printf("&%s%s%s, ", vp->name, elem_str, suffix); /* variable ptr */ - printf("(chid)0, "); /* reserve place for chid */ + /* variable name with optional elem num */ + printf("\"%s%s\", ", vp->name, elem_str); - printf("0, 0, 0, 0, "); /* connected, get_complete, status, severity */ + /* variable type */ + printf("\n \"%s\", ", db_type_str(vp->type) ); - printf("%d,\n", size); /* element size (bytes) */ + /* count for db requests */ + printf("%d, ", cp->count); - printf("\t%s, ", get_type_string);/* DB request conversion type (get/mon) */ + /* event number */ + printf("%d, ", cp->index + elem_num + num_events + 1); - printf("%s, ", put_type_string);/* DB request conversion type (put) */ + /* event flag number (or 0) */ + printf("%d, ", ef_num); - count = cp->count; - if (count == 0) - count = 1; - printf("%d, ", count); /* count for db requests */ + /* monitor flag */ + printf("%d", mon_flag); - printf("%d, ", cp->mon_flag); /* monitor flag */ - - printf("0, "); /* monitored */ - - printf("%g, ", cp->delta); /* monitor delta */ - - printf("%g, ", cp->timeout); /* monitor timeout */ - - printf("0, "); /* event id supplied by CA */ - - printf("0, "); /* semaphore id for async. pvGet() */ - - printf("&%s", prog_name); /* ptr to state program structure */ + printf(",\n\n"); return; } + +/* Convert variable type to db type as a string */ +char *db_type_str(type) +int type; +{ + switch (type) + { + case V_CHAR: return "char"; + case V_SHORT: return "short"; + case V_INT: return "int"; + case V_LONG: return "long"; + case V_FLOAT: return "float"; + case V_DOUBLE: return "double"; + case V_STRING: return "string"; + default: return ""; + } +} -/* Generate structure and data for state blocks (STATE) */ +/* Generate structure and data for state blocks */ gen_state_blocks() { extern Expr *ss_list; Expr *ssp; Expr *sp; - int ns; - extern int nstates; + int nstates, n; + extern int num_events, num_channels; + int numEventWords; + bitMask *pEventMask; - printf("\n/* State Blocks:\n"); - printf(" action_func, event_func, delay_func, event_flag_mask"); - printf(", *delay, *name */\n"); - nstates = 0; + /* Allocate an array for event mask bits */ + numEventWords = (num_events + num_channels + NBITS - 1)/NBITS; + pEventMask = (bitMask *)calloc(numEventWords, sizeof (bitMask)); + + /* for all state sets ... */ for (ssp = ss_list; ssp != NULL; ssp = ssp->next) { - printf("\nstatic STATE state_%s[] = {\n", ssp->value); - ns = 0; + /* Build event mask arrays for each state */ + printf("\n/* Event masks for state set %s */\n", ssp->value); + for (sp = ssp->left; sp != NULL; sp = sp->next) + { + eval_state_event_mask(sp, pEventMask, numEventWords); + printf("\t/* Event mask for state %s: */\n", sp->value); + printf("static bitMask\tEM_%s_%s[] = {\n", ssp->value, sp->value); + for (n = 0; n < numEventWords; n++) + printf("\t0x%08x,\n", pEventMask[n]); + printf("};\n"); + } + + /* Build state block for each state in this state set */ + printf("\n/* State Blocks */\n"); + printf("\nstatic struct seqState state_%s[] = {\n", ssp->value); + nstates = 0; for (sp = ssp->left; sp != NULL; sp = sp->next) { - if (ns > 0) - printf(",\n\n"); - ns++; nstates++; fill_state_block(sp, ssp->value); } printf("\n};\n"); } + + free(pEventMask); return; } -/* Fill in data for a the state block */ +/* Fill in data for a state block (see seqState in seqCom.h) */ fill_state_block(sp, ss_name) Expr *sp; char *ss_name; { - bitMask events[NWRDS]; - int n; printf("\t/* State \"%s\"*/\n", sp->value); - printf("\tA_%s_%s,\t/* action_function */\n", ss_name, sp->value); + printf("\t/* state name */ \"%s\",\n", sp->value); - printf("\tE_%s_%s,\t/* event_function */\n", ss_name, sp->value); + printf("\t/* action function */ A_%s_%s,\n", ss_name, sp->value); - printf("\tD_%s_%s,\t/* delay_function */\n", ss_name, sp->value); + printf("\t/* event function */ E_%s_%s,\n", ss_name, sp->value); - eval_state_event_mask(sp, events); - printf("\t/* Event mask for this state: */\n"); - for (n = 0; n < NWRDS; n++) - printf("\t0x%08x,\n", events[n]); + printf("\t/* delay function */ D_%s_%s,\n", ss_name, sp->value); - printf("\t\"%s\"\t/* *name */", sp->value); + printf("\t/* event mask array */ EM_%s_%s,\n\n", ss_name, sp->value); return; } -/* Generate the structure with data for a state program table (SPROG) */ -gen_state_prog_table() +/* Generate the program parameter list */ +gen_prog_params() { - extern char *prog_name, *prog_param; - extern int async_opt, debug_opt, reent_opt, conn_opt, newef_opt; - extern int nstates; - extern Expr exit_code_list; - int i; + extern char *prog_param; printf("\n/* Program parameter list */\n"); printf("static char prog_param[] = \"%s\";\n", prog_param); +} + +/* Generate the structure with data for a state program table (SPROG) */ +gen_prog_table() +{ + extern int reent_opt; + + extern char *prog_name; + extern Expr exit_code_list; + int i; printf("\n/* State Program table (global) */\n"); - printf("SPROG %s = {\n", prog_name); + printf("struct seqProgram %s = {\n", prog_name); - printf("\t%d,\t/* magic number */\n", MAGIC); + printf("\t/* magic number */ %d,\n", MAGIC); /* magic number */ - printf("\t0,\t/* task id */\n"); + printf("\t/* *name */ \"%s\",\n", prog_name);/* program name */ - printf("\t0,\t/* dyn_ptr */\n"); + printf("\t/* *pChannels */ seqChan,\n"); /* table of db channels */ - printf("\t0,\t/* task_is_deleted */\n"); + printf("\t/* numChans */ NUM_CHANNELS,\n"); /* number of db channels */ - printf("\t1,\t/* relative task priority */\n"); + printf("\t/* *pSS */ seqSS,\n"); /* array of SS blocks */ - printf("\t0,\t/* caSemId */\n"); - - printf("\tdb_channels,\t/* *channels */\n"); - - printf("\tNUM_CHANNELS,\t/* nchan */\n"); - - printf("\t0,\t/* conn_count */\n"); - - printf("\tsscb,\t/* *sscb */\n"); - - printf("\tNUM_SS,\t/* nss */\n"); - - printf("\tNULL,\t/* ptr to states */\n"); - - printf("\t%d,\t/* number of states */\n", nstates); - - printf("\tNULL,\t/* ptr to user area (not used) */\n"); + printf("\t/* numSS */ NUM_SS,\n"); /* number of state sets */ if (reent_opt) - printf("\tsizeof(struct UserVar),\t/* user area size */\n"); + printf("\t/* user variable size */ sizeof(struct UserVar),\n"); else - printf("\t0,\t/* user area size (not used) */\n"); + printf("\t/* user variable size */ 0,\n"); - printf("\tNULL,\t/* mac_ptr */\n"); + printf("\t/* *pParams */ prog_param,\n"); /* program parameters */ - printf("\tNULL,\t/* scr_ptr */\n"); + printf("\t/* numEvents */ NUM_EVENTS,\n"); /* number event flags */ - printf("\t0,\t/* scr_nleft */\n"); + printf("\t/* encoded options */ "); + encode_options(); - printf("\t\"%s\",\t/* *name */\n", prog_name); - - printf("\tprog_param,\t/* *params */\n"); - - printf("\t"); - for (i = 0; i < NWRDS; i++) - printf("0, "); - printf("\t/* Event flags (bit encoded) */\n"); - - printf("\t0x%x,\t/* encoded async, debug, conn, newef & reent options */\n", - encode_options() ); - - printf("\texit_handler,\t/* exit handler */\n"); - - printf("\t0, 0\t/* logSemId & logFd */\n"); + printf("\t/* exit handler */ exit_handler,\n"); printf("};\n"); @@ -314,71 +316,55 @@ gen_state_prog_table() encode_options() { - int options; - extern int async_opt, debug_opt, reent_opt, conn_opt, newef_opt; + extern int async_opt, debug_opt, reent_opt, + newef_opt, conn_opt, vx_opt; - options = 0; + printf("(0"); if (async_opt) - options |= OPT_ASYNC; + printf(" | OPT_ASYNC"); if (conn_opt) - options |= OPT_CONN; + printf(" | OPT_CONN"); if (debug_opt) - options |= OPT_DEBUG; - if (reent_opt) - options |= OPT_REENT; + printf(" | OPT_DEBUG"); if (newef_opt) - options |= OPT_NEWEF; - return options; + printf(" | OPT_NEWEF"); + if (reent_opt) + printf(" | OPT_REENT"); + if (vx_opt) + printf(" | OPT_VXWORKS"); + printf("),\n"); + + return; } - /* Generate an array of state set control blocks (SSCB), - one entry for each state set */ -gen_sscb_array() + /* Generate an array of state set blocks, one entry for each state set */ +gen_ss_array() { extern Expr *ss_list; Expr *ssp; int nss, nstates, n; - bitMask events[NWRDS]; - printf("\n/* State Set Control Blocks */\n"); - printf("static SSCB sscb[NUM_SS] = {\n"); + printf("\n/* State Set Blocks */\n"); + printf("static struct seqSS seqSS[NUM_SS] = {\n"); nss = 0; for (ssp = ss_list; ssp != NULL; ssp = ssp->next) { if (nss > 0) - printf(",\n\n"); + printf("\n\n"); nss++; printf("\t/* State set \"%s\"*/\n", ssp->value); - printf("\t0, 1,\t/* task_id, task_prioity */\n"); + printf("\t/* ss name */ \"%s\",\n", ssp->value); - printf("\t0, 0,\t/* caSemId, getSemId */\n"); + printf("\t/* ptr to state block */ state_%s%,\n", ssp->value); nstates = exprCount(ssp->left); - printf("\t%d, state_%s,\t/* num_states, *states */\n", nstates, - ssp->value); + printf("\t/* number of states */ %d,\n", nstates, ssp->value); - printf("\t0, 0, 0,"); - printf("\t/* current_state, next_state, prev_state */\n"); + printf("\t/* error state */ %d,\n", find_error_state(ssp)); - printf("\t%d,\t/* error_state */\n", find_error_state(ssp)); - - printf("\t0, FALSE,\t/* trans_number, action_complete */\n"); - - printf("\t0,\t/* pMask - ptr to current event mask */\n"); - - printf("\t0,\t/* number of delays in use */\n"); - - printf("\t/* array of delay values: */\n\t"); - for (n = 0; n < MAX_NDELAY; n++) - printf("0,"); - printf("\n"); - - printf("\t0,\t/* time (ticks) when state was entered */\n"); - - printf("\t\"%s\"\t\t/* ss name */", ssp->value); } - printf("\n};\n"); + printf("};\n"); return; } @@ -397,42 +383,146 @@ Expr *ssp; } /* Evaluate composite event mask for a single state */ -eval_state_event_mask(sp, events) +eval_state_event_mask(sp, pEventWords, numEventWords) Expr *sp; -bitMask events[NWRDS]; +bitMask *pEventWords; +int numEventWords; { int n; - int eval_tr_event_mask(); + int eval_event_mask(), eval_event_mask_subscr(); Expr *tp; - /* Clear all bits in mask */ - for (n = 0; n < NWRDS; n++) - events[n] = 0; + /* Set appropriate bits based on transition expressions. + * Here we look at the when() statement for references to event flags + * and database variables. Database variables might have a subscript, + * which could be a constant (set a single event bit) or an expression + * (set a group of bits for the possible range of the evaluated expression) + */ + + for (n = 0; n < numEventWords; n++) + pEventWords[n] = 0; - /* Set appropriate bits based on transition expressions */ for (tp = sp->left; tp != 0; tp = tp->next) - traverseExprTree(tp->left, E_VAR, 0, - eval_tr_event_mask, events); + { + /* look for simple variables, e.g. "when(x > 0)" */ + traverseExprTree(tp->left, E_VAR, 0, eval_event_mask, pEventWords); + + /* look for subscripted variables, e.g. "when(x[i] > 0)" */ + traverseExprTree(tp->left, E_SUBSCR, 0, eval_event_mask_subscr, pEventWords); + } +#ifdef DEBUG + fprintf(stderr, "Event mask for state %s is", sp->value); + for (n = 0; n < numEventWords; n++) + fprintf(stderr, " 0x%x", pEventWords[n]); + fprintf(stderr, "\n"); +#endif DEBUG } -/* Evaluate the event mask for a given transition. */ -eval_tr_event_mask(ep, events) +/* Evaluate the event mask for a given transition (when() statement). + * Called from traverseExprTree() when ep->type==E_VAR. + */ +eval_event_mask(ep, pEventWords) Expr *ep; -bitMask events[NWRDS]; +bitMask *pEventWords; { Chan *cp; Var *vp; + extern int num_events; vp = (Var *)ep->left; if (vp == 0) return; /* this shouldn't happen */ + /* event flag? */ + if (vp->type == V_EVFLAG) + { #ifdef DEBUG - fprintf(stderr, "eval_tr_event_mask: %s, ef_num=%d\n", - vp->name, vp->ef_num); + fprintf(stderr, " eval_event_mask: %s, ef_num=%d\n", + vp->name, vp->ef_num); #endif - if (vp->ef_num != 0) - bitSet(events, vp->ef_num); + bitSet(pEventWords, vp->ef_num); + return; + } + + /* database channel? */ + cp = vp->chan; + if (cp != NULL && cp->num_elem == 0) + { +#ifdef DEBUG + fprintf(stderr, " eval_event_mask: %s, db event bit=%d\n", + vp->name, cp->index + 1); +#endif + bitSet(pEventWords, cp->index + num_events + 1); + } + + return; +} + +/* Evaluate the event mask for a given transition (when() statement) + * for subscripted database variables. + * Called from traverseExprTree() when ep->type==E_SUBSCR. + */ +eval_event_mask_subscr(ep, pEventWords) +Expr *ep; +bitMask *pEventWords; +{ + extern int num_events; + + Chan *cp; + Var *vp; + Expr *ep1, *ep2; + int subscr, n; + + ep1 = ep->left; + if (ep1 == 0 || ep1->type != E_VAR) + return; + vp = (Var *)ep1->left; + if (vp == 0) + return; /* this shouldn't happen */ + + cp = vp->chan; + if (cp == NULL) + return; + + /* Only do this if the array is assigned to multiple pv's */ + if (cp->num_elem == 0) + { +#ifdef DEBUG + fprintf(stderr, " eval_event_mask_subscr: %s, db event bit=%d\n", + vp->name, cp->index); +#endif + bitSet(pEventWords, cp->index + num_events + 1); + return; + } + + /* Is this subscript a constant? */ + ep2 = ep->right; + if (ep2 == 0) + return; + if (ep2->type == E_CONST) + { + subscr = atoi(ep2->value); + if (subscr < 0 || subscr >= cp->num_elem) + return; +#ifdef DEBUG + fprintf(stderr, " eval_event_mask_subscr: %s, db event bit=%d\n", + vp->name, cp->index + subscr + 1); +#endif + bitSet(pEventWords, cp->index + subscr + num_events + 1); + return; + } + + /* subscript is an expression -- set all event bits for this variable */ +#ifdef DEBUG + fprintf(stderr, " eval_event_mask_subscr: %s, db event bits=%d..%d\n", + vp->name, cp->index + 1, cp->index + vp->length1); +#endif + for (n = 0; n < vp->length1; n++) + { + bitSet(pEventWords, cp->index + n + num_events + 1); + } + + return; } /* Count the number of linked expressions */ diff --git a/src/sequencer/parse.c b/src/sequencer/parse.c index 664be400b..9af8067ae 100644 --- a/src/sequencer/parse.c +++ b/src/sequencer/parse.c @@ -4,7 +4,7 @@ Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - $Id$ +< parse.c,v 1.3 1995/10/19 16:30:16 wright Exp DESCRIPTION: Parsing support routines for state notation compiler. The 'yacc' parser calls these routines to build the tables and linked lists, which are then passed on to the phase 2 routines. @@ -15,6 +15,10 @@ 20nov91,ajk Removed snc_init() - no longer did anything useful. 20nov91,ajk Added option_stmt() routine. 28apr92,ajk Implemented new event flag mode. +29opc93,ajk Implemented assignment of pv's to array elements. +29oct93,ajk Implemented variable class (VC_SIMPLE, VC_ARRAY, & VC_POINTER). +29oct93,ajk Added 'v' (vxWorks include) option. +17may94,ajk Removed old event flag (-e) option. ***************************************************************************/ /*====================== Includes, globals, & defines ====================*/ @@ -22,12 +26,11 @@ #include #include "parse.h" /* defines linked list structures */ #include -#include "db_access.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 -#endif /* TRUE */ +#endif TRUE int debug_print_opt = 0; /* Debug level (set by source file) */ @@ -65,8 +68,6 @@ Expr *global_c_list; /* global C code following state program */ program_name(pname, pparam) char *pname, *pparam; { - extern char *prog_name, *prog_param; - prog_name = pname; prog_param = pparam; #ifdef DEBUG @@ -76,29 +77,40 @@ char *pname, *pparam; } /* Parsing a declaration statement */ -decl_stmt(type, name, s_length, value) +decl_stmt(type, class, name, s_length1, s_length2, value) int type; /* variable type (e.g. V_FLOAT) */ +int class; /* variable class (e.g. VC_ARRAY) */ char *name; /* ptr to variable name */ -char *s_length; /* array lth (NULL=single element) */ +char *s_length1; /* array lth (1st dim, arrays only) */ +char *s_length2; /* array lth (2nd dim, [n]x[m] arrays only) */ char *value; /* initial value or NULL */ { Var *vp; - int length; + int length1, length2; extern int line_num; - if (s_length == 0) - length = 0; - else if (type == V_STRING) - length = 0; - else - { - length = atoi(s_length); - if (length < 0) - length = 0; - } #ifdef DEBUG - fprintf(stderr, "variable decl: type=%d, name=%s, length=%d\n", - type, name, length); + fprintf(stderr, + "variable decl: type=%d, class=%d, name=%s, ", type, class, name); +#endif + length1 = length2 = 1; + + if (s_length1 != NULL) + { + length1 = atoi(s_length1); + if (length1 <= 0) + length1 = 1; + } + + if (s_length2 != NULL) + { + length2 = atoi(s_length2); + if (length2 <= 0) + length2 = 1; + } + +#ifdef DEBUG + fprintf(stderr, "length1=%d, length2=%d\n", length1, length2); #endif /* See if variable already declared */ vp = (Var *)findVar(name); @@ -112,9 +124,12 @@ char *value; /* initial value or NULL */ vp = allocVar(); addVar(vp); /* add to var list */ vp->name = name; + vp->class = class; vp->type = type; - vp->length = length; + vp->length1 = length1; + vp->length2 = length2; vp->value = value; /* initial value or NULL */ + vp->chan = NULL; return; } @@ -123,8 +138,8 @@ option_stmt(option, value) char *option; /* "a", "r", ... */ int value; /* TRUE means +, FALSE means - */ { - extern int async_opt, conn_opt, debug_opt, - line_opt, reent_opt, warn_opt, newef_opt; + extern int async_opt, conn_opt, debug_opt, line_opt, + reent_opt, warn_opt, vx_opt, newef_opt; switch(*option) { @@ -137,6 +152,10 @@ int value; /* TRUE means +, FALSE means - */ case 'd': debug_opt = value; break; + case 'e': + newef_opt = value; + break; + case 'l': line_opt = value; break; @@ -145,28 +164,30 @@ int value; /* TRUE means +, FALSE means - */ break; case 'w': warn_opt = value; - - case 'e': - newef_opt = value; - + break; + case 'v': + vx_opt = value; break; } return; } -/* "Assign" statement: assign a variable to a DB channel. - elem_num is ignored in this version) */ -assign_stmt(name, db_name) +/* "Assign" statement: Assign a variable to a DB channel. + * Format: assign to var = vp; /* make connection to variable */ - vp->chan = cp; /* reverse ptr */ - cp->db_name = db_name; /* DB name */ - cp->count = vp->length; /* default count is variable length */ + cp = vp->chan; + if (cp != NULL) + { + fprintf(stderr, "assign: %s already assigned, line %d\n", + name, line_num); + return; + } + + /* Build structure for this channel */ + cp = (Chan *)build_db_struct(vp); + + cp->db_name = db_name; /* DB name */ + + /* The entire variable is assigned */ + cp->count = vp->length1 * vp->length2; - cp->mon_flag = FALSE; /* assume no monitor */ - cp->ef_var = NULL; /* assume no sync event flag */ return; } -/* Parsing a "monitor" statement */ -monitor_stmt(name, delta) -char *name; /* variable name (should be assigned) */ -char *delta; /* monitor delta */ +/* "Assign" statement: assign an array element to a DB channel. + * Format: assign [] to ; */ +assign_subscr(name, subscript, db_name) +char *name; /* ptr to variable name */ +char *subscript; /* subscript value or NULL */ +char *db_name; /* ptr to db name */ { - Chan *cp; + Chan *cp; + Var *vp; + int subNum; extern int line_num; +#ifdef DEBUG + fprintf(stderr, "assign %s[%s] to \"%s\";\n", name, subscript, db_name); +#endif DEBUG + /* Find the variable */ + vp = (Var *)findVar(name); + if (vp == 0) + { + fprintf(stderr, "assign: variable %s not declared, line %d\n", + name, line_num); + return; + } + + if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2) + { + fprintf(stderr, "assign: variable %s not an array, line %d\n", + name, line_num); + return; + } + + cp = vp->chan; + if (cp == NULL) + { + /* Build structure for this channel */ + cp = (Chan *)build_db_struct(vp); + } + else if (cp->db_name != NULL) + { + fprintf(stderr, "assign: array %s already assigned, line %d\n", + name, line_num); + return; + } + + subNum = atoi(subscript); + if (subNum < 0 || subNum >= vp->length1) + { + fprintf(stderr, + "assign: subscript %s[%d] is out of range, line %d\n", + name, subNum, line_num); + return; + } + + if (cp->db_name_list == NULL) + alloc_db_lists(cp, vp->length1); /* allocate lists */ + else if (cp->db_name_list[subNum] != NULL) + { + fprintf(stderr, "assign: %s[%d] already assigned, line %d\n", + name, subNum, line_num); + return; + } + + cp->db_name_list[subNum] = db_name; + cp->count = vp->length2; /* could be a 2-dimensioned array */ + + return; +} + +/* Assign statement: assign an array to multiple DB channels. + * Format: assign to { , , ... }; + * Assignments for double dimensioned arrays: + * [0][0] assigned to 1st db name, + * [1][0] assigned to 2nd db name, etc. + * If db name list contains fewer names than the array dimension, + * the remaining elements receive NULL assignments. + */ +assign_list(name, db_name_list) +char *name; /* ptr to variable name */ +Expr *db_name_list; /* ptr to db name list */ +{ + Chan *cp; + Var *vp; + int elem_num; + extern int line_num; + +#ifdef DEBUG + fprintf(stderr, "assign %s to {", name); +#endif DEBUG + /* Find the variable */ + vp = (Var *)findVar(name); + if (vp == 0) + { + fprintf(stderr, "assign: variable %s not declared, line %d\n", + name, line_num); + return; + } + + if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2) + { + fprintf(stderr, "assign: variable %s is not an array, line %d\n", + name, line_num); + return; + } + + cp = vp->chan; + if (cp != NULL) + { + fprintf(stderr, "assign: variable %s already assigned, line %d\n", + name, line_num); + return; + } + + /* Build a db structure for this variable */ + cp = (Chan *)build_db_struct(vp); + + /* Allocate lists */ + alloc_db_lists(cp, vp->length1); /* allocate lists */ + + /* fill in the array of pv names */ + for (elem_num = 0; elem_num < vp->length1; elem_num++) + { + if (db_name_list == NULL) + break; /* end of list */ + +#ifdef DEBUG + fprintf(stderr, "\"%s\", ", db_name_list->value); +#endif DEBUG + cp->db_name_list[elem_num] = db_name_list->value; /* DB name */ + cp->count = vp->length2; + + db_name_list = db_name_list->next; + } +#ifdef DEBUG + fprintf(stderr, "};\n"); +#endif DEBUG + + return; +} + +/* Build a db structure for this variable */ +build_db_struct(vp) +Var *vp; +{ + Chan *cp; + + cp = allocChan(); + addChan(cp); /* add to Chan list */ + + /* make connections between Var & Chan structures */ + cp->var = vp; + vp->chan = cp; + + /* Initialize the structure */ + cp->db_name_list = 0; + cp->mon_flag_list = 0; + cp->ef_var_list = 0; + cp->ef_num_list = 0; + cp->num_elem = 0; + cp->mon_flag = 0; + cp->ef_var = 0; + cp->ef_num = 0; + + return (int)cp; +} + +/* Allocate lists for assigning multiple pv's to a variable */ +alloc_db_lists(cp, length) +Chan *cp; +int length; +{ + /* allocate an array of pv names */ + cp->db_name_list = (char **)calloc(sizeof(char **), length); + + /* allocate an array for monitor flags */ + cp->mon_flag_list = (int *)calloc(sizeof(int **), length); + + /* allocate an array for event flag var ptrs */ + cp->ef_var_list = (Var **)calloc(sizeof(Var **), length); + + /* allocate an array for event flag numbers */ + cp->ef_num_list = (int *)calloc(sizeof(int **), length); + + cp->num_elem = length; + +} + +/* Parsing a "monitor" statement. + * Format: + * monitor ; - monitor a single variable or all elements in an array. + * monitor []; - monitor m-th element of an array. + */ +monitor_stmt(name, subscript) +char *name; /* variable name (should be assigned) */ +char *subscript; /* element number or NULL */ +{ + Var *vp; + Chan *cp; + int subNum; + extern int line_num; + +#ifdef DEBUG + fprintf(stderr, "monitor_stmt: name=%s[%s]\n", name, subscript); +#endif DEBUG + + /* Find the variable */ + vp = (Var *)findVar(name); + if (vp == 0) + { + fprintf(stderr, "assign: variable %s not declared, line %d\n", + name, line_num); + return; + } + /* Find a channel assigned to this variable */ - cp = (Chan *)findChan(name); + cp = vp->chan; if (cp == 0) { fprintf(stderr, "monitor: variable %s not assigned, line %d\n", @@ -206,22 +438,67 @@ char *delta; /* monitor delta */ return; } - /* Enter monitor parameters */ - cp->mon_flag = TRUE; - cp->delta = atof(delta); + if (subscript == NULL) + { + if (cp->num_elem == 0) + { /* monitor one channel for this variable */ + cp->mon_flag = TRUE; + return; + } + + /* else monitor all channels in db list */ + for (subNum = 0; subNum < cp->num_elem; subNum++) + { /* 1 pv per element of the array */ + cp->mon_flag_list[subNum] = TRUE; + } + return; + } + + /* subscript != NULL */ + subNum = atoi(subscript); + if (subNum < 0 || subNum >= cp->num_elem) + { + fprintf(stderr, "monitor: subscript of %s out of range, line %d\n", + name, line_num); + return; + } + + if (cp->num_elem == 0 || cp->db_name_list[subNum] == NULL) + { + fprintf(stderr, "monitor: %s[%d] not assigned, line %d\n", + name, subNum, line_num); + return; + } + + cp->mon_flag_list[subNum] = TRUE; return; } /* Parsing "sync" statement */ -sync_stmt(name, ef_name) -char *name; -char *ef_name; +sync_stmt(name, subscript, ef_name) +char *name; +char *subscript; +char *ef_name; { Chan *cp; Var *vp; extern int line_num; + int subNum; - cp = (Chan *)findChan(name); +#ifdef DEBUG + fprintf(stderr, "sync_stmt: name=%s, subNum=%s, ef_name=%s\n", + name, subscript, ef_name); +#endif DEBUG + + vp = (Var *)findVar(name); + if (vp == 0) + { + fprintf(stderr, "sync: variable %s not declared, line %d\n", + name, line_num); + return; + } + + cp = vp->chan; if (cp == 0) { fprintf(stderr, "sync: variable %s not assigned, line %d\n", @@ -238,36 +515,56 @@ char *ef_name; return; } - /* Insert pointers between Var & Chan structures */ - cp->ef_var = vp; - vp->chan = cp; + if (subscript == NULL) + { /* no subscript */ + if (cp->db_name != NULL) + { /* 1 pv assigned to this variable */ + cp->ef_var = vp; + return; + } + + /* 1 pv per element in the array */ + for (subNum = 0; subNum < cp->num_elem; subNum++) + { + cp->ef_var_list[subNum] = vp; + } + return; + } + + /* subscript != NULL */ + subNum = atoi(subscript); + if (subNum < 0 || subNum >= cp->num_elem) + { + fprintf(stderr, + "sync: subscript %s[%d] out of range, line %d\n", + name, subNum, line_num); + return; + } + cp->ef_var_list[subNum] = vp; /* sync to a specific element of the array */ return; } /* Definition C code */ -defn_c_stmt(c_str) -char *c_str; /* ptr to C code string */ +defn_c_stmt(c_list) +Expr *c_list; /* ptr to C code */ { - Expr *ep; - #ifdef DEBUG fprintf(stderr, "defn_c_stmt\n"); #endif - ep = expression(E_TEXT, "", c_str, 0); if (defn_c_list == 0) - defn_c_list = ep; + defn_c_list = c_list; else - link_expr(defn_c_list, ep); + link_expr(defn_c_list, c_list); return; } /* Global C code (follows state program) */ -global_c_stmt(c_str) -char *c_str; /* ptr to C code */ +global_c_stmt(c_list) +Expr *c_list; /* ptr to C code */ { - global_c_list = expression(E_TEXT, "", c_str, 0); + global_c_list = c_list; return; } @@ -292,22 +589,13 @@ char *name; { Var *vp; -#ifdef DEBUG - fprintf(stderr, "findVar, name=%s: ", name); -#endif for (vp = var_list; vp != NULL; vp = vp->next) { if (strcmp(vp->name, name) == 0) { -#ifdef DEBUG - fprintf(stderr, "found\n"); -#endif return vp; } } -#ifdef DEBUG - fprintf(stderr, "not found\n"); -#endif return 0; } @@ -322,35 +610,6 @@ Chan *cp; chan_tail = cp; cp->next = NULL; } - -/* Find a channel with a given associated variable name */ -Chan *findChan(name) -char *name; /* variable name */ -{ - Chan *cp; - Var *vp; - -#ifdef DEBUG - fprintf(stderr, "findChan, var name=%s: ", name); -#endif - for (cp = chan_list; cp != NULL; cp = cp->next) - { - vp = cp->var; - if (vp == 0) - continue; - if (strcmp(vp->name, name) == 0) - { -#ifdef DEBUG - fprintf(stderr, "found chan name=%s\n", cp->db_name); -#endif - return cp; - } - } -#ifdef DEBUG - fprintf(stderr, "not found\n"); -#endif - return 0; -} /* Set debug print opt */ set_debug_print(opt) @@ -366,7 +625,7 @@ Expr *prog_list; ss_list = prog_list; #ifdef DEBUG fprintf(stderr, "----Phase2---\n"); -#endif /* DEBUG */ +#endif DEBUG phase2(ss_list); exit(0); @@ -442,7 +701,7 @@ Expr *ep2; /* beginning 2-nd (append it to 1-st) */ break; } fprintf(stderr, ")\n"); -#endif /* DEBUG */ +#endif DEBUG return ep1; } @@ -452,7 +711,7 @@ char *line; char *fname; { extern int line_num; - extern char *src_file; + extern char *src_file; line_num = atoi(line); src_file = fname; @@ -462,4 +721,6 @@ char *fname; char *stype[] = { "E_EMPTY", "E_CONST", "E_VAR", "E_FUNC", "E_STRING", "E_UNOP", "E_BINOP", "E_ASGNOP", "E_PAREN", "E_SUBSCR", "E_TEXT", "E_STMT", "E_CMPND", - "E_IF", "E_ELSE", "E_WHILE", "E_SS", "E_STATE", "E_WHEN" }; + "E_IF", "E_ELSE", "E_WHILE", "E_SS", "E_STATE", "E_WHEN", + "E_FOR", "E_X", "E_PRE", "E_POST", "E_BREAK", "E_COMMA", + "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?" }; diff --git a/src/sequencer/parse.h b/src/sequencer/parse.h index 9edec859f..49c201895 100644 --- a/src/sequencer/parse.h +++ b/src/sequencer/parse.h @@ -1,13 +1,17 @@ /************************************************************************** GTA PROJECT AT division - Copyright, 1989, The Regents of the University of California. + Copyright, 1989-93, The Regents of the University of California. Los Alamos National Laboratory - $Id$ + parse.h,v 1.2 1995/06/27 15:25:50 wright Exp DESCRIPTION: Structures for parsing the state notation language. ENVIRONMENT: UNIX HISTORY: 18nov91,ajk Replaced lstLib stuff with in-line links. +28oct93,ajk Added support for assigning array elements to pv's. +28oct93,ajk Added support for pointer declarations (see VC_*) +5nov93,ajk Changed structures var & db_chan to handle array assignments. +5nov93,ajk changed malloc() to calloc() 3 places. ***************************************************************************/ /* Data for these blocks are generated by the parsing routines for each ** state set. The tables are then used to generate the run-time C code @@ -34,41 +38,47 @@ struct var /* Variable or function definition */ char *name; /* variable name */ char *value; /* initial value or NULL */ int type; /* var type */ - int length; /* array lth (0 if not an array) */ - int ef_num; /* event flag bit number */ - struct db_chan *chan; /* ptr to db channel struct or NULL */ + int class; /* simple, array, or pointer */ + int length1; /* 1st dim. array lth (default=1) */ + int length2; /* 2nd dim. array lth (default=1) */ + int ef_num; /* bit number if this is an event flag */ + struct db_chan *chan; /* ptr to channel struct if assigned */ }; typedef struct var Var; -struct db_chan /* DB channel info */ +struct db_chan /* DB channel assignment info */ { struct db_chan *next; /* link to next item in list */ - char *db_name; /* database name */ - int index; /* channel array index */ + char *db_name; /* database name (assign all to 1 pv) */ + char **db_name_list; /* list of db names (assign each to a pv) */ + int num_elem; /* number of elements assigned in db_name_list */ Var *var; /* ptr to variable definition */ - Var *ef_var; /* ptr to event flag variable for sync */ int count; /* count for db access */ int mon_flag; /* TRUE if channel is "monitored" */ - float delta; /* monitor dead-band */ - float timeout; /* monitor timeout */ + int *mon_flag_list; /* ptr to list of monitor flags */ + Var *ef_var; /* ptr to event flag variable for sync */ + Var **ef_var_list; /* ptr to list of event flag variables */ + int ef_num; /* event flag number */ + int *ef_num_list; /* list of event flag numbers */ + int index; /* index in database channel array (seqChan) */ }; typedef struct db_chan Chan; +/* Note: Only one of db_name or db_name_list can have a non-zero value */ Expr *expression(), *link_expr(); Var *findVar(); Chan *findChan(); - /* Linked list allocation definitions */ -#define allocExpr() (Expr *)malloc(sizeof(Expr)); -#define allocVar() (Var *)malloc(sizeof(Var)); -#define allocChan() (Chan *)malloc(sizeof(Chan)); +#define allocExpr() (Expr *)calloc(1, sizeof(Expr)); +#define allocVar() (Var *)calloc(1, sizeof(Var)); +#define allocChan() (Chan *)calloc(1, sizeof(Chan)); /* Variable types */ #define V_NONE 0 /* not defined */ #define V_CHAR 1 /* char */ #define V_SHORT 2 /* short */ -#define V_INT 3 /* int (but converted to long) */ +#define V_INT 3 /* int */ #define V_LONG 4 /* long */ #define V_FLOAT 5 /* float */ #define V_DOUBLE 6 /* double */ @@ -77,9 +87,16 @@ Chan *findChan(); #define V_FUNC 9 /* function (not a variable) */ #define V_UCHAR 11 /* unsigned char */ #define V_USHORT 12 /* unsigned short */ -#define V_UINT 13 /* unsigned int (converted to unsigned long) */ +#define V_UINT 13 /* unsigned int */ #define V_ULONG 14 /* unsigned long */ +/* Variable classes */ +#define VC_SIMPLE 0 /* simple (un-dimentioned) variable */ +#define VC_ARRAY1 1 /* single dim. array */ +#define VC_ARRAY2 2 /* multiple dim. array */ +#define VC_POINTER 3 /* pointer */ +#define VC_ARRAYP 4 /* array of pointers */ + /* Expression types */ #define E_EMPTY 0 /* empty expression */ #define E_CONST 1 /* numeric constant */ diff --git a/src/sequencer/phase2.c b/src/sequencer/phase2.c index 8cf97aeb2..a7e9d31bb 100644 --- a/src/sequencer/phase2.c +++ b/src/sequencer/phase2.c @@ -3,23 +3,29 @@ Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - $Id$ + phase2.c,v 1.2 1995/06/27 15:25:52 wright Exp + DESCRIPTION: Phase 2 code generation routines for SNC. Produces code and tables in C output file. - See also: gen_ss_code.c + See also: gen_ss_code.c and gen_tables.c ENVIRONMENT: UNIX HISTORY: 19nov91,ajk Replaced lstLib calls with built-in linked list. 19nov91,ajk Removed extraneous "static" from "UserVar" declaration. +01mar94,ajk Implemented new interface to sequencer (seqCom.h). +01mar94,ajk Implemented assignment of array elements to db channels. +01mar94,ajk Changed algorithm for assigning event bits. ***************************************************************************/ +/*#define DEBUG 1*/ #include #include "parse.h" -#include -#include +#include int num_channels = 0; /* number of db channels */ +int num_events = 0; /* number of event flags */ int num_ss = 0; /* number of state sets */ +int max_delays = 0; /* maximum number of delays per state */ int num_errors = 0; /* number of errors detected in phase 2 processing */ /*+************************************************************************ @@ -31,7 +37,7 @@ int num_errors = 0; /* number of errors detected in phase 2 processing */ * * RETURNS: n/a * -* FUNCTION: Generate C code from tables. +* FUNCTION: Generate C code from parsing lists. * * NOTES: All inputs are external globals. *-*************************************************************************/ @@ -51,6 +57,12 @@ phase2() /* reconcile all state names, including next state in transitions */ reconcile_states(); + /* Assign bits for event flags */ + assign_ef_bits(); + + /* Assign delay id's */ + assign_delay_ids(); + /* Generate preamble code */ gen_preamble(); @@ -60,12 +72,6 @@ phase2() /* Generate definition C code */ gen_defn_c_code(); - /* Assign bits for event flags */ - assign_ef_bits(); - - /* Assign delay id's */ - assign_delay_ids(); - /* Generate code for each state set */ gen_ss_code(); @@ -87,11 +93,16 @@ gen_preamble() printf("/* Program \"%s\" */\n", prog_name); /* Include files */ - printf("#include \"seq.h\"\n"); + printf("#define ANSI\n"); /* Expands ANSI prototypes in seqCom.h */ + printf("#include \"seqCom.h\"\n"); /* Local definitions */ printf("\n#define NUM_SS %d\n", num_ss); printf("#define NUM_CHANNELS %d\n", num_channels); + printf("#define NUM_EVENTS %d\n", num_events); + + /* The following definition should be consistant with db_access.h */ + printf("#define MAX_STRING_SIZE 40\n"); /* #define's for compiler options */ gen_opt_defn(async_opt, "ASYNC_OPT"); @@ -101,12 +112,13 @@ gen_preamble() printf("\n"); /* Forward references of tables: */ - printf("\nextern SPROG %s;\n", prog_name); - printf("extern CHAN db_channels[];\n"); + printf("\nextern struct seqProgram %s;\n", prog_name); + printf("extern struct seqChan seqChan[];\n"); return; } +/* Generate defines for compiler options */ gen_opt_defn(opt, defn_name) int opt; char *defn_name; @@ -118,8 +130,9 @@ char *defn_name; } /* Reconcile all variables in an expression, - and tie each to the appropriate VAR struct */ -int printTree = FALSE; + * and tie each to the appropriate VAR structure. + */ +int printTree = FALSE; /* For debugging only */ reconcile_variables() { @@ -131,7 +144,7 @@ reconcile_variables() { #ifdef DEBUG fprintf(stderr, "reconcile_variables: ss=%s\n", ssp->value); -#endif /* DEBUG */ +#endif DEBUG traverseExprTree(ssp, E_VAR, 0, connect_variable, 0); } @@ -151,6 +164,11 @@ Expr *ep; extern char *stype[]; extern int warn_opt; + if (ep->type != E_VAR) + return; +#ifdef DEBUG + fprintf(stderr, "connect_variable: \"%s\", line %d\n", ep->value, ep->line_num); +#endif vp = (Var *)findVar(ep->value); if (vp == 0) { /* variable not declared; add it to the variable list */ @@ -162,39 +180,39 @@ Expr *ep; addVar(vp); vp->name = ep->value; vp->type = V_NONE; /* undeclared type */ - vp->length = 0; + vp->length1 = 1; + vp->length2 = 1; vp->value = 0; } ep->left = (Expr *)vp; /* make connection */ -#ifdef DEBUG - fprintf(stderr, "connect_variable: %s\n", ep->value); -#endif return; } /* Reconcile state names */ reconcile_states() { + + extern Expr *ss_list; + extern int num_errors; - extern Expr *ss_list; Expr *ssp, *sp, *sp1, tr; for (ssp = ss_list; ssp != 0; ssp = ssp->next) { - for (sp = ssp->left; sp != 0; sp = sp->next) + for (sp = ssp->left; sp != 0; sp = sp->next) + { + /* Check for duplicate state names in this state set */ + for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next) { - /* Check for duplicate state names in this state set */ - for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next) + if (strcmp(sp->value, sp1->value) == 0) { - if (strcmp(sp->value, sp1->value) == 0) - { - fprintf(stderr, - "State \"%s\" is duplicated in state set \"%s\"\n", - sp->value, ssp->value); - num_errors++; - } - } - } + fprintf(stderr, + "State \"%s\" is duplicated in state set \"%s\"\n", + sp->value, ssp->value); + num_errors++; + } + } + } } } @@ -231,47 +249,60 @@ gen_var_decl() { switch (vp->type) { - case V_CHAR: + case V_CHAR: vstr = "char"; break; - case V_INT: - case V_LONG: + case V_INT: + vstr = "int"; + break; + case V_LONG: vstr = "long"; break; - case V_SHORT: + case V_SHORT: vstr = "short"; break; - case V_FLOAT: + case V_FLOAT: vstr = "float"; break; - case V_DOUBLE: + case V_DOUBLE: vstr = "double"; break; - case V_STRING: + case V_STRING: vstr = "char"; break; - case V_EVFLAG: - case V_NONE: + case V_EVFLAG: + case V_NONE: vstr = NULL; break; - default: + default: vstr = "int"; break; } + if (vstr == NULL) + continue; - if (vstr != NULL) - { - if (reent_opt) - printf("\t"); - else - printf("static "); - printf("%s\t%s", vstr, vp->name); - if (vp->length > 0) - printf("[%d]", vp->length); - else if (vp->type == V_STRING) - printf("[MAX_STRING_SIZE]"); - printf(";\n"); - } + if (reent_opt) + printf("\t"); + else + printf("static "); + + printf("%s\t", vstr); + + if (vp->class == VC_POINTER || vp->class == VC_ARRAYP) + printf("*"); + + printf("%s", vp->name); + + if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP) + printf("[%d]", vp->length1); + + else if (vp->class == VC_ARRAY2) + printf("[%d][%d]", vp->length1, vp->length2); + + if (vp->type == V_STRING) + printf("[MAX_STRING_SIZE]"); + + printf(";\n"); } if (reent_opt) printf("};\n"); @@ -306,16 +337,17 @@ gen_global_c_code() if (ep != NULL) { printf("\f\t/* Global C code */\n"); + print_line_num(ep->line_num, ep->src_file); for (; ep != NULL; ep = ep->next) { - print_line_num(ep->line_num, ep->src_file); printf("%s\n", ep->left); } } return; } -/* Returns number of db channels defined & inserts index into each channel struct */ +/* Sets cp->index for each variable, & returns number of db channels defined. + */ db_chan_count() { extern Chan *chan_list; @@ -325,57 +357,68 @@ db_chan_count() nchan = 0; for (cp = chan_list; cp != NULL; cp = cp->next) { - if (cp->db_name != NULL) - { - cp->index = nchan; - nchan++; -#ifdef DEBUG - fprintf(stderr, "db_name=%s, index=%d\n", - cp->db_name, cp->index); -#endif - } + cp->index = nchan; + if (cp->num_elem == 0) + nchan += 1; + else + nchan += cp->num_elem; /* array with multiple channels */ } + return nchan; } -/* Assign bits to event flags and database variables */ +/* Assign event bits to event flags and associate db channels with + * event flags. + */ assign_ef_bits() { - extern Var *var_list; - Var *vp; - Chan *cp; - int ef_num; - extern int num_channels; + extern Var *var_list; + extern Chan *chan_list; + Var *vp; + Chan *cp; + extern int num_events; + int n; - ef_num = num_channels + 1; /* start with 1-st avail mask bit */ + /* Assign event flag numbers (starting at 1) */ printf("\n/* Event flags */\n"); -#ifdef DEBUG - fprintf(stderr, "\nAssign values to event flags\n"); -#endif + num_events = 0; for (vp = var_list; vp != NULL; vp = vp->next) { - cp = vp->chan; - /* First see if this is an event flag */ if (vp->type == V_EVFLAG) { - if (cp != 0) - vp->ef_num = cp->index + 1; /* sync'ed */ - else - vp->ef_num = ef_num++; - printf("#define %s\t%d\n", vp->name, vp->ef_num); + num_events++; + vp->ef_num = num_events; + printf("#define %s\t%d\n", vp->name, num_events); } - - else - { - if (cp != 0) - vp->ef_num = cp->index + 1; - } - -#ifdef DEBUG - fprintf(stderr, "%s: ef_num=%d\n", vp->name, vp->ef_num); -#endif } + + /* Associate event flags with DB channels */ + for (cp = chan_list; cp != NULL; cp = cp->next) + { + if (cp->num_elem == 0) + { + if (cp->ef_var != NULL) + { + vp = cp->ef_var; + cp->ef_num = vp->ef_num; + } + } + + else /* cp->num_elem != 0 */ + { + for (n = 0; n < cp->num_elem; n++) + { + vp = cp->ef_var_list[n]; + if (vp != NULL) + { + cp->ef_num_list[n] = vp->ef_num; + } + } + } + + } + return; } @@ -387,6 +430,9 @@ assign_delay_ids() int delay_id; int assign_next_delay_id(); +#ifdef DEBUG + fprintf(stderr, "assign_delay_ids:\n"); +#endif DEBUG for (ssp = ss_list; ssp != 0; ssp = ssp->next) { for (sp = ssp->left; sp != 0; sp = sp->next) @@ -398,6 +444,10 @@ assign_delay_ids() traverseExprTree(tp->left, E_FUNC, "delay", assign_next_delay_id, &delay_id); } + + /* Keep track of number of delay id's requied */ + if (delay_id > max_delays) + max_delays = delay_id; } } } @@ -409,9 +459,10 @@ int *delay_id; ep->right = (Expr *)*delay_id; *delay_id += 1; } - -/* Traverse the expression tree, and call the supplied - * function on matched conditions */ + /* Traverse the expression tree, and call the supplied + * function whenever type = ep->type AND value matches ep->value. + * The condition value = 0 matches all. + * The function is called with the current ep and a supplied argument (argp) */ traverseExprTree(ep, type, value, funcp, argp) Expr *ep; /* ptr to start of expression */ int type; /* to search for */ @@ -430,8 +481,7 @@ void *argp; /* ptr to argument to pass on to function */ stype[ep->type], ep->value); /* Call the function? */ - if ((ep->type == type) && - (value == 0 || strcmp(ep->value, value) == 0) ) + if ((ep->type == type) && (value == 0 || strcmp(ep->value, value) == 0) ) { funcp(ep, argp); } @@ -439,7 +489,6 @@ void *argp; /* ptr to argument to pass on to function */ /* Continue traversing the expression tree */ switch(ep->type) { - case E_EMPTY: case E_VAR: case E_CONST: case E_STRING: diff --git a/src/sequencer/seq_ca.c b/src/sequencer/seq_ca.c index d619ff5d0..e84f22ee3 100644 --- a/src/sequencer/seq_ca.c +++ b/src/sequencer/seq_ca.c @@ -1,4 +1,6 @@ -/* $Id$ +/* + seq_ca.c,v 1.2 1995/06/27 15:25:54 wright Exp + * DESCRIPTION: Channel access interface for sequencer. * * Author: Andy Kozubal @@ -6,7 +8,7 @@ * * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, + * Copyright 1991-1994, the Regents of the University of California, * and the University of Chicago Board of Governors. * * This software was produced under U.S. Government contracts: @@ -37,16 +39,23 @@ * all state programs. Added seq_disconnect() and ca_import_cancel(). DB name resolution was moved to seq_main.c. * 19feb93,ajk Added patched version of VxWorks 5.02b taskVarDelete(). + * 01mar94,ajk Moved "seq_pv*()" functions to seq_if.c. + * 28mar94,ajk Restructured event& callback handlers to call proc_db_events(). + * 29mar94,ajk Removed getPtrToValue(). Offset is now in db_channel structure. + * 08apr94,ajk Added support for time stamp. */ #define ANSI #include "seq.h" -#include -LOCAL VOID *getPtrToValue(union db_access_val *, chtype); +LOCAL VOID proc_db_events(union db_access_val *, CHAN *, int); /*#define DEBUG*/ +#ifdef DEBUG +#undef LOCAL +#define LOCAL +#endif DEBUG /* * seq_connect() - Connect to all database channels through channel access. */ @@ -58,21 +67,22 @@ SPROG *pSP; extern VOID seq_conn_handler(); extern int seqInitialTaskId; - pSP->conn_count = 0; - /* - * For each channel: substitute macros, connect to db, - * & isssue monitor (if monitor request flaf is TRUE). + * For each channel: connect to db & isssue monitor (if monFlag is TRUE). */ - pDB = pSP->channels; - for (i = 0; i < pSP->nchan; i++) + for (i = 0, pDB = pSP->pChan; i < pSP->numChans; i++, pDB++) { + if (pDB->dbName == NULL || pDB->dbName[0] == 0) + continue; /* skip records without pv names */ + pDB->assigned = TRUE; + pSP->assignCount += 1; /* keep track of number of *assigned* channels */ #ifdef DEBUG - printf("connect to \"%s\"\n", pDB->db_name); -#endif /* DEBUG */ + logMsg("seq_connect: connect %s to %s\n", + pDB->pVarName, pDB->dbName); +#endif DEBUG /* Connect to it */ status = ca_build_and_connect( - pDB->db_name, /* DB channel name */ + pDB->dbName, /* DB channel name */ TYPENOTCONN, /* Don't get initial value */ 0, /* get count (n/a) */ &(pDB->chid), /* ptr to chid */ @@ -91,16 +101,19 @@ SPROG *pSP; /* * Issue monitor request */ - if (pDB->mon_flag) + if (pDB->monFlag) { - seq_pvMonitor(pSP, 0, pDB); + seq_pvMonitor((SS_ID)pSP->pSS, i); } - pDB++; } ca_flush_io(); return 0; } - /* + +#define GET_COMPLETE 0 +#define MON_COMPLETE 1 + +/* * seq_event_handler() - Channel access events (monitors) come here. * args points to CA event handler argument structure. args.usr contains * a pointer to the channel structure (CHAN *). @@ -108,33 +121,75 @@ SPROG *pSP; VOID seq_event_handler(args) struct event_handler_args args; { - SPROG *pSP; - CHAN *pDB; - struct dbr_sts_char *dbr_sts_ptr; - void *pVal; - int i, nbytes; - - /* User arg is ptr to db channel structure */ - pDB = (CHAN *)args.usr; - - /* Copy value returned into user variable */ - pVal = getPtrToValue((union db_access_val *)args.dbr, pDB->get_type); - nbytes = pDB->size * pDB->count; - memcpy(pDB->var, pVal, nbytes); - - /* Copy status & severity */ - dbr_sts_ptr = (struct dbr_sts_char *)args.dbr; - pDB->status = dbr_sts_ptr->status; - pDB->severity = dbr_sts_ptr->severity; - /* Process event handling in each state set */ - pSP = pDB->sprog; /* State program that owns this db entry */ - - /* Wake up each state set that is waiting for event processing */ - seq_efSet(pSP, 0, pDB->index + 1); + proc_db_events((union db_access_val *)args.dbr, (CHAN *)args.usr, MON_COMPLETE); return; } + +/* + * seq_callback_handler() - Sequencer callback handler. + * Called when a "get" completes. + * args.usr points to the db structure (CHAN *) for tis channel. + */ +VOID seq_callback_handler(args) +struct event_handler_args args; +{ + + /* Process event handling in each state set */ + proc_db_events((union db_access_val *)args.dbr, (CHAN *)args.usr, GET_COMPLETE); + + return; +} + +/* Common code for event and callback handling */ +LOCAL VOID proc_db_events(pAccess, pDB, complete_type) +union db_access_val *pAccess; +CHAN *pDB; +int complete_type; +{ + SPROG *pSP; + void *pVal; + int i; + +#ifdef DEBUG + logMsg("proc_db_events: var=%s, pv=%s\n", pDB->VarName, pDB->dbName); +#endif DEBUG + + /* Copy value returned into user variable */ + pVal = (void *)pAccess + pDB->dbOffset; /* ptr to data in CA structure */ + bcopy(pVal, pDB->pVar, pDB->size * pDB->dbCount); + + /* Copy status & severity */ + pDB->status = pAccess->tchrval.status; + pDB->severity = pAccess->tchrval.severity; + + /* Copy time stamp */ + pDB->timeStamp = pAccess->tchrval.stamp; + + /* Get ptr to the state program that owns this db entry */ + pSP = pDB->sprog; + + /* Wake up each state set that uses this channel in an event */ + seqWakeup(pSP, pDB->eventNum); + + /* If there's an event flag associated with this channel, set it */ + if (pDB-> efId > 0) + seq_efSet((SS_ID)pSP->pSS, pDB->efId); + + /* Special processing for completed pvGet() */ + if (complete_type == GET_COMPLETE) + { + pDB->getComplete = TRUE; + + /* If syncronous pvGet then notify pending state set */ + if (pDB->getSemId != NULL) + semGive(pDB->getSemId); + } + + return; +} + /* Disconnect all database channels */ seq_disconnect(pSP) SPROG *pSP; @@ -143,43 +198,54 @@ SPROG *pSP; STATUS status; int i; extern int seqAuxTaskId; + SPROG *pMySP; /* NULL if this task is not a sequencer task */ /* Did we already disconnect? */ - if (pSP->conn_count < 0) + if (pSP->connCount < 0) return 0; /* Import Channel Access context from the auxillary seq. task */ - ca_import(seqAuxTaskId); - - pDB = pSP->channels; - for (i = 0; i < pSP->nchan; i++) + pMySP = seqFindProg(taskIdSelf() ); + if (pMySP == NULL) { + ca_import(seqAuxTaskId); /* not a sequencer task */ + } + + pDB = pSP->pChan; + for (i = 0; i < pSP->numChans; i++, pDB++) + { + if (!pDB->assigned) + continue; #ifdef DEBUG - printf("disconnect \"%s\"\n", pDB->db_name); -#endif /* DEBUG */ + logMsg("seq_disconnect: disconnect %s from %s\n", + pDB->pVarName, pDB->dbName); + taskDelay(30); +#endif DEBUG /* Disconnect this channel */ status = ca_clear_channel(pDB->chid); if (status != ECA_NORMAL) { - SEVCHK(status, "ca_clear_chan"); - ca_task_exit(); - return -1; + /* SEVCHK(status, "ca_clear_chan"); */ + /* ca_task_exit(); */ + /* return -1; */ } /* Clear monitor & connect indicators */ pDB->monitored = FALSE; pDB->connected = FALSE; - - pDB++; } - pSP->conn_count = -1; /* flag to indicate all disconnected */ + pSP->connCount = -1; /* flag to indicate all disconnected */ ca_flush_io(); - /* Cancel CA import */ - ca_import_cancel(taskIdSelf()); + /* Cancel CA context if it was imported above */ + if (pMySP == NULL) + { +logMsg("seq_disconnect: cancel import CA context\n"); + ca_import_cancel(taskIdSelf()); + } return 0; } @@ -204,309 +270,55 @@ struct connection_handler_args args; if (ca_field_type(args.chid) == TYPENOTCONN) { pDB->connected = FALSE; - pSP->conn_count--; + pSP->connCount--; + pDB->monitored = FALSE; #ifdef DEBUG - seq_log(pSP, "Channel \"%s\" disconnected\n", pDB->db_name); -#endif /* DEBUG */ + logMsg("%s disconnected from %s\n", pDB->VarName, pDB->dbName); +#endif DEBUG } - else + else /* PV connected */ { pDB->connected = TRUE; - pSP->conn_count++; + pSP->connCount++; + if (pDB->monFlag) + pDB->monitored = TRUE; #ifdef DEBUG - seq_log(pSP, "Channel \"%s\" connected\n", pDB->db_name); -#endif /* DEBUG */ - if (pDB->count > ca_element_count(args.chid)) - { - pDB->count = ca_element_count(args.chid); -#ifdef DEBUG - seq_log(pSP, "\"%s\": reset count to %d\n", - pDB->db_name, pDB->count); -#endif /* DEBUG */ - } + logMsg("%s connected to %s\n", pDB->VarName, pDB->dbName); +#endif DEBUG + pDB->dbCount = ca_element_count(args.chid); + if (pDB->dbCount > pDB->count) + pDB->dbCount = pDB->count; } /* Wake up each state set that is waiting for event processing */ - seq_efSet(pSP, 0, 0); + seqWakeup(pSP, 0); return; } /* - * seq_efSet() - Set an event flag, then wake up each state - * set that might be waiting on that event flag. + * seqWakeup() -- wake up each state set that is waiting on this event + * based on the current event mask. EventNum = 0 means wake all state sets. */ -VOID seq_efSet(pSP, dummy, ev_flag) +VOID seqWakeup(pSP, eventNum) SPROG *pSP; -int dummy; -int ev_flag; /* event flag */ +int eventNum; { - SSCB *pSS; int nss; + SSCB *pSS; - /* Set this bit (apply resource lock) */ - semTake(pSP->caSemId, WAIT_FOREVER); - bitSet(pSP->events, ev_flag); - - /* Check flag against mask for all state sets: */ - for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++) + /* Check event number against mask for all state sets: */ + for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++) { - /* Test for possible event trig based on bit mask for this state */ - if ( (ev_flag == 0) || bitTest(pSS->pMask, ev_flag) ) + /* If event bit in mask is set, wake that state set */ + if ( (eventNum == 0) || bitTest(pSS->pMask, eventNum) ) { semGive(pSS->syncSemId); /* wake up the ss task */ } } - - /* Unlock resource */ - semGive(pSP->caSemId); -} - -/* - * seq_efTest() - Test event flag against outstanding events. - */ -int seq_efTest(pSP, pSS, ev_flag) -SPROG *pSP; -SSCB *pSS; -int ev_flag; /* event flag */ -{ - return bitTest(pSP->events, ev_flag); -} - -/* - * seq_efClear() - Test event flag against outstanding events, then clear it. - */ -int seq_efClear(pSP, pSS, ev_flag) -SPROG *pSP; -SSCB *pSS; -int ev_flag; /* event flag */ -{ - int isSet; - - isSet = bitTest(pSP->events, ev_flag); - bitClear(pSP->events, ev_flag); - return isSet; -} - /* - * seq_pvGet() - Get DB value (uses channel access). - */ -seq_pvGet(pSP, pSS, pDB) -SPROG *pSP; /* ptr to state program */ -SSCB *pSS; /* ptr to current state set */ -CHAN *pDB; /* ptr to channel struct */ -{ - int status, sem_status; - extern VOID seq_callback_handler(); - - /* Check for channel connected */ - if (!pDB->connected) - return ECA_DISCONN; - - /* Flag this pvGet() as not completed */ - pDB->get_complete = FALSE; - - /* If synchronous pvGet then clear the pvGet pend semaphore */ - if ( !(pSP->options & OPT_ASYNC) ) - { - pDB->getSemId = pSS->getSemId; - semTake(pSS->getSemId, NO_WAIT); - } - - /* Perform the CA get operation with a callback routine specified */ - status = ca_array_get_callback( - pDB->get_type, /* db request type */ - pDB->count, /* element count */ - pDB->chid, /* chid */ - seq_callback_handler, /* callback handler */ - pDB); /* user arg */ - - if ( (pSP->options & OPT_ASYNC) || (status != ECA_NORMAL) ) - return status; - - /* Synchronous pvGet() */ - - ca_flush_io(); - - /* Wait for completion (10s timeout) */ - sem_status = semTake(pSS->getSemId, 600); - if (sem_status == ERROR) - status = ECA_TIMEOUT; - - return status; -} - -/* - * seq_callback_handler() - Sequencer callback handler. - * Called when a "get" completes. - * args.usr points to the db structure (CHAN *) for tis channel. - */ -VOID seq_callback_handler(args) -struct event_handler_args args; -{ - SPROG *pSP; - CHAN *pDB; - struct dbr_sts_char *dbr_sts_ptr; - int i, nbytes; - void *pVal; - - /* User arg is ptr to db channel structure */ - pDB = (CHAN *)args.usr; - - /* Copy value returned into user variable */ - pVal = getPtrToValue((union db_access_val *)args.dbr, pDB->get_type); - nbytes = pDB->size * pDB->count; - memcpy(pDB->var, pVal, nbytes); - - /* Copy status & severity */ - dbr_sts_ptr = (struct dbr_sts_char *)args.dbr; - pDB->status = dbr_sts_ptr->status; - pDB->severity = dbr_sts_ptr->severity; - - /* Set get complete flag */ - pDB->get_complete = TRUE; - - /* Wake up each state set that is waiting for event processing) */ - pSP = pDB->sprog; /* State program that owns this db entry */ - seq_efSet(pSP, 0, pDB->index + 1); - - /* If syncronous pvGet then notify pending state set */ - if ( !(pSP->options & OPT_ASYNC) ) - semGive(pDB->getSemId); - return; } - -/* Flush outstanding CA requests */ -VOID seq_pvFlush() -{ - ca_flush_io(); -} - -/* - * seq_pvPut() - Put DB value (uses channel access). - */ -seq_pvPut(pSP, pSS, pDB) -SPROG *pSP; /* ptr to state program */ -SSCB *pSS; /* ptr to current state set */ -CHAN *pDB; /* ptr to channel struct */ -{ - int status; - - if (!pDB->connected) - return ECA_DISCONN; - - status = ca_array_put(pDB->put_type, pDB->count, - pDB->chid, pDB->var); - if (status != ECA_NORMAL) - { -#ifdef DEBUG - seq_log(pSP, "pvPut on \"%s\" failed (%d)\n", - pDB->db_name, status); - seq_log(pSP, " put_type=%d\n", pDB->put_type); - seq_log(pSP, " size=%d, count=%d\n", pDB->size, pDB->count); -#endif /* DEBUG */ - } - - return status; -} - /* - * seq_pvMonitor() - Initiate a monitor on a channel. - */ -seq_pvMonitor(pSP, pSS, pDB) -SPROG *pSP; /* ptr to state program */ -SSCB *pSS; /* ptr to current state set */ -CHAN *pDB; /* ptr to channel struct */ -{ - int status; - extern VOID seq_event_handler(); - -#ifdef DEBUG - printf("monitor \"%s\"\n", pDB->db_name); -#endif /* DEBUG */ - - if (pDB->monitored) - return; - - status = ca_add_array_event( - pDB->get_type, /* requested type */ - pDB->count, /* element count */ - pDB->chid, /* chid */ - seq_event_handler, /* function to call */ - pDB, /* user arg (db struct) */ - pDB->delta, /* pos. delta value */ - pDB->delta, /* neg. delta value */ - pDB->timeout, /* timeout */ - &pDB->evid); /* where to put event id */ - - if (status != ECA_NORMAL) - { - SEVCHK(status, "ca_add_array_event"); - ca_task_exit(); /* this is serious */ - return; - } - ca_flush_io(); - - pDB->monitored = TRUE; - return; -} - -/* - * seq_pvStopMonitor() - Cancel a monitor - */ -seq_pvStopMonitor(pSP, pSS, pDB) -SPROG *pSP; /* ptr to state program */ -SSCB *pSS; /* ptr to current state set */ -CHAN *pDB; /* ptr to channel struct */ -{ - int status; - - if (!pDB->monitored) - return -1; - - status = ca_clear_event(pDB->evid); - if (status != ECA_NORMAL) - { - SEVCHK(status, "ca_clear_event"); - return status; - } - - pDB->monitored = FALSE; - - return status; -} - -/* - * getPtr() - Given ptr to value structure & type, return ptr to value. - */ -LOCAL VOID *getPtrToValue(pBuf, dbrType) -union db_access_val *pBuf; -chtype dbrType; -{ - switch (dbrType) { - case DBR_STRING: return (void *)pBuf->strval; - case DBR_STS_STRING: return (void *)pBuf->sstrval.value; - - case DBR_SHORT: return (void *)&pBuf->shrtval; - case DBR_STS_SHORT: return (void *)&pBuf->sshrtval.value; - - case DBR_FLOAT: return (void *)&pBuf->fltval; - case DBR_STS_FLOAT: return (void *)&pBuf->sfltval.value; - - case DBR_ENUM: return (void *)&pBuf->enmval; - case DBR_STS_ENUM: return (void *)&pBuf->senmval.value; - - case DBR_CHAR: return (void *)&pBuf->charval; - case DBR_STS_CHAR: return (void *)&pBuf->schrval.value; - - case DBR_LONG: return (void *)&pBuf->longval; - case DBR_STS_LONG: return (void *)&pBuf->slngval.value; - - case DBR_DOUBLE: return (void *)&pBuf->doubleval; - case DBR_STS_DOUBLE: return (void *)&pBuf->sdblval.value; - default: return NULL; - } -} #include "memLib.h" #include "taskVarLib.h" #include "taskLib.h" @@ -524,7 +336,7 @@ chtype dbrType; * SEE ALSO: taskVarAdd(2), taskVarGet(2), taskVarSet(2) */ -LOCAL STATUS taskVarDelete (tid, pVar) +LOCAL STATUS LtaskVarDelete (tid, pVar) int tid; /* task id whose task variable is to be retrieved */ int *pVar; /* pointer to task variable to be removed from task */ @@ -571,7 +383,7 @@ int tid; extern int ca_static; int status; - status = taskVarDelete(tid, &ca_static); + status = LtaskVarDelete(tid, &ca_static); if (status != OK) { logMsg("Seq: taskVarDelete failed for tid = 0x%x\n", tid); diff --git a/src/sequencer/seq_if.c b/src/sequencer/seq_if.c new file mode 100644 index 000000000..218a56b04 --- /dev/null +++ b/src/sequencer/seq_if.c @@ -0,0 +1,616 @@ +/* + seq_if.c,v 1.3 1995/10/10 01:56:49 wright Exp + * DESCRIPTION: Interface functions from state program to run-time sequencer. + * Note: To prevent global name conflicts "seq_" is added by the SNC, e.g. + * pvPut() becomes seq_pvPut(). + * + * Author: Andy Kozubal + * Date: 1 March, 1994 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991-1994, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + */ + +#define ANSI +#include "seq.h" + +/* See seqCom.h for function prototypes (ANSI standard) */ + +/*#define DEBUG*/ + + /* The following "pv" functions are included here: + seq_pvGet() + seq_pvGetComplete() + seq_pvPut() + seq_pvFlush() + seq_pvConnect() + seq_pvMonitor() + seq_pvStopMonitor() + seq_pvStatus() + seq_pvSeverity() + seq_pvConnected() + seq_pvAssigned() + seq_pvChannelCount() + seq_pvAssignCount() + seq_pvConnectCount() + seq_pvCount() + seq_pvIndex() + seq_pvTimeStamp() + */ + +/* Flush outstanding CA requests */ +void seq_pvFlush() +{ + ca_flush_io(); +} + +/* + * seq_pvGet() - Get DB value (uses channel access). + */ +seq_pvGet(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + SSCB *pSS; + CHAN *pDB; /* ptr to channel struct */ + int status, sem_status; + extern VOID seq_callback_handler(); + + pSS = (SSCB *)ssId; + pSP = pSS->sprog; + pDB = pSP->pChan + pvId; + + /* Check for channel connected */ + if (!pDB->connected) + return ECA_DISCONN; + + /* Flag this pvGet() as not completed */ + pDB->getComplete = FALSE; + + /* If synchronous pvGet then clear the pvGet pend semaphore */ + if ( !(pSP->options & OPT_ASYNC) ) + { + pDB->getSemId = pSS->getSemId; + semTake(pSS->getSemId, NO_WAIT); + } + + /* Perform the CA get operation with a callback routine specified */ + status = ca_array_get_callback( + pDB->getType, /* db request type */ + pDB->count, /* element count */ + pDB->chid, /* chid */ + seq_callback_handler, /* callback handler */ + pDB); /* user arg */ + + if ( (pSP->options & OPT_ASYNC) || (status != ECA_NORMAL) ) + return status; + + /* Synchronous pvGet() */ + + ca_flush_io(); + + /* Wait for completion (10s timeout) */ + sem_status = semTake(pSS->getSemId, 600); + if (sem_status == ERROR) + status = ECA_TIMEOUT; + + return status; +} + +/* + * seq_pvGetComplete() - returns TRUE if the last get completed. + */ +seq_pvGetComplete(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan; + return pDB->getComplete; +} + + +/* + * seq_pvPut() - Put DB value. + */ +seq_pvPut(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; +#ifdef DEBUG + logMsg("seq_pvPut: pv name=%s, pVar=0x%x\n", pDB->dbName, pDB->pVar); +#endif DEBUG + + if (!pDB->connected) + return ECA_DISCONN; + + status = ca_array_put(pDB->putType, pDB->count, + pDB->chid, pDB->pVar); +#ifdef DEBUG + logMsg("seq_pvPut: status=%d\n", status); + if (status != ECA_NORMAL) + { + seq_log(pSP, "pvPut on \"%s\" failed (%d)\n", + pDB->dbName, status); + seq_log(pSP, " putType=%d\n", pDB->putType); + seq_log(pSP, " size=%d, count=%d\n", pDB->size, pDB->count); + } +#endif DEBUG + + return status; +} + /* + * seq_pvAssign() - Assign/Connect to a channel. + * Assign to a zero-lth string ("") disconnects/de-assignes. + */ +seq_pvAssign(ssId, pvId, pvName) +SS_ID ssId; +int pvId; +char *pvName; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status, nchar; + extern VOID seq_conn_handler(); + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + +#ifdef DEBUG + printf("Assign %s to \"%s\"\n", pDB->pVarName, pvName); +#endif DEBUG + if (pDB->assigned) + { /* Disconnect this channel */ + status = ca_clear_channel(pDB->chid); + if (status != ECA_NORMAL) + return status; + free(pDB->dbName); + pDB->assigned = FALSE; + pSP->assignCount -= 1; + } + + if (pDB->connected) + { + pDB->connected = FALSE; + pSP->connCount -= 1; + } + pDB->monitored = FALSE; + nchar = strlen(pvName); + pDB->dbName = (char *)calloc(1, nchar + 1); + strcpy(pDB->dbName, pvName); + + /* Connect */ + if (nchar > 0) + { + pDB->assigned = TRUE; + pSP->assignCount += 1; + status = ca_build_and_connect( + pDB->dbName, /* DB channel name */ + TYPENOTCONN, /* Don't get initial value */ + 0, /* get count (n/a) */ + &(pDB->chid), /* ptr to chid */ + 0, /* ptr to value (n/a) */ + seq_conn_handler, /* connection handler routine */ + pDB); /* user ptr is CHAN structure */ + if (status != ECA_NORMAL) + { + return status; + } + + if (pDB->monFlag) + { + status = seq_pvMonitor(ssId, pvId); + if (status != ECA_NORMAL) + return status; + } + } + + ca_flush_io(); + + return ECA_NORMAL; +} + /* + * seq_pvMonitor() - Initiate a monitor on a channel. + */ +seq_pvMonitor(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + extern VOID seq_event_handler(); + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + +#ifdef DEBUG + printf("monitor \"%s\"\n", pDB->dbName); +#endif DEBUG + + if (pDB->monitored || !pDB->assigned) + return ECA_NORMAL; + + status = ca_add_array_event( + pDB->getType, /* requested type */ + pDB->count, /* element count */ + pDB->chid, /* chid */ + seq_event_handler, /* function to call */ + pDB, /* user arg (db struct) */ + 0.0, /* pos. delta value */ + 0.0, /* neg. delta value */ + 0.0, /* timeout */ + &pDB->evid); /* where to put event id */ + + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_add_array_event"); + ca_task_exit(); /* this is serious */ + return status; + } + ca_flush_io(); + + pDB->monitored = TRUE; + return ECA_NORMAL; +} + +/* + * seq_pvStopMonitor() - Cancel a monitor + */ +seq_pvStopMonitor(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + if (!pDB->monitored) + return -1; + + status = ca_clear_event(pDB->evid); + if (status != ECA_NORMAL) + { + SEVCHK(status, "ca_clear_event"); + return status; + } + + pDB->monitored = FALSE; + + return status; +} + +/* + * seq_pvChannelCount() - returns total number of database channels. + */ +seq_pvChannelCount(ssId) +SS_ID ssId; +{ + SPROG *pSP; /* ptr to state program */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + return pSP->numChans; +} + +/* + * seq_pvConnectCount() - returns number of database channels connected. + */ +seq_pvConnectCount(ssId) +SS_ID ssId; +{ + SPROG *pSP; /* ptr to state program */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + return pSP->connCount; +} + +/* + * seq_pvAssignCount() - returns number of database channels assigned. + */ +seq_pvAssignCount(ssId) +SS_ID ssId; +{ + SPROG *pSP; /* ptr to state program */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + return pSP->assignCount; +} + +/* + * seq_pvConnected() - returns TRUE if database channel is connected. + */ +seq_pvConnected(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->connected; +} + +/* + * seq_pvAssigned() - returns TRUE if database channel is assigned. + */ +seq_pvAssigned(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->assigned; +} + +/* + * seq_pvCount() - returns number elements in an array, which is the lesser of + * (1) the array size and (2) the element count returned by channel access. + */ +seq_pvCount(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->dbCount; +} + +/* + * seq_pvStatus() - returns channel alarm status. + */ +seq_pvStatus(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->status; +} + +/* + * seq_pvSeverity() - returns channel alarm severity. + */ +seq_pvSeverity(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->severity; +} + +/* + * seq_pvIndex() - returns index of database variable. + */ +int seq_pvIndex(ssId, pvId) +SS_ID ssId; +int pvId; +{ + return pvId; /* index is same as pvId */ +} + +/* + * seq_pvTimeStamp() - returns channel time stamp. + */ +TS_STAMP seq_pvTimeStamp(ssId, pvId) +SS_ID ssId; +int pvId; +{ + SPROG *pSP; /* ptr to state program */ + CHAN *pDB; /* ptr to channel struct */ + int status; + + pSP = ((SSCB *)ssId)->sprog; + pDB = pSP->pChan + pvId; + return pDB->timeStamp; +} + /* + * seq_efSet() - Set an event flag, then wake up each state + * set that might be waiting on that event flag. + */ +VOID seq_efSet(ssId, ev_flag) +SS_ID ssId; +int ev_flag; /* event flag */ +{ + SPROG *pSP; + SSCB *pSS; + int nss; + + pSS = (SSCB *)ssId; + pSP = pSS->sprog; + +#ifdef DEBUG + logMsg("seq_efSet: pSP=0x%x, pSS=0x%x, ev_flag=0x%x\n", pSP, pSS, ev_flag); + taskDelay(10); +#endif DEBUG + + /* Set this bit (apply resource lock) */ + semTake(pSP->caSemId, WAIT_FOREVER); + bitSet(pSP->pEvents, ev_flag); + + /* Wake up state sets that are waiting for this event flag */ + seqWakeup(pSP, ev_flag); + + /* Unlock resource */ + semGive(pSP->caSemId); +} + +/* + * seq_efTest() - Test event flag against outstanding events. + */ +int seq_efTest(ssId, ev_flag) +SS_ID ssId; +int ev_flag; /* event flag */ +{ + SPROG *pSP; + SSCB *pSS; + int isSet; + + pSS = (SSCB *)ssId; + pSP = pSS->sprog; + isSet = bitTest(pSP->pEvents, ev_flag); +#ifdef DEBUG + logMsg("seq_efTest: ev_flag=%d, event=0x%x, isSet=%d\n", + ev_flag, pSP->pEvents[0], isSet); +#endif DEBUG + return isSet; +} + +/* + * seq_efClear() - Test event flag against outstanding events, then clear it. + */ +int seq_efClear(ssId, ev_flag) +SS_ID ssId; +int ev_flag; /* event flag */ +{ + SPROG *pSP; + SSCB *pSS; + int isSet; + + pSS = (SSCB *)ssId; + pSP = pSS->sprog; + + isSet = bitTest(pSP->pEvents, ev_flag); + bitClear(pSP->pEvents, ev_flag); + return isSet; +} + +/* + * seq_efTestAndClear() - Test event flag against outstanding events, then clear it. + */ +int seq_efTestAndClear(ssId, ev_flag) +SS_ID ssId; +int ev_flag; /* event flag */ +{ + SPROG *pSP; + SSCB *pSS; + int isSet; + + pSS = (SSCB *)ssId; + pSP = pSS->sprog; + + isSet = bitTest(pSP->pEvents, ev_flag); + bitClear(pSP->pEvents, ev_flag); + return isSet; +} + /* + * seq_delay() - test for delay() time-out expired */ +int seq_delay(ssId, delayId) +SS_ID ssId; +int delayId; +{ + SSCB *pSS; + ULONG timeElapsed; + + pSS = (SSCB *)ssId; + + /* Calc. elapsed time since state was entered */ + timeElapsed = tickGet() - pSS->timeEntered; + + /* Check for delay timeout */ + if (timeElapsed >= pSS->delay[delayId]) + { + pSS->delayExpired[delayId] = TRUE; /* mark as expired */ + return TRUE; + } + + return FALSE; +} + +/* + * seq_delayInit() - initialize delay time on entering a state. + */ +VOID seq_delayInit(ssId, delayId, delay) +SS_ID ssId; +int delayId; +float delay; /* delay in seconds */ +{ + SSCB *pSS; + int ndelay; + + pSS = (SSCB *)ssId; + + /* Convert delay time to tics & save */ + pSS->delay[delayId] = delay * 60.0; + + ndelay = delayId + 1; + if (ndelay > pSS->numDelays) + pSS->numDelays = ndelay; +} + /* + * seq_optGet: return the value of an option. + * FALSE means "-" and TRUE means "+". + */ +BOOL seq_optGet(ssId, opt) +SS_ID ssId; +char *opt; /* one of the snc options as a strign (e.g. "a") */ +{ + SPROG *pSP; + + pSP = ((SSCB *)ssId)->sprog; + switch (opt[0]) + { + case 'a': return ( (pSP->options & OPT_ASYNC) != 0); + case 'c': return ( (pSP->options & OPT_CONN) != 0); + case 'd': return ( (pSP->options & OPT_DEBUG) != 0); + case 'e': return ( (pSP->options & OPT_NEWEF) != 0); + case 'r': return ( (pSP->options & OPT_REENT) != 0); + case 'v': return ( (pSP->options & OPT_VXWORKS) != 0); + default: return FALSE; + } +} diff --git a/src/sequencer/seq_mac.c b/src/sequencer/seq_mac.c index c0b290a5e..3dd6b8fb1 100644 --- a/src/sequencer/seq_mac.c +++ b/src/sequencer/seq_mac.c @@ -3,7 +3,9 @@ Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - $Id$ + + seq_mac.c,v 1.2 1995/06/27 15:25:56 wright Exp + DESCRIPTION: Macro routines for Sequencer. The macro table contains name & value pairs. These are both pointers to strings. @@ -11,77 +13,72 @@ ENVIRONMENT: VxWorks HISTORY: +01mar94,ajk Added seq_macValueGet() as state program interface routine. + ***************************************************************************/ #define ANSI #include "seq.h" -#include -LOCAL int macNameLth(char *); LOCAL int seqMacParseName(char *); LOCAL int seqMacParseValue(char *); LOCAL char *skipBlanks(char *); -LOCAL MACRO *seqMacTblGet(char *, MACRO *); +LOCAL MACRO *seqMacTblGet(MACRO *, char *); /*#define DEBUG*/ - /* - *seqMacTblInit - initialize macro the table. - */ -seqMacTblInit(pMac) -MACRO *pMac; -{ - int i; - - for (i = 0 ; i < MAX_MACROS; i++, pMac++) - { - pMac->name = NULL; - pMac->value = NULL; - } -} - /* *seqMacEval - substitute macro value into a string containing: * ....{mac_name}.... */ -seqMacEval(pInStr, pOutStr, maxChar, macTbl) +VOID seqMacEval(pInStr, pOutStr, maxChar, pMac) char *pInStr; char *pOutStr; int maxChar; -MACRO *macTbl; +MACRO *pMac; { - char *pMacVal, *pTmp; + char name[50], *pValue, *pTmp; int nameLth, valLth; #ifdef DEBUG - printf("seqMacEval: InStr=%s\n", pInStr); + logMsg("seqMacEval: InStr=%s\n", pInStr); + taskDelay(30); #endif pTmp = pOutStr; while (*pInStr != 0 && maxChar > 0) { if (*pInStr == '{') - { /* Macro substitution */ + { /* Do macro substitution */ pInStr++; /* points to macro name */ - nameLth = macNameLth(pInStr); + /* Copy the macro name */ + nameLth = 0; + while (*pInStr != '}' && *pInStr != 0) + { + name[nameLth] = *pInStr++; + if (nameLth < (sizeof(name) - 1)) + nameLth++; + } + name[nameLth] = 0; + if (*pInStr != 0) + pInStr++; + #ifdef DEBUG - printf("Name=%s[%d]\n", pInStr, nameLth); + logMsg("Macro name=%s\n", name); + taskDelay(30); #endif /* Find macro value from macro name */ - pMacVal = seqMacValGet(pInStr, nameLth, macTbl); - if (pMacVal != NULL) + pValue = seqMacValGet(pMac, name); + if (pValue != NULL) { /* Substitute macro value */ - valLth = strlen(pMacVal); + valLth = strlen(pValue); if (valLth > maxChar) valLth = maxChar; #ifdef DEBUG - printf("Val=%s[%d]\n", pMacVal, valLth); + logMsg("Value=%s\n", pValue); #endif - strncpy(pOutStr, pMacVal, valLth); + strncpy(pOutStr, pValue, valLth); maxChar -= valLth; pOutStr += valLth; } - pInStr += nameLth; - if (*pInStr != 0) - pInStr++; /* skip '}' */ } else @@ -89,52 +86,58 @@ MACRO *macTbl; *pOutStr++ = *pInStr++; maxChar--; } - *pOutStr = 0; -#ifdef DEBUG - printf("OutStr=%s\n", pTmp); -#endif } *pOutStr = 0; +#ifdef DEBUG + logMsg("OutStr=%s\n", pTmp); + taskDelay(30); +#endif } /* - * seqMacValGet - given macro name, return pointer to its value. + * seq_macValueGet - given macro name, return pointer to its value. */ -char *seqMacValGet(macName, macNameLth, macTbl) -char *macName; -int macNameLth; -MACRO *macTbl; +char *seq_macValueGet(ssId, pName) +SS_ID ssId; +char *pName; { - int i; + SPROG *pSP; + MACRO *pMac; - for (i = 0 ; i < MAX_MACROS; i++, macTbl++) + pSP = ((SSCB *)ssId)->sprog; + pMac = pSP->pMacros; + + return seqMacValGet(pMac, pName); +} +/* + * seqMacValGet - internal routine to convert macro name to macro value. + */ +char *seqMacValGet(pMac, pName) +MACRO *pMac; +char *pName; +{ + int i; + +#ifdef DEBUG + logMsg("seqMacValGet: name=%s", pName); +#endif DEBUG + for (i = 0 ; i < MAX_MACROS; i++, pMac++) { - if ((macTbl->name != NULL) && - (strlen(macTbl->name) == macNameLth)) + if (pMac->pName != NULL) { - if (strncmp(macName, macTbl->name, macNameLth) == 0) + if (strcmp(pName, pMac->pName) == 0) { - return macTbl->value; +#ifdef DEBUG + logMsg(", value=%s\n", pMac->pValue); +#endif DEBUG + return pMac->pValue; } } } +#ifdef DEBUG + logMsg(", no value\n"); +#endif DEBUG return NULL; } - -/* - * macNameLth() - Return number of characters in a macro name */ -LOCAL int macNameLth(pstr) -char *pstr; -{ - int nchar; - - nchar = 0; - while ( (*pstr != 0) && (*pstr != '}') ) - { - pstr++; - nchar++; - } - return nchar; -} /* * seqMacParse - parse the macro definition string and build * the macro table (name/value pairs). Returns number of macros parsed. @@ -147,11 +150,11 @@ SPROG *pSP; { int nMac, nChar; char *skipBlanks(); - MACRO *macTbl; /* macro table */ + MACRO *pMac; /* macro table */ MACRO *pMacTbl; /* macro tbl entry */ - char *name, *value; + char *pName, *pValue; - macTbl = pSP->mac_ptr; + pMac = pSP->pMacros; for ( ;; ) { /* Skip blanks */ @@ -162,23 +165,24 @@ SPROG *pSP; nChar = seqMacParseName(pMacStr); if (nChar == 0) break; /* finished or error */ - name = seqAlloc(pSP, nChar+1); - if (name == NULL) + pName = (char *)calloc(nChar+1, 1); + if (pName == NULL) break; - memcpy(name, pMacStr, nChar); - name[nChar] = 0; + bcopy(pMacStr, pName, nChar); + pName[nChar] = 0; #ifdef DEBUG - printf("name=%s, nChar=%d\n", name, nChar); + logMsg("name=%s, nChar=%d\n", pName, nChar); + taskDelay(30); #endif pMacStr += nChar; /* Find a slot in the table */ - pMacTbl = seqMacTblGet(name, macTbl); + pMacTbl = seqMacTblGet(pMac, pName); if (pMacTbl == NULL) break; /* table is full */ - if (pMacTbl->name == NULL) + if (pMacTbl->pName == NULL) { /* Empty slot, insert macro name */ - pMacTbl->name = name; + pMacTbl->pName = pName; } /* Skip over blanks and equal sign or comma */ @@ -196,20 +200,26 @@ SPROG *pSP; nChar = seqMacParseValue(pMacStr); if (nChar == 0) break; - value = seqAlloc(pSP, nChar+1); - if (value == NULL) + + /* Remove previous value if it exists */ + pValue = pMacTbl->pValue; + if (pValue != NULL) + free(pValue); + + /* Copy value string into newly allocated space */ + pValue = (char *)calloc(nChar+1, 1); + if (pValue == NULL) break; - memcpy(value, pMacStr, nChar); - value[nChar] = 0; - pMacStr += nChar; + pMacTbl->pValue = pValue; + bcopy(pMacStr, pValue, nChar); + pValue[nChar] = 0; #ifdef DEBUG - printf("value=%s, nChar=%d\n", value, nChar); + logMsg("value=%s, nChar=%d\n", pValue, nChar); + taskDelay(30); #endif - /* Insert or replace macro value */ - pMacTbl->value = value; - - /* Skip blanks and comma */ + /* Skip past last value and over blanks and comma */ + pMacStr += nChar; pMacStr = skipBlanks(pMacStr); if (*pMacStr++ != ',') break; @@ -245,7 +255,8 @@ char *pStr; /* * seqMacParseValue() - Parse a macro value from the input string. - */LOCAL int seqMacParseValue(pStr) + */ +LOCAL int seqMacParseValue(pStr) char *pStr; { int nChar; @@ -260,6 +271,7 @@ char *pStr; return nChar; } +/* skipBlanks() - skip blank characters */ LOCAL char *skipBlanks(pChar) char *pChar; { @@ -272,21 +284,22 @@ char *pChar; * seqMacTblGet - find a match for the specified name, otherwise * return an empty slot in macro table. */ -LOCAL MACRO *seqMacTblGet(name, macTbl) -char *name; /* macro name */ -MACRO *macTbl; +LOCAL MACRO *seqMacTblGet(pMac, pName) +MACRO *pMac; +char *pName; /* macro name */ { int i; MACRO *pMacTbl; #ifdef DEBUG - printf("seqMacTblGet: name=%s\n", name); + logMsg("seqMacTblGet: name=%s\n", pName); + taskDelay(30); #endif - for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++) + for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++) { - if (pMacTbl->name != NULL) + if (pMacTbl->pName != NULL) { - if (strcmp(name, pMacTbl->name) == 0) + if (strcmp(pName, pMacTbl->pName) == 0) { return pMacTbl; } @@ -294,9 +307,9 @@ MACRO *macTbl; } /* Not found, find an empty slot */ - for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++) + for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++) { - if (pMacTbl->name == NULL) + if (pMacTbl->pName == NULL) { return pMacTbl; } diff --git a/src/sequencer/seq_main.c b/src/sequencer/seq_main.c index 686ae3fb5..2b3912fd1 100644 --- a/src/sequencer/seq_main.c +++ b/src/sequencer/seq_main.c @@ -1,9 +1,11 @@ /************************************************************************** GTA PROJECT AT division - Copyright, 1990, 91, 92, 93, The Regents of the University of California. - Los Alamos National Laboratory + Copyright, 1990-1994, The Regents of the University of California + and the University of Chicago. + Los Alamos National Laboratory + + seq_main.c,v 1.2 1995/06/27 15:25:58 wright Exp - $Id$ DESCRIPTION: Seq() initiates a sequence as a group of cooperating tasks. An optional string parameter specifies the values for macros. The channel access context and task are shared by all state @@ -30,25 +32,41 @@ 29apr92,ajk Now alocates private program structures, even when reentry option is not specified. This avoids problems with seqAddTask(). 29apr92,ajk Implemented mutual exclusion lock in seq_log(). -16feb93,ajk Converted to single task for channel access, all state programs. +16feb93,ajk Converted to single channel access task for all state programs. 16feb93,ajk Removed VxWorks pre-v5 stuff. 17feb93,ajk Evaluation of channel names moved here from seq_ca.c. 19feb93,ajk Fixed time stamp format for seq_log(). 16jun93,ajk Fixed taskSpawn() to have 15 args per vx5.1. 20jul93,ajk Replaced obsolete delete() with remove() per vx5.1 release notes. 20jul93,ajk Removed #define ANSI +15mar94,ajk Implemented i/f to snc through structures in seqCom.h. +15mar94,ajk Allowed assignment of array elements to db. +15mar94,ajk Rearranged code that builds program structures. +02may94,ajk Performed initialization when sequencer is evoked, even w/o + parameters. ***************************************************************************/ /*#define DEBUG 1*/ +#include "seqCom.h" #include "seq.h" +#ifdef DEBUG +#undef LOCAL +#define LOCAL +#endif DEBUG /* ANSI functional prototypes for local routines */ -LOCAL SPROG *alloc_task_area(SPROG *); -LOCAL VOID copy_sprog(SPROG *, SPROG *); -LOCAL VOID init_sprog(SPROG *); -LOCAL VOID init_sscb(SPROG *); +LOCAL SPROG *seqInitTables(struct seqProgram *); +LOCAL SPROG *alloc_task_area(struct seqProgram *); +LOCAL VOID init_sprog(struct seqProgram *, SPROG *); +LOCAL VOID init_sscb(struct seqProgram *, SPROG *); +LOCAL VOID init_chan(struct seqProgram *, SPROG *); +LOCAL VOID init_mac(SPROG *); + LOCAL VOID seq_logInit(SPROG *); LOCAL VOID seqChanNameEval(SPROG *); +LOCAL int countStates(struct seqProgram *); +LOCAL int roundUp(int); +LOCAL VOID selectDBtype(char *, short *, short *, short *, short *); #define SCRATCH_SIZE (MAX_MACROS*(MAX_STRING_SIZE+1)*12) /* Globals */ @@ -68,41 +86,22 @@ int seqAuxTaskId = 0; * Creates the initial state program task and returns its task id. * Most initialization is performed here. */ -int seq(pSP_orig, macro_def, stack_size) -SPROG *pSP_orig; /* ptr to original state program table */ -char *macro_def; /* optional macro def'n string */ -int stack_size; /* optional stack size (bytes) */ +int seq(pSeqProg, macro_def, stack_size) +struct seqProgram *pSeqProg; /* state program info generated by snc */ +char *macro_def; /* optional macro def'n string */ +int stack_size; /* optional stack size (bytes) */ { int tid; extern sequencer(); /* Sequencer task entry point */ extern sprog_delete(); /* Task delete routine */ extern char *seqVersion; - SPROG *pSP, *alloc_task_area(); - char *pname, *pvalue, *ptask_name; + SPROG *pSP; + char *pValue, *ptask_name; extern seqAuxTask(); /* Print version & date of sequencer */ printf("%s\n", seqVersion); - /* Exit if no parameters specified */ - if (pSP_orig == 0) - { - return 0; - } - - /* Check for correct state program format */ - if (pSP_orig->magic != MAGIC) - { /* Oops */ - logMsg("Illegal magic number in state program.\n"); - logMsg(" - Possible mismatch between SNC & SEQ versions\n"); - logMsg(" - Re-compile your program?\n"); - return -1; - } - -#ifdef DEBUG - print_sp_info(pSP_orig); -#endif /* DEBUG */ - /* Spawn the sequencer auxillary task */ if (seqAuxTaskId == 0) { @@ -110,6 +109,9 @@ int stack_size; /* optional stack size (bytes) */ 0,0,0,0,0,0,0,0,0,0); while (seqAuxTaskId == 0) taskDelay(5); /* wait for task to init. ch'l access */ +#ifdef DEBUG + logMsg("task seqAux spawned, tid=0x%x\n", seqAuxTaskId); +#endif DEBUG } /* Specify a routine to run at task delete */ @@ -119,23 +121,26 @@ int stack_size; /* optional stack size (bytes) */ seqDeleteHookAdded = TRUE; } - /* Allocate a contiguous space for all dynamic structures */ - pSP = alloc_task_area(pSP_orig); + /* Exit if no parameters specified */ + if (pSeqProg == 0) + { + return 0; + } - /* Make a private copy of original structures (but change pointers!) */ - copy_sprog(pSP_orig, pSP); + /* Check for correct state program format */ + if (pSeqProg->magic != MAGIC) + { /* Oops */ + logMsg("Illegal magic number in state program.\n"); + logMsg(" - Possible mismatch between SNC & SEQ versions\n"); + logMsg(" - Re-compile your program?\n"); + return -1; + } - /* Initialize state program block */ - init_sprog(pSP); - - /* Initialize state set control blocks */ - init_sscb(pSP); - - /* Initialize the macro definition table */ - seqMacTblInit(pSP->mac_ptr); /* Init macro table */ + /* Initialize the sequencer tables */ + pSP = seqInitTables(pSeqProg); /* Parse the macro definitions from the "program" statement */ - seqMacParse(pSP->params, pSP); + seqMacParse(pSeqProg->pParams, pSP); /* Parse the macro definitions from the command line */ seqMacParse(macro_def, pSP); @@ -149,183 +154,99 @@ int stack_size; /* optional stack size (bytes) */ /* Specify stack size */ if (stack_size == 0) stack_size = SPAWN_STACK_SIZE; - pname = "stack"; - pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr); - if (pvalue != NULL && strlen(pvalue) > 0) + pValue = seqMacValGet(pSP->pMacros, "stack"); + if (pValue != NULL && strlen(pValue) > 0) { - sscanf(pvalue, "%d", &stack_size); + sscanf(pValue, "%d", &stack_size); } if (stack_size < SPAWN_STACK_SIZE/2) stack_size = SPAWN_STACK_SIZE/2; /* Specify task name */ - pname = "name"; - pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr); - if (pvalue != NULL && strlen(pvalue) > 0) - ptask_name = pvalue; + pValue = seqMacValGet(pSP->pMacros, "name"); + if (pValue != NULL && strlen(pValue) > 0) + ptask_name = pValue; else - ptask_name = pSP->name; + ptask_name = pSP->pProgName; /* Spawn the initial sequencer task */ +#ifdef DEBUG + logMsg("Spawing task %s, stack_size=%d\n", ptask_name, stack_size); +#endif tid = taskSpawn(ptask_name, SPAWN_PRIORITY, SPAWN_OPTIONS, stack_size, sequencer, (int)pSP, stack_size, (int)ptask_name, 0,0,0,0,0,0,0); seq_log(pSP, "Spawning state program \"%s\", task name = \"%s\"\n", - pSP->name, ptask_name); + pSP->pProgName, ptask_name); seq_log(pSP, " Task id = %d = 0x%x\n", tid, tid); /* Return task id to calling program */ return tid; } - - /* - * ALLOC_TASK_AREA - * Allocate a single block for all dynamic structures - * The pointer to the allocated area is saved for task delete hook routine. - */ -LOCAL SPROG *alloc_task_area(pSP_orig) -SPROG *pSP_orig; /* original state program structure */ + /* seqInitTables - initialize sequencer tables */ +LOCAL SPROG *seqInitTables(pSeqProg) +struct seqProgram *pSeqProg; { - int size, nss, nstates, nchannels, user_size, - prog_size, ss_size, state_size, chan_size, mac_size, scr_size; - SPROG *pSP_new; /* ptr to new state program struct */ - char *dyn_ptr, *dyn_ptr_start; /* ptr to allocated area */ + SPROG *pSP; - nss = pSP_orig->nss; - nstates = pSP_orig->nstates; - nchannels = pSP_orig->nchan; + pSP = (SPROG *)calloc(1, sizeof (SPROG)); - /* Calc. # of bytes to allocate for all structures */ - prog_size = sizeof(SPROG); - ss_size = nss*sizeof(SSCB); - state_size = nstates*sizeof(STATE); - chan_size = nchannels*sizeof(CHAN); - user_size = pSP_orig->user_size; - mac_size = MAX_MACROS*sizeof(MACRO); - scr_size = SCRATCH_SIZE; + /* Initialize state program block */ + init_sprog(pSeqProg, pSP); - /* Total # bytes to allocate */ - size = prog_size + ss_size + state_size + - chan_size + user_size + mac_size + scr_size; + /* Initialize state set control blocks */ + init_sscb(pSeqProg, pSP); - /* Alloc the dynamic task area */ - dyn_ptr = dyn_ptr_start = (char *)calloc(size, 1); + /* Initialize database channel blocks */ + init_chan(pSeqProg, pSP); + + /* Initialize the macro table */ + init_mac(pSP); + + + return pSP; +} + +/* Count the total number of states in a state program */ +LOCAL int countStates(pSeqProg) +struct seqProgram *pSeqProg; +{ + struct seqSS *pSeqSS; + int nstates, nss; + + nstates = 0; + for (nss = 0, pSeqSS = pSeqProg->pSS; nss < pSeqProg->numSS; nss++, pSeqSS++) + nstates += pSeqSS->numStates; +} + /* + * Copy data from seqCom.h structures into this task's dynamic structures as defined + * in seq.h. + */ +LOCAL VOID init_sprog(pSeqProg, pSP) +struct seqProgram *pSeqProg; +SPROG *pSP; +{ + SSCB *pSS; + STATE *pState; + CHAN *pDB; + char *pVar; + int i, nWords; + + /* Copy information for state program */ + pSP->numSS = pSeqProg->numSS; + pSP->numChans = pSeqProg->numChans; + pSP->numEvents = pSeqProg->numEvents; + pSP->options = pSeqProg->options; + pSP->pProgName = pSeqProg->pProgName; + pSP->exitFunc = pSeqProg->exitFunc; + pSP->varSize = pSeqProg->varSize; #ifdef DEBUG - printf("Allocate task area:\n"); - printf(" nss=%d, nstates=%d, nchannels=%d\n", nss, nstates, nchannels); - printf(" prog_size=%d, ss_size=%d, state_size=%d\n", - prog_size, ss_size, state_size); - printf(" user_size=%d, mac_size=%d, scr_size=%d\n", - user_size, mac_size, scr_size); - printf(" size=%d=0x%x\n", size, size); - printf(" dyn_ptr=%d=0x%x\n", dyn_ptr, dyn_ptr); -#endif /* DEBUG */ + logMsg("init_sprog: num SS=%d, num Chans=%d, num Events=%d, Prog Name=%s, var Size=%d\n", + pSP->numSS, pSP->numChans, pSP->numEvents, pSP->pProgName, pSP->varSize); +#endif DEBUG - /* Set ptrs in the PROG structure */ - pSP_new = (SPROG *)dyn_ptr; - - /* Copy the SPROG struct contents */ - *pSP_new = *pSP_orig; - - /* Allocate space for copies of the original structures */ - dyn_ptr += prog_size; - pSP_new->sscb = (SSCB *)dyn_ptr; - dyn_ptr += ss_size; - pSP_new->states = (STATE *)dyn_ptr; - dyn_ptr += state_size; - pSP_new->channels = (CHAN *)dyn_ptr; - dyn_ptr += chan_size; - if (user_size != 0) - { - pSP_new->user_area = (char *)dyn_ptr; - dyn_ptr += user_size; - } - else - pSP_new->user_area = NULL; - - /* Create additional dynamic structures for macros and scratch area */ - pSP_new->mac_ptr = (MACRO *)dyn_ptr; - dyn_ptr += mac_size; - pSP_new->scr_ptr = (char *)dyn_ptr; - pSP_new->scr_nleft = scr_size; - - /* Save ptr to start of allocated area so we can free it at task delete */ - pSP_new->dyn_ptr = dyn_ptr_start; - - return pSP_new; -} - /* - * Copy the SSCB, STATE, and CHAN structures into this task's dynamic structures. - * Note: we have to change some pointers in the SPROG struct, user variables, - * and all SSCB structs. - */ -LOCAL VOID copy_sprog(pSP_orig, pSP) -SPROG *pSP_orig; /* original ptr to program struct */ -SPROG *pSP; /* new ptr */ -{ - SSCB *pSS, *pSS_orig; - STATE *pST, *pST_orig; - CHAN *pDB, *pDB_orig; - int nss, nstates, nchan; - char *var_ptr; - - /* Ptr to 1-st SSCB in original SPROG */ - pSS_orig = pSP_orig->sscb; - - /* Ptr to 1-st SSCB in new SPROG */ - pSS = pSP->sscb; - - /* Copy structures for each state set */ - for (nss = 0, pST = pSP->states; nss < pSP->nss; nss++) - { - *pSS = *pSS_orig; /* copy SSCB */ - pSS->states = pST; /* new ptr to 1-st STATE */ - pST_orig = pSS_orig->states; - for (nstates = 0; nstates < pSS->num_states; nstates++) - { - *pST = *pST_orig; /* copy STATE struct */ - pST++; - pST_orig++; - } - pSS++; - pSS_orig++; - } - - /* Copy database channel structures */ - pDB = pSP->channels; - pDB_orig = pSP_orig->channels; - var_ptr = pSP->user_area; - for (nchan = 0; nchan < pSP->nchan; nchan++) - { - *pDB = *pDB_orig; - - /* Reset ptr to SPROG structure */ - pDB->sprog = pSP; - - /* +r: Convert offset to address of the user variable. - * -r: var_ptr is an absolute address. - */ - if (pSP->options & OPT_REENT) - pDB->var += (int)var_ptr; - - pDB++; - pDB_orig++; - } - - /* Note: user area is not copied; it should be all zeros */ - - return; -} - /* - * Initialize the state program block - */ -LOCAL VOID init_sprog(pSP) -SPROG *pSP; -{ - int i; - - /* Semaphore for resource locking on CA events */ + /* Create a semaphore for resource locking on CA events */ pSP->caSemId = semBCreate(SEM_Q_FIFO, SEM_FULL); if (pSP->caSemId == NULL) { @@ -334,26 +255,54 @@ SPROG *pSP; } pSP->task_is_deleted = FALSE; + pSP->connCount = 0; + pSP->assignCount = 0; pSP->logFd = 0; - /* Clear all event flags */ - for (i = 0; i < NWRDS; i++) - pSP->events[i] = 0; + /* Allocate an array for event flag bits */ + nWords = (pSP->numEvents + NBITS - 1) / NBITS; + if (nWords == 0) + nWords = 1; + pSP->pEvents = (bitMask *)calloc(nWords, sizeof(bitMask)); + for (i = 0; i < nWords; i++) + pSP->pEvents[i] = 0; return; } /* * Initialize the state set control blocks */ -LOCAL VOID init_sscb(pSP) -SPROG *pSP; +LOCAL VOID init_sscb(pSeqProg, pSP) +struct seqProgram *pSeqProg; +SPROG *pSP; { - SSCB *pSS; - int nss, i; + SSCB *pSS; + STATE *pState; + int nss, i, nstates; + struct seqSS *pSeqSS; + struct seqState *pSeqState; - for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++) + + /* Allocate space for the SSCB structures */ + pSP->pSS = pSS = (SSCB *)calloc(pSeqProg->numSS, sizeof(SSCB)); + + /* Copy information for each state set and state */ + pSeqSS = pSeqProg->pSS; + for (nss = 0; nss < pSeqProg->numSS; nss++, pSS++, pSeqSS++) { - pSS->task_id = 0; + /* Fill in SSCB */ + pSS->pSSName = pSeqSS->pSSName; + pSS->numStates = pSeqSS->numStates; + pSS->errorState = pSeqSS->errorState; + pSS->currentState = 0; /* initial state */ + pSS->nextState = 0; + pSS->prevState = 0; + pSS->taskId = 0; + pSS->sprog = pSP; +#ifdef DEBUG + logMsg("init_sscb: SS Name=%s, num States=%d, pSS=0x%x\n", + pSS->pSSName, pSS->numStates, pSS); +#endif DEBUG /* Create a binary semaphore for synchronizing events in a SS */ pSS->syncSemId = semBCreate(SEM_Q_FIFO, SEM_FULL); if (pSS->syncSemId == NULL) @@ -375,12 +324,100 @@ SPROG *pSP; } - pSS->current_state = 0; /* initial state */ - pSS->next_state = 0; - pSS->action_complete = TRUE; + /* Allocate & fill in state blocks */ + pSS->pStates = pState = (STATE *)calloc(pSS->numStates, sizeof(STATE)); + + pSeqState = pSeqSS->pStates; + for (nstates = 0; nstates < pSeqSS->numStates; + nstates++, pState++, pSeqState++) + { + pState->pStateName = pSeqState->pStateName; + pState->actionFunc = pSeqState->actionFunc; + pState->eventFunc = pSeqState->eventFunc; + pState->delayFunc = pSeqState->delayFunc; + pState->pEventMask = pSeqState->pEventMask; +#ifdef DEBUG + logMsg("init_sscb: State Name=%s, Event Mask=0x%x\n", + pState->pStateName, *pState->pEventMask); +#endif DEBUG + } } + +#ifdef DEBUG + logMsg("init_sscb: numSS=%d\n", pSP->numSS); +#endif DEBUG return; } + +/* + * init_chan--Build the database channel structures. + * Note: Actual PV name is not filled in here. */ +LOCAL VOID init_chan(pSeqProg, pSP) +struct seqProgram *pSeqProg; +SPROG *pSP; +{ + int nchan; + CHAN *pDB; + struct seqChan *pSeqChan; + + /* Allocate space for the CHAN structures */ + pSP->pChan = (CHAN *)calloc(pSP->numChans, sizeof(CHAN)); + pDB = pSP->pChan; + + pSeqChan = pSeqProg->pChan; + for (nchan = 0; nchan < pSP->numChans; nchan++, pDB++, pSeqChan++) + { +#ifdef DEBUG + logMsg("init_chan: pDB=0x%x\n", pDB); +#endif DEBUG + pDB->sprog = pSP; + pDB->dbAsName = pSeqChan->dbAsName; + pDB->pVarName = pSeqChan->pVarName; + pDB->pVarType = pSeqChan->pVarType; + pDB->pVar = pSeqChan->pVar; /* this is an offset for +r option */ + pDB->count = pSeqChan->count; + pDB->efId = pSeqChan->efId; + pDB->monFlag = pSeqChan->monFlag; + pDB->eventNum = pSeqChan->eventNum; + pDB->assigned = 0; + + /* Fill in get/put database types, element size, & access offset */ + selectDBtype(pSeqChan->pVarType, &pDB->getType, + &pDB->putType, &pDB->size, &pDB->dbOffset); + + /* Reentrant option: Convert offset to address of the user variable. */ + if (pSP->options & OPT_REENT) + pDB->pVar += (int)pSP->pVar; +#ifdef DEBUG + logMsg(" Assigned Name=%s, VarName=%s, VarType=%s, count=%d\n", + pDB->dbAsName, pDB->pVarName, pDB->pVarType, pDB->count); + logMsg(" size=%d, dbOffset=%d\n", pDB->size, pDB->dbOffset); + logMsg(" efId=%d, monFlag=%d, eventNum=%d\n", + pDB->efId, pDB->monFlag, pDB->eventNum); +#endif DEBUG + } +} + +/* + * init_mac - initialize the macro table. + */ +LOCAL VOID init_mac(pSP) +SPROG *pSP; +{ + int i; + MACRO *pMac; + + pSP->pMacros = pMac = (MACRO *)calloc(MAX_MACROS, sizeof (MACRO)); +#ifdef DEBUG + logMsg("init_mac: pMac=0x%x\n", pMac); +#endif + + for (i = 0 ; i < MAX_MACROS; i++, pMac++) + { + pMac->pName = NULL; + pMac->pValue = NULL; + } +} /* * Evaluate channel names by macro substitution. */ @@ -391,36 +428,77 @@ SPROG *pSP; CHAN *pDB; int i; - pDB = pSP->channels; - for (i = 0; i < pSP->nchan; i++, pDB++) + pDB = pSP->pChan; + for (i = 0; i < pSP->numChans; i++, pDB++) { - pDB->db_name = seqAlloc(pSP, MACRO_STR_LEN); - seqMacEval(pDB->db_uname, pDB->db_name, MACRO_STR_LEN, pSP->mac_ptr); + pDB->dbName = calloc(1, MACRO_STR_LEN); + seqMacEval(pDB->dbAsName, pDB->dbName, MACRO_STR_LEN, pSP->pMacros); +#ifdef DEBUG + logMsg("seqChanNameEval: \"%s\" evaluated to \"%s\"\n", + pDB->dbAsName, pDB->dbName); +#endif DEBUG } } - -/* - * seqAlloc: Allocate memory from the program scratch area. - * Always round up to even no. bytes. + /* + * selectDBtype -- returns types for DB put/getm element size, and db access + * offset based on user variable type. + * Mapping is determined by the following typeMap[] array. + * DBR_TIME_* types for gets/monitors returns status and time stamp. + * Note that type "int" is mapped into DBR_LONG, because DBR_INT is actually + * 16 bits as defined in the database. This could cause future problems + * if the cpu architecture or compiler doesn't make this same assumption! */ -char *seqAlloc(pSP, nChar) -SPROG *pSP; -int nChar; -{ - char *pStr; +LOCAL struct typeMap { + char *pTypeStr; + short putType; + short getType; + short size; + short offset; +} typeMap[] = { + "char", DBR_CHAR, DBR_TIME_CHAR, + sizeof (char), OFFSET(struct dbr_time_char, value), - pStr = pSP->scr_ptr; - /* round to even no. bytes */ - if ((nChar & 1) != 0) - nChar++; - if (pSP->scr_nleft >= nChar) + "short", DBR_SHORT, DBR_TIME_SHORT, + sizeof (short), OFFSET(struct dbr_time_short, value), + + "int", DBR_LONG, DBR_TIME_LONG, + sizeof (long), OFFSET(struct dbr_time_long, value), + + "long", DBR_LONG, DBR_TIME_LONG, + sizeof (long), OFFSET(struct dbr_time_long, value), + + "float", DBR_FLOAT, DBR_TIME_FLOAT, + sizeof (float), OFFSET(struct dbr_time_float, value), + + "double", DBR_DOUBLE, DBR_TIME_DOUBLE, + sizeof (double), OFFSET(struct dbr_time_double, value), + + "string", DBR_STRING, DBR_TIME_STRING, + MAX_STRING_SIZE, OFFSET(struct dbr_time_string, value[0]), + + 0, 0, 0, 0, 0 +}; + +LOCAL VOID selectDBtype(pUserType, pGetType, pPutType, pSize, pOffset) +char *pUserType; +short *pGetType, *pPutType, *pSize, *pOffset; +{ + struct typeMap *pMap; + + for (pMap = &typeMap[0]; *pMap->pTypeStr != 0; pMap++) { - pSP->scr_ptr += nChar; - pSP->scr_nleft -= nChar; - return pStr; + if (strcmp(pUserType, pMap->pTypeStr) == 0) + { + *pGetType = pMap->getType; + *pPutType = pMap->putType; + *pSize = pMap->size; + *pOffset = pMap->offset; + return; + } } - else - return NULL; + *pGetType = *pPutType = *pSize = *pOffset = 0; /* this shouldn't happen */ + + return; } /* * seq_logInit() - Initialize logging. @@ -429,7 +507,7 @@ int nChar; LOCAL VOID seq_logInit(pSP) SPROG *pSP; { - char *pname, *pvalue; + char *pValue; int fd; /* Create a logging resource locking semaphore */ @@ -442,26 +520,25 @@ SPROG *pSP; pSP->logFd = ioGlobalStdGet(1); /* default fd is std out */ /* Check for logfile spec. */ - pname = "logfile"; - pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr); - if (pvalue != NULL && strlen(pvalue) > 0) + pValue = seqMacValGet(pSP->pMacros, "logfile"); + if (pValue != NULL && strlen(pValue) > 0) { /* Create & open a new log file for write only */ - remove(pvalue); /* remove the file if it exists */ - fd = open(pvalue, O_CREAT | O_WRONLY, 0664); + remove(pValue); /* remove the file if it exists */ + fd = open(pValue, O_CREAT | O_WRONLY, 0664); if (fd != ERROR) pSP->logFd = fd; - printf("logfile=%s, fd=%d\n", pvalue, fd); + printf("logfile=%s, fd=%d\n", pValue, fd); } } /* * seq_log - * Log a message to the console or a file with time of day and task id. - * The format looks like "mytask 12/13/91 10:07:43: ". + * Log a message to the console or a file with task name, date, & time of day. + * The format looks like "mytask 12/13/93 10:07:43: Hello world!". */ #include "tsDefs.h" #define LOG_BFR_SIZE 200 -VOID seq_log(pSP, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +STATUS seq_log(pSP, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) SPROG *pSP; char *fmt; /* format string */ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ @@ -481,7 +558,7 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ /* Convert to text format: "mm/dd/yy hh:mm:ss.nano-sec" */ tsStampToText(&timeStamp, TS_TEXT_MMDDYY, pBfr); - /* We're going to truncate the ".nano-sec" part */ + /* Truncate the ".nano-sec" part */ if (pBfr[2] == '/') /* valid t-s? */ pBfr += 17; @@ -498,11 +575,13 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ fd = pSP->logFd; count = pBfr - logBfr + 1; status = write(fd, logBfr, count); + + semGive(pSP->logSemId); if (status != count) { logMsg("Log file error, fd=%d, error no.=%d\n", fd, errnoGet()); printErrno(errnoGet()); - return; + return ERROR; } /* If this is an NSF file flush the buffer */ @@ -510,41 +589,19 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ { ioctl(fd, FIOSYNC, 0); } - semGive(pSP->logSemId); - return; -} - /* - * seqLog() - State program interface to seq_log(). - * Does not require ptr to state program block. - */ -STATUS seqLog(fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8) -char *fmt; /* format string */ -int arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ -{ - SPROG *pSP, *seqFindProg(); - - pSP = seqFindProg(taskIdSelf()); - if (pSP == NULL) - return ERROR; - - seq_log(pSP, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8); return OK; } /* - * seq_optGet: return the value of an option. - * FALSE means "-" and TRUE means "+". + * seq_seqLog() - State program interface to seq_log(). + * Does not require ptr to state program block. */ -BOOL seq_optGet(pSP, opt) -SPROG *pSP; -char *opt; /* one of the snc options as a strign (e.g. "a") */ +STATUS seq_seqLog(ssId, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8) +SS_ID ssId; +char *fmt; /* format string */ +int arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */ { - switch (opt[0]) - { - case 'a': return ( (pSP->options & OPT_ASYNC) != 0); - case 'c': return ( (pSP->options & OPT_CONN) != 0); - case 'd': return ( (pSP->options & OPT_DEBUG) != 0); - case 'r': return ( (pSP->options & OPT_REENT) != 0); - case 'e': return ( (pSP->options & OPT_NEWEF) != 0); - default: return FALSE; - } + SPROG *pSP; + + pSP = ((SSCB *)ssId)->sprog; + return seq_log(pSP, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8); } diff --git a/src/sequencer/seq_prog.c b/src/sequencer/seq_prog.c index 56e9cfdc5..65c74e329 100644 --- a/src/sequencer/seq_prog.c +++ b/src/sequencer/seq_prog.c @@ -2,8 +2,9 @@ GTA PROJECT AT division Copyright, 1991, The Regents of the University of California. Los Alamos National Laboratory + seq_prog.c,v 1.2 1995/06/27 15:26:00 wright Exp + - $Id$ DESCRIPTION: Seq_prog.c: state program list management functions. All active state programs are inserted into the list when created and removed from the list when deleted. @@ -15,37 +16,38 @@ 29apr92,ajk Added mutual exclusion locks 17Jul92,rcz Changed semBCreate call for V5 vxWorks, maybe should be semMCreate ??? ***************************************************************************/ -#define DEBUG +/*#define DEBUG*/ #define ANSI #include "seq.h" +#include "lstLib.h" LOCAL SEM_ID seqProgListSemId; LOCAL int seqProgListInited = FALSE; -LOCAL ELLLIST seqProgList; +LOCAL LIST seqProgList; LOCAL VOID seqProgListInit(); typedef struct prog_node { - ELLNODE node; + NODE node; SPROG *pSP; } PROG_NODE; -#define seqListFirst(pList) (PROG_NODE *)ellFirst((ELLLIST *)pList) +#define seqListFirst(pList) (PROG_NODE *)lstFirst((LIST *)pList) -#define seqListNext(pNode) (PROG_NODE *)ellNext((ELLNODE *)pNode) +#define seqListNext(pNode) (PROG_NODE *)lstNext((NODE *)pNode) /* * seqFindProg() - find a program in the state program list from task id. */ -SPROG *seqFindProg(task_id) -int task_id; +SPROG *seqFindProg(taskId) +int taskId; { PROG_NODE *pNode; SPROG *pSP; SSCB *pSS; int n; - if (!seqProgListInited || task_id == 0) + if (!seqProgListInited || taskId == 0) return NULL; semTake(seqProgListSemId, WAIT_FOREVER); @@ -54,15 +56,15 @@ int task_id; pNode = seqListNext(pNode) ) { pSP = pNode->pSP; - if (pSP->task_id == task_id) + if (pSP->taskId == taskId) { semGive(seqProgListSemId); return pSP; } - pSS = pSP->sscb; - for (n = 0; n < pSP->nss; n++, pSS++) + pSS = pSP->pSS; + for (n = 0; n < pSP->numSS; n++, pSS++) { - if (pSS->task_id == task_id) + if (pSS->taskId == taskId) { semGive(seqProgListSemId); return pSP; @@ -122,7 +124,7 @@ SPROG *pSP; { semGive(seqProgListSemId); #ifdef DEBUG - printf("Task %d already in list\n", pSP->task_id); + printf("Task %d already in list\n", pSP->taskId); #endif return ERROR; /* already in list */ } @@ -137,10 +139,10 @@ SPROG *pSP; } pNode->pSP = pSP; - ellAdd((ELLLIST *)&seqProgList, (ELLNODE *)pNode); + lstAdd((LIST *)&seqProgList, (NODE *)pNode); semGive(seqProgListSemId); #ifdef DEBUG - printf("Added task %d to list.\n", pSP->task_id); + printf("Added task %d to list.\n", pSP->taskId); #endif return OK; @@ -164,11 +166,11 @@ SPROG *pSP; { if (pNode->pSP == pSP) { - ellDelete((ELLLIST *)&seqProgList, (ELLNODE *)pNode); + lstDelete((LIST *)&seqProgList, (NODE *)pNode); semGive(seqProgListSemId); #ifdef DEBUG - printf("Deleted task %d from list.\n", pSP->task_id); + printf("Deleted task %d from list.\n", pSP->taskId); #endif return OK; } @@ -184,7 +186,7 @@ SPROG *pSP; LOCAL VOID seqProgListInit() { /* Init linked list */ - ellInit(&seqProgList); + lstInit(&seqProgList); /* Create a semaphore for mutual exclusion */ seqProgListSemId = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); diff --git a/src/sequencer/seq_qry.c b/src/sequencer/seq_qry.c index a5a43837d..6828865c4 100644 --- a/src/sequencer/seq_qry.c +++ b/src/sequencer/seq_qry.c @@ -1,9 +1,9 @@ /************************************************************************** GTA PROJECT AT division - Copyright, 1990, The Regents of the University of California. + Copyright, 1990-1994, The Regents of the University of California. Los Alamos National Laboratory + seq_qry.c,v 1.2 1995/06/27 15:26:02 wright Exp - $Id$ DESCRIPTION: Task querry & debug routines for run-time sequencer: seqShow - prints state set info. seqChanShow - printf channel (pv) info. @@ -21,17 +21,17 @@ 29apr92,ajk Modified to interpret encoded options. 21may92,ajk Modified format for listing programs & tasks. 21feb93,ajk Some minor code cleanup. +01mar94,ajk Major changes to print more meaningful information. ***************************************************************************/ -/* #define DEBUG 1 */ +/*#define DEBUG 1*/ #include "seq.h" int seqShow(int); -int seqChanShow(int); -LOCAL VOID wait_rtn(); -LOCAL VOID printValue(void *, int, int, int); -LOCAL VOID printType(int); +int seqChanShow(int, char *); +LOCAL int wait_rtn(); +LOCAL VOID printValue(char *, int, int); LOCAL SPROG *seqQryFind(int); LOCAL seqShowAll(); @@ -53,32 +53,27 @@ int tid; /* convert (possible) name to task id */ if (tid != 0) + { tid = taskIdFigure(tid); + if (tid == ERROR) + return 0; + } pSP = seqQryFind(tid); if (pSP == NULL) return 0; /* Print info about state program */ - printf("State Program: \"%s\"\n", pSP->name); - printf(" Memory layout:\n"); - printf("\tpSP=%d=0x%x\n", pSP, pSP); - printf("\tdyn_ptr=%d=0x%x\n", pSP->dyn_ptr, pSP->dyn_ptr); - printf("\tsscb=%d=0x%x\n", pSP->sscb, pSP->sscb); - printf("\tstates=%d=0x%x\n", pSP->states, pSP->states); - printf("\tuser_area=%d=0x%x\n", pSP->user_area, pSP->user_area); - printf("\tuser_size=%d=0x%x\n", pSP->user_size, pSP->user_size); - printf("\tmac_ptr=%d=0x%x\n", pSP->mac_ptr, pSP->mac_ptr); - printf("\tscr_ptr=%d=0x%x\n", pSP->scr_ptr, pSP->scr_ptr); - printf("\tscr_nleft=%d=0x%x\n\n", pSP->scr_nleft, pSP->scr_nleft); - printf(" initial task id=%d=0x%x\n", pSP->task_id, pSP->task_id); - printf(" task priority=%d\n", pSP->task_priority); - printf(" number of state sets=%d\n", pSP->nss); - printf(" number of channels=%d\n", pSP->nchan); - printf(" number of channels connected=%d\n", pSP->conn_count); - printf(" options: async=%d, debug=%d, reent=%d, conn=%d, newef=%d\n", + printf("State Program: \"%s\"\n", pSP->pProgName); + printf(" initial task id=%d=0x%x\n", pSP->taskId, pSP->taskId); + printf(" task priority=%d\n", pSP->taskPriority); + printf(" number of state sets=%d\n", pSP->numSS); + printf(" number of channels=%d\n", pSP->numChans); + printf(" number of channels assigned=%d\n", pSP->assignCount); + printf(" number of channels connected=%d\n", pSP->connCount); + printf(" options: async=%d, debug=%d, newef=%d, reent=%d, conn=%d\n", ((pSP->options & OPT_ASYNC) != 0), ((pSP->options & OPT_DEBUG) != 0), - ((pSP->options & OPT_REENT) != 0), ((pSP->options & OPT_CONN) != 0), - ((pSP->options & OPT_NEWEF) != 0) ); + ((pSP->options & OPT_NEWEF) != 0), ((pSP->options & OPT_REENT) != 0), + ((pSP->options & OPT_CONN) != 0) ); printf(" log file fd=%d\n", pSP->logFd); status = ioctl(pSP->logFd, FIOGETNAME, (int)file_name); if (status != ERROR) @@ -87,88 +82,129 @@ int tid; printf("\n"); /* Print state set info */ - for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++) + for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++) { - wait_rtn(); + printf(" State Set: \"%s\"\n", pSS->pSSName); - printf(" State Set: \"%s\"\n", pSS->name); + printf(" task name=%s; ", taskName(pSS->taskId)); - printf(" task name=%s; ", taskName(pSS->task_id)); + printf(" task id=%d=0x%x\n", pSS->taskId, pSS->taskId); - printf(" id=%d=0x%x\n", pSS->task_id, pSS->task_id); + pST = pSS->pStates; + printf(" First state = \"%s\"\n", pST->pStateName); - pST = pSS->states; - printf(" First state = \"%s\"\n", pSS->states->name); + pST = pSS->pStates + pSS->currentState; + printf(" Current state = \"%s\"\n", pST->pStateName); - pST = pSS->states + pSS->current_state; - printf(" Current state = \"%s\"\n", pST->name); + pST = pSS->pStates + pSS->prevState; + printf(" Previous state = \"%s\"\n", pST->pStateName); - pST = pSS->states + pSS->prev_state; - printf(" Previous state = \"%s\"\n", pST->name); - - time = pSS->time/60.0; - printf("\tTime state was entered = %.1f seconds)\n", time); - time = (tickGet() - pSS->time)/60.0; + time = (tickGet() - pSS->timeEntered)/60.0; printf("\tElapsed time since state was entered = %.1f seconds)\n", time); - - printf("\tNumber delays queued=%d\n", pSS->ndelay); - for (n = 0; n < pSS->ndelay; n++) +#ifdef DEBUG + printf(" Queued time delays:\n"); + for (n = 0; n < pSS->numDelays; n++) { - time = pSS->timeout[n]/60.0; - printf("\t\ttimeout[%d] = %.1f seconds\n", n, time); + printf("\tdelay[%2d]=%d", n, pSS->delay[n]); + if (pSS->delayExpired[n]) + printf(" - expired"); + printf("\n"); } +#endif DEBUG + printf("\n"); } return 0; } /* - * seqChanQry() - Querry the sequencer for channel information. + * seqChanShow() - Show channel information for a state program. */ -int seqChanShow(tid) -int tid; +int seqChanShow(tid, pStr) +int tid; /* task id or name */ +char *pStr; /* optional pattern matching string */ { SPROG *pSP; CHAN *pDB; - int nch; + int nch, n; float time; + char tsBfr[50], connQual; + int match, showAll; /* convert (possible) name to task id */ if (tid != 0) + { tid = taskIdFigure(tid); + if (tid == ERROR) + return 0; + } pSP = seqQryFind(tid); if (tid == NULL) return 0; - pDB = pSP->channels; - printf("State Program: \"%s\"\n", pSP->name); - printf("Number of channels=%d\n", pSP->nchan); + printf("State Program: \"%s\"\n", pSP->pProgName); + printf("Number of channels=%d\n", pSP->numChans); - for (nch = 0; nch < pSP->nchan; nch++, pDB++) + if (pStr != NULL) { - printf("\nChannel name: \"%s\"\n", pDB->db_name); - printf(" Unexpanded name: \"%s\"\n", pDB->db_uname); - printf(" Variable=%d=0x%x\n", pDB->var, pDB->var); - printf(" Size=%d bytes\n", pDB->size); - printf(" Count=%d\n", pDB->count); - printType(pDB->put_type); - printValue((void *)pDB->var, pDB->size, pDB->count, - pDB->put_type); - printf(" DB get request type=%d\n", pDB->get_type); - printf(" DB put request type=%d\n", pDB->put_type); - printf(" monitor flag=%d\n", pDB->mon_flag); + connQual = pStr[0]; + /* Check for channel connect qualifier */ + if ((connQual == '+') || (connQual == '-')) + { + pStr += 1; + } + } + else + connQual = 0; + + pDB = pSP->pChan; + for (nch = 0; nch < pSP->numChans; ) + { + if (pStr != NULL) + { + /* Check for channel connect qualifier */ + if (connQual == '+') + showAll = pDB->connected; /* TRUE if connected */ + else if (connQual == '-') + showAll = !pDB->connected; /* TRUE if NOT connected */ + else + showAll = TRUE; /* Always TRUE */ + + /* Check for pattern match if specified */ + match = (pStr[0] == 0) || (strstr(pDB->dbName, pStr) != NULL); + if (!(match && showAll)) + { + pDB += 1; + nch += 1; + continue; /* skip this channel */ + } + } + printf("\n#%d of %d:\n", nch+1, pSP->numChans); + printf("Channel name: \"%s\"\n", pDB->dbName); + printf(" Unexpanded (assigned) name: \"%s\"\n", pDB->dbAsName); + printf(" Variable name: \"%s\"\n", pDB->pVarName); + printf(" address = %d = 0x%x\n", pDB->pVar, pDB->pVar); + printf(" type = %s\n", pDB->pVarType); + printf(" count = %d\n", pDB->count); + printValue(pDB->pVar, pDB->putType, pDB->count); + printf(" Monitor flag=%d\n", pDB->monFlag); if (pDB->monitored) - printf(" Monitored\n"); + printf(" Monitored\n"); else - printf(" Not monitored\n"); + printf(" Not monitored\n"); + + if (pDB->assigned) + printf(" Assigned\n"); + else + printf(" Not assigned\n"); if(pDB->connected) printf(" Connected\n"); else printf(" Not connected\n"); - if(pDB->get_complete) + if(pDB->getComplete) printf(" Last get completed\n"); else printf(" Get not completed or no get issued\n"); @@ -176,118 +212,117 @@ int tid; printf(" Status=%d\n", pDB->status); printf(" Severity=%d\n", pDB->severity); - printf(" Delta=%g\n", pDB->delta); - printf(" Timeout=%g\n", pDB->timeout); - wait_rtn(); + /* Print time stamp in text format: "mm/dd/yy hh:mm:ss.nano-sec" */ + tsStampToText(&pDB->timeStamp, TS_TEXT_MMDDYY, tsBfr); + if (tsBfr[2] == '/') /* valid t-s? */ + printf(" Time stamp = %s\n", tsBfr); + + n = wait_rtn(); + if (n == 0) + return 0; + nch += n; + if (nch < 0) + nch = 0; + pDB = pSP->pChan + nch; } return 0; } /* Read from console until a RETURN is detected */ -LOCAL VOID wait_rtn() +LOCAL int wait_rtn() { - char bfr; - printf("Hit RETURN to continue\n"); - do { - read(STD_IN, &bfr, 1); - } while (bfr != '\n'); + char bfr[10]; + int i, n; + + printf("Next? (+/- skip count)\n"); + for (i = 0; i < 10; i++) + { + read(STD_IN, &bfr[i], 1); + if (bfr[i] == '\n') + break; + } + bfr[i] = 0; + if (bfr[0] == 'q') + return 0; /* quit */ + + n = atoi(bfr); + if (n == 0) + n = 1; + return n; } -/* Special union to simplify printing values */ -struct dbr_union { - union { - char c; - short s; - long l; - float f; - double d; - } u; -}; - /* Print the current internal value of a database channel */ -LOCAL VOID printValue(pvar, size, count, type) -void *pvar; -int size, count, type; +LOCAL VOID printValue(pVal, type, count) +char *pVal; +int count, type; { - struct dbr_union *pv = pvar; + int i; + char *c; + short *s; + long *l; + float *f; + double *d; if (count > 5) count = 5; printf(" Value ="); - while (count-- > 0) - { - switch (type) - { - case DBR_STRING: - printf(" %s", pv->u.c); - break; - - case DBR_CHAR: - printf(" %d", pv->u.c); - break; - - case DBR_SHORT: - printf(" %d", pv->u.s); - break; - - case DBR_LONG: - printf(" %d", pv->u.l); - break; - - case DBR_FLOAT: - printf(" %g", pv->u.f); - break; - - case DBR_DOUBLE: - printf(" %lg", pv->u.d); - break; - } - - pv = (struct dbr_union *)((char *)pv + size); - } - - printf("\n"); -} - -/* Print the data type of a channel */ -LOCAL VOID printType(type) -int type; -{ - char *type_str; - - switch (type) + for (i = 0; i < count; i++) { + switch (type) + { case DBR_STRING: - type_str = "string"; + c = (char *)pVal; + for (i = 0; i < count; i++, c += MAX_STRING_SIZE) + { + printf(" %s", c); + } break; - case DBR_CHAR: - type_str = "char"; + case DBR_CHAR: + c = (char *)pVal; + for (i = 0; i < count; i++, c++) + { + printf(" %d", *c); + } break; case DBR_SHORT: - type_str = "short"; + s = (short *)pVal; + for (i = 0; i < count; i++, s++) + { + printf(" %d", *s); + } break; case DBR_LONG: - type_str = "long"; + l = (long *)pVal; + for (i = 0; i < count; i++, l++) + { + printf(" %d", *l); + } break; case DBR_FLOAT: - type_str = "float"; + f = (float *)pVal; + for (i = 0; i < count; i++, f++) + { + printf(" %g", *f); + } break; case DBR_DOUBLE: - type_str = "double"; - break; - - default: - type_str = "?"; + d = (double *)pVal; + for (i = 0; i < count; i++, d++) + { + printf(" %g", *d); + } break; + } } - printf(" Type = %s\n", type_str); + + printf("\n"); } /* Find a state program associated with a given task id */ @@ -311,13 +346,6 @@ int tid; return NULL; } - /* Check for correct magic number */ - if (pSP->magic != MAGIC) - { - printf("Sorry, wrong magic number\n"); - return NULL; - } - return pSP; } @@ -334,15 +362,15 @@ SPROG *pSP; if (seqProgCount++ == 0) printf("Program Name Task ID Task Name SS Name\n\n"); - progName = pSP->name; - for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++) + progName = pSP->pProgName; + for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++) { - if (pSS->task_id == 0) + if (pSS->taskId == 0) ptaskName = "(no task)"; else - ptaskName = taskName(pSS->task_id); + ptaskName = taskName(pSS->taskId); printf("%-16s %-10d %-16s %-16s\n", - progName, pSS->task_id, ptaskName, pSS->name ); + progName, pSS->taskId, ptaskName, pSS->pSSName ); progName = ""; } printf("\n"); diff --git a/src/sequencer/seq_task.c b/src/sequencer/seq_task.c index 118408450..42eba06a2 100644 --- a/src/sequencer/seq_task.c +++ b/src/sequencer/seq_task.c @@ -1,10 +1,11 @@ /************************************************************************** GTA PROJECT AT division - Copyright, 1990, 1991, 1992 - The Regents of the University of California + Copyright, 1990-1994 + The Regents of the University of California and + the University of Chicago. Los Alamos National Laboratory + seq_task.c,v 1.3 1995/10/19 16:30:18 wright Exp - $Id$ DESCRIPTION: Seq_tasks.c: Task creation and control for sequencer state sets. @@ -20,14 +21,21 @@ Some minor changes in the way semaphores are deleted. 18feb92,ajk Changed to allow sharing of single CA task by all state programs. Added seqAuxTask() and removed ca_pend_event() from ss_entry(). -9aug93,ajk Added calls to taskwdInsert() & taskwdRemove(). +09aug93,ajk Added calls to taskwdInsert() & taskwdRemove(). +24nov93,ajk Added support for assigning array elements to db channels. +24nov93,ajk Changed implementation of event bits to support unlimited channels +20may94,ajk Changed sprog_delete() to spawn a separate cleanup task. +19oct95,ajk/rmw Fixed bug which kept events from being cleared in old eventflag mode ***************************************************************************/ +/*#define DEBUG*/ #define ANSI +#include "seqCom.h" #include "seq.h" #include /* Function declarations */ LOCAL VOID ss_task_init(SPROG *, SSCB *); +LOCAL VOID seq_clearDelay(SSCB *); LOCAL long seq_getTimeout(SSCB *); #define TASK_NAME_SIZE 10 @@ -37,10 +45,10 @@ LOCAL long seq_getTimeout(SSCB *); /* * sequencer() - Sequencer main task entry point. * */ -sequencer(pSP, stack_size, ptask_name) +sequencer(pSP, stack_size, pTaskName) SPROG *pSP; /* ptr to original (global) state program table */ int stack_size; /* stack size */ -char *ptask_name; /* Parent task name */ +char *pTaskName; /* Parent task name */ { SSCB *pSS; STATE *pST; @@ -49,9 +57,9 @@ char *ptask_name; /* Parent task name */ extern VOID ss_entry(); extern int seqAuxTaskId; - pSP->task_id = taskIdSelf(); /* my task id */ - pSS = pSP->sscb; - pSS->task_id = pSP->task_id; + pSP->taskId = taskIdSelf(); /* my task id */ + pSS = pSP->pSS; + pSS->taskId = pSP->taskId; /* Add the program to the state program list */ seqAddProg(pSP); @@ -63,19 +71,19 @@ char *ptask_name; /* Parent task name */ seq_connect(pSP); /* Additional state set task names are derived from the first ss */ - if (strlen(ptask_name) > TASK_NAME_SIZE) - ptask_name[TASK_NAME_SIZE] = 0; + if (strlen(pTaskName) > TASK_NAME_SIZE) + pTaskName[TASK_NAME_SIZE] = 0; /* Create each additional state set task */ - for (nss = 1, pSS = pSP->sscb + 1; nss < pSP->nss; nss++, pSS++) + for (nss = 1, pSS = pSP->pSS + 1; nss < pSP->numSS; nss++, pSS++) { /* Form task name from program name + state set number */ - sprintf(task_name, "%s_%d", ptask_name, nss); + sprintf(task_name, "%s_%d", pTaskName, nss); /* Spawn the task */ task_id = taskSpawn( task_name, /* task name */ - SPAWN_PRIORITY+pSS->task_priority, /* priority */ + SPAWN_PRIORITY+pSS->taskPriority, /* priority */ SPAWN_OPTIONS, /* task options */ stack_size, /* stack size */ (FUNCPTR)ss_entry, /* entry point */ @@ -85,7 +93,7 @@ char *ptask_name; /* Parent task name */ } /* First state set jumps directly to entry point */ - ss_entry(pSP, pSP->sscb); + ss_entry(pSP, pSP->pSS); } /* * ss_entry() - Task entry point for all state sets. @@ -100,6 +108,8 @@ SSCB *pSS; long delay; char *pVar; LOCAL VOID seq_waitConnect(); + int nWords; + SS_ID ssId; /* Initialize all ss tasks */ ss_task_init(pSP, pSS); @@ -109,29 +119,29 @@ SSCB *pSS; seq_waitConnect(pSP, pSS); /* Initilaize state set to enter the first state */ - pST = pSS->states; - pSS->current_state = 0; + pST = pSS->pStates; + pSS->currentState = 0; /* Use the event mask for this state */ - pSS->pMask = (pST->eventMask); + pSS->pMask = (pST->pEventMask); + nWords = (pSP->numEvents + NBITS - 1) / NBITS; /* Local ptr to user variables (for reentrant code only) */ - pVar = pSP->user_area; + pVar = pSP->pVar; + + /* State set id */ + ssId = (SS_ID)pSS; /* * ============= Main loop ============== */ while (1) { - pSS->time = tickGet(); /* record time we entered this state */ + seq_clearDelay(pSS); /* Clear delay list */ + pST->delayFunc(ssId, pVar); /* Set up new delay list */ - /* Call delay function to set up delays */ - pSS->ndelay = 0; - pST->delay_func(pSP, pSS, pVar); - - /* Generate a phoney event. - * This guarantees that a when() is always executed at - * least once when a state is entered. */ + /* Setting this semaphor here guarantees that a when() is always + * executed at least once when a state is first entered. */ semGive(pSS->syncSemId); /* @@ -139,7 +149,7 @@ SSCB *pSS; */ do { /* Wake up on CA event, event flag, or expired time delay */ - delay = seq_getTimeout(pSS); + delay = seq_getTimeout(pSS); /* min. delay from list */ if (delay > 0) semTake(pSS->syncSemId, delay); @@ -149,38 +159,43 @@ SSCB *pSS; */ semTake(pSP->caSemId, WAIT_FOREVER); - ev_trig = pST->event_func(pSP, pSS, pVar); /* check events */ + ev_trig = pST->eventFunc(ssId, pVar, + &pSS->transNum, &pSS->nextState); /* check events */ - if ( ev_trig && (pSP->options & OPT_NEWEF) == 0 ) + /* Clear all event flags (old ef mode only) */ + if ( ev_trig && ((pSP->options & OPT_NEWEF) == 0) ) { /* Clear all event flags (old mode only) */ register int i; - for (i = 0; i < NWRDS; i++) - pSP->events[i] = pSP->events[i] & !pSS->pMask[i]; + + for (i = 0; i < nWords; i++) + pSP->pEvents[i] = pSP->pEvents[i] & !pSS->pMask[i]; + } + semGive(pSP->caSemId); } while (!ev_trig); + + /* * An event triggered: * execute the action statements and enter the new state. */ /* Change event mask ptr for next state */ - pStNext = pSS->states + pSS->next_state; - pSS->pMask = (pStNext->eventMask); + pStNext = pSS->pStates + pSS->nextState; + pSS->pMask = (pStNext->pEventMask); /* Execute the action for this event */ - pSS->action_complete = FALSE; - pST->action_func(pSP, pSS, pVar); + pST->actionFunc(ssId, pVar, pSS->transNum); /* Flush any outstanding DB requests */ ca_flush_io(); /* Change to next state */ - pSS->prev_state = pSS->current_state; - pSS->current_state = pSS->next_state; - pST = pSS->states + pSS->current_state; - pSS->action_complete = TRUE; + pSS->prevState = pSS->currentState; + pSS->currentState = pSS->nextState; + pST = pSS->pStates + pSS->currentState; } } /* Initialize state-set tasks */ @@ -191,14 +206,14 @@ SSCB *pSS; extern int seqAuxTaskId; /* Get this task's id */ - pSS->task_id = taskIdSelf(); + pSS->taskId = taskIdSelf(); /* Import Channel Access context from the auxillary seq. task */ - if (pSP->task_id != pSS->task_id) + if (pSP->taskId != pSS->taskId) ca_import(seqAuxTaskId); /* Register this task with the EPICS watchdog (no callback function) */ - taskwdInsert(pSS->task_id, (VOIDFUNCPTR)0, (VOID *)0); + taskwdInsert(pSS->taskId, (VOIDFUNCPTR)0, (VOID *)0); return; } @@ -212,94 +227,82 @@ SSCB *pSS; long delay; delay = 600; /* 10, 20, 30, 40, 40,... sec */ - while (pSP->conn_count < pSP->nchan) + while (pSP->connCount < pSP->assignCount) { status = semTake(pSS->syncSemId, delay); - if ((status != OK) && (pSP-> task_id == pSS->task_id)) + if ((status != OK) && (pSP-> taskId == pSS->taskId)) { - logMsg("%d of %d channels connected\n", - pSP->conn_count, pSP->nchan); + logMsg("%d of %d assigned channels have connected\n", + pSP->connCount, pSP->assignCount); } if (delay < 2400) delay = delay + 600; } } - /* + * seq_clearDelay() - clear the time delay list. + */ +LOCAL VOID seq_clearDelay(pSS) +SSCB *pSS; +{ + int ndelay; + + pSS->timeEntered = tickGet(); /* record time we entered this state */ + + for (ndelay = 0; ndelay < MAX_NDELAY; ndelay++) + { + pSS->delay[ndelay] = 0; + pSS->delayExpired[ndelay] = FALSE; + } + + pSS->numDelays = 0; + + return; +} + +/* * seq_getTimeout() - return time-out for pending on events. * Returns number of tics to next expected timeout of a delay() call. * Returns MAX_DELAY if no delays pending */ LOCAL long seq_getTimeout(pSS) -SSCB *pSS; +SSCB *pSS; { int ndelay; - long timeout; /* expiration clock time (tics) */ - long delay, delayMin; /* remaining & min. delay (tics) */ + long delay, delayMin, delayN; - if (pSS->ndelay == 0) + if (pSS->numDelays == 0) return MAX_DELAY; + delay = tickGet() - pSS->timeEntered; /* actual delay since state entered */ + delayMin = MAX_DELAY; /* start with largest possible delay */ /* Find the minimum delay among all non-expired timeouts */ - for (ndelay = 0; ndelay < pSS->ndelay; ndelay++) + for (ndelay = 0; ndelay < pSS->numDelays; ndelay++) { - timeout = pSS->timeout[ndelay]; - if (timeout == 0) - continue; /* already expired */ - delay = timeout - tickGet(); /* convert timeout to remaining delay */ - if (delay <= 0) + if (pSS->delayExpired[ndelay]) + continue; /* skip if this delay entry already expired */ + + delayN = pSS->delay[ndelay]; + if (delay >= delayN) { /* just expired */ - delayMin = 0; - pSS->timeout[ndelay] = 0; /* mark as expired */ + pSS->delayExpired[ndelay] = TRUE; /* mark as expired */ + return 0; } - else if (delay < delayMin) + else if (delayN < delayMin) { - delayMin = delay; /* this is the min. delay so far */ + delayMin = delayN; /* this is the min. delay so far */ } } + delay = delayMin - delay; + if (delay < 0) + delay = 0; - return delayMin; -} - /* Set-up for delay() on entering a state. This routine is called -by the state program for each delay in the "when" statement */ -VOID seq_start_delay(pSP, pSS, delay_id, delay) -SPROG *pSP; -SSCB *pSS; -int delay_id; /* delay id */ -float delay; -{ - int td_tics; - - /* Note: the following 2 lines could be combined, but doing so produces - * the undefined symbol "Mund", which is not in VxWorks library */ - td_tics = delay*60.0; - pSS->timeout[delay_id] = pSS->time + td_tics; - delay_id += 1; - if (delay_id > pSS->ndelay) - pSS->ndelay = delay_id; - return; -} - -/* Test for time-out expired */ -BOOL seq_test_delay(pSP, pSS, delay_id) -SPROG *pSP; -SSCB *pSS; -int delay_id; -{ - if (pSS->timeout[delay_id] == 0) - return TRUE; /* previously expired t-o */ - - if (tickGet() >= pSS->timeout[delay_id]) - { - pSS->timeout[delay_id] = 0; /* mark as expired */ - return TRUE; - } - return FALSE; + return delay; } /* * Delete all state set tasks and do general clean-up. - * General procedure is: + * General procedure is to spawn a task that does the following: * 1. Suspend all state set tasks except self. * 2. Call the user program's exit routine. * 3. Disconnect all channels for this state program. @@ -310,27 +313,46 @@ int delay_id; * * This task is run whenever ANY task in the system is deleted. * Therefore, we have to check the task belongs to a state program. + * Note: We could do this without spawning a task, except for the condition + * when executed in the context of ExcTask. ExcTask is not spawned with + * floating point option, and fp is required to do the cleanup. */ sprog_delete(tid) -int tid; +int tid; /* task being deleted */ { - int nss, tid_ss; - SPROG *pSP, *seqFindProg(); - SSCB *pSS; - + SPROG *pSP; + extern int seq_cleanup(); + SEM_ID cleanupSem; + pSP = seqFindProg(tid); if (pSP == NULL) return -1; /* not a state program task */ - logMsg("Delete %s: pSP=%d=0x%x, tid=%d\n", - pSP->name, pSP, pSP, tid); + /* Create a semaphore for cleanup task */ + cleanupSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY); - /* Is this a real sequencer task? */ - if (pSP->magic != MAGIC) - { - logMsg(" Not main state program task\n"); - return -1; - } + /* Spawn the cleanup task */ + taskSpawn("seqCleanup", SPAWN_PRIORITY-1, VX_FP_TASK, 2000, seq_cleanup, + tid, (int)pSP, (int)cleanupSem, 0,0,0,0,0,0,0); + + /* Wait for cleanup task completion */ + semTake(cleanupSem, WAIT_FOREVER); + semDelete(cleanupSem); + + return 0; +} + +/* Cleanup task */ +seq_cleanup(tid, pSP, cleanupSem) +int tid; +SPROG *pSP; +SEM_ID cleanupSem; /* indicate cleanup is finished */ +{ + int nss, tid_ss; + SSCB *pSS; + + logMsg("Delete %s: pSP=%d=0x%x, tid=%d\n", + pSP->pProgName, pSP, pSP, tid); /* Wait for log semaphore (in case a task is doing a write) */ semTake(pSP->logSemId, 600); @@ -338,20 +360,20 @@ int tid; /* Remove tasks' watchdog & suspend all state set tasks except self */ #ifdef DEBUG logMsg(" Suspending state set tasks:\n"); -#endif /*DEBUG */ - pSS = pSP->sscb; - for (nss = 0; nss < pSP->nss; nss++, pSS++) +#endif DEBUG + pSS = pSP->pSS; + for (nss = 0; nss < pSP->numSS; nss++, pSS++) { - tid_ss = pSS->task_id; + tid_ss = pSS->taskId; /* Remove the task from EPICS watchdog */ taskwdRemove(tid_ss); - if ( (tid_ss != 0) && (tid != tid_ss) ) + if (tid_ss != taskIdSelf() ) { #ifdef DEBUG logMsg(" suspend task: tid=%d\n", tid_ss); -#endif /*DEBUG */ +#endif DEBUG taskSuspend(tid_ss); } } @@ -360,21 +382,21 @@ int tid; semGive(pSP->logSemId); /* Call user exit routine (only if task has run) */ - if (pSP->sscb->task_id != 0) + if (pSP->pSS->taskId != 0) { #ifdef DEBUG logMsg(" Call exit function\n"); -#endif /*DEBUG */ - pSP->exit_func(pSP, pSP->user_area); +#endif DEBUG + pSP->exitFunc( (SS_ID)pSP->pSS, pSP->pVar); } /* Disconnect all channels */ seq_disconnect(pSP); /* Cancel the CA context for each state set task */ - for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++) + for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++) { - ca_import_cancel(pSS->task_id); + ca_import_cancel(pSS->taskId); } /* Close the log file */ @@ -382,7 +404,7 @@ int tid; { #ifdef DEBUG logMsg("Closing log fd=%d\n", pSP->logFd); -#endif /*DEBUG */ +#endif DEBUG close(pSP->logFd); pSP->logFd = ioGlobalStdGet(1); } @@ -391,15 +413,15 @@ int tid; seqDelProg(pSP); /* Delete state set tasks (except self) & delete their semaphores */ - pSS = pSP->sscb; - for (nss = 0; nss < pSP->nss; nss++, pSS++) + pSS = pSP->pSS; + for (nss = 0; nss < pSP->numSS; nss++, pSS++) { - tid_ss = pSS->task_id; + tid_ss = pSS->taskId; if ( (tid != tid_ss) && (tid_ss != 0) ) { #ifdef DEBUG logMsg(" delete ss task: tid=%d\n", tid_ss); -#endif /*DEBUG */ +#endif DEBUG taskDelete(tid_ss); } @@ -414,15 +436,58 @@ int tid; semDelete(pSP->caSemId); semDelete(pSP->logSemId); - /* Free the memory that was allocated for the task area */ -#ifdef DEBUG - logMsg("free pSP->dyn_ptr=0x%x\n", pSP->dyn_ptr); -#endif /*DEBUG */ + /* Free all allocated memory */ taskDelay(5); - free(pSP->dyn_ptr); + seqFree(pSP); + + semGive(cleanupSem); return 0; } + /* seqFree()--free all allocated memory */ +VOID seqFree(pSP) +SPROG *pSP; +{ + SSCB *pSS; + CHAN *pDB; + MACRO *pMac; + int n; + + /* Free macro table entries */ + for (pMac = pSP->pMacros, n = 0; n < MAX_MACROS; pMac++, n++) + { + if (pMac->pName != NULL) + free(pMac->pName); + if (pMac->pValue != NULL) + free(pMac->pValue); + } + + /* Free MACRO table */ + free(pSP->pMacros); + + /* Free channel names */ + for (pDB = pSP->pChan, n = 0; n < pSP->numChans; pDB++, n++) + { + if (pDB->dbName != NULL) + free(pDB->dbName); + } + + /* Free channel structures */ + free(pSP->pChan); + + /* Free STATE blocks */ + pSS = pSP->pSS; + free(pSS->pStates); + + /* Free event words */ + free(pSP->pEvents); + + /* Free SSCBs */ + free(pSP->pSS); + + /* Free SPROG */ + free(pSP); +} /* * Sequencer auxillary task -- loops on ca_pend_event(). diff --git a/src/sequencer/snc.y b/src/sequencer/snc.y index d79ddc62a..ec18aeb55 100644 --- a/src/sequencer/snc.y +++ b/src/sequencer/snc.y @@ -3,11 +3,15 @@ GTA PROJECT AT division Copyright, 1990, The Regents of the University of California. Los Alamos National Laboratory - - $Id$ + snc.y,v 1.2 1995/06/27 15:26:07 wright Exp ENVIRONMENT: UNIX HISTORY: 20nov91,ajk Added new "option" statement. +08nov93,ajk Implemented additional declarations (see VC_CLASS in parse.h). +08nov93,ajk Implemented assignment of array elements to pv's. +02may93,ajk Removed "parameter" definition for functions, and added "%prec" + qualifications to some "expr" definitions. +31may94,ajk Changed method for handling global C code. ***************************************************************************/ /* SNC - State Notation Compiler. * The general structure of a state program is: @@ -31,13 +35,12 @@ */ #include #include -#include #include "parse.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 -#endif /* TRUE */ +#endif TRUE extern int line_num; /* input file line no. */ %} @@ -74,10 +77,11 @@ extern int line_num; /* input file line no. */ %type type %type subscript binop asgnop unop %type state_set_list state_set state_list state transition_list transition -%type parameter expr +%type expr compound_expr assign_list bracked_expr %type statement stmt_list compound_stmt if_stmt else_stmt while_stmt -%type for_stmt +%type for_stmt escaped_c_list /* precidence rules for expr evaluation */ +%right EQUAL COMMA %left OR AND %left GT GE EQ NE LE LT %left PLUS MINUS @@ -112,33 +116,60 @@ defn_stmt /* individual definitions for SNL (preceeds state sets) */ | debug_stmt | sync_stmt | option_stmt -| C_STMT { defn_c_stmt($1); } +| defn_c_stmt | pp_code | error { snc_err("definitions/declarations"); } ; -assign_stmt /* 'assign to ;' */ -: ASSIGN NAME TO STRING SEMI_COLON { assign_stmt($2, $4); } +assign_stmt /* assign to ; */ +: ASSIGN NAME TO STRING SEMI_COLON { assign_single($2, $4); } + + /* assign [] to ; */ +| ASSIGN NAME subscript TO STRING SEMI_COLON { assign_subscr($2, $3, $5); } + + /* assign to {, ... }; */ +| ASSIGN NAME TO L_BRACKET assign_list R_BRACKET SEMI_COLON + { assign_list($2, $5); } +; + +assign_list /* {"", .... } */ +: STRING { $$ = expression(E_STRING, $1, 0, 0); } +| assign_list COMMA STRING + { $$ = link_expr($1, expression(E_STRING, $3, 0, 0)); } ; monitor_stmt /* variable to be monitored; delta is optional */ -: MONITOR NAME SEMI_COLON { monitor_stmt($2, "0"); } -| MONITOR NAME COMMA NUMBER SEMI_COLON { monitor_stmt($2, $4); } +: MONITOR NAME SEMI_COLON { monitor_stmt($2, NULL); } +| MONITOR NAME subscript SEMI_COLON { monitor_stmt($2, $3); } ; subscript /* e.g. [10] */ -: /* empty */ { $$ = 0; } -| L_SQ_BRACKET NUMBER R_SQ_BRACKET { $$ = $2; } +: L_SQ_BRACKET NUMBER R_SQ_BRACKET { $$ = $2; } ; debug_stmt : DEBUG_PRINT NUMBER SEMI_COLON { set_debug_print($2); } ; -decl_stmt /* variable declarations (e.g. float x[20];) */ -: type NAME subscript SEMI_COLON { decl_stmt($1, $2, $3, (char *)0); } -| type NAME subscript EQUAL NUMBER SEMI_COLON { decl_stmt($1, $2, $3, $5); } -| type NAME subscript EQUAL STRING SEMI_COLON { decl_stmt($1, $2, $3, $5); } +decl_stmt /* variable declarations (e.g. float x[20];) + * decl_stmt(type, class, name, <1-st dim>, <2-nd dim>, value) */ +: type NAME SEMI_COLON + { decl_stmt($1, VC_SIMPLE, $2, NULL, NULL, NULL); } + +| type NAME EQUAL NUMBER SEMI_COLON + { decl_stmt($1, VC_SIMPLE, $2, NULL, NULL, $4 ); } + +| type NAME subscript SEMI_COLON + { decl_stmt($1, VC_ARRAY1, $2, $3, NULL, NULL); } + +| type NAME subscript subscript SEMI_COLON + { decl_stmt($1, VC_ARRAY2, $2, $3, $4, NULL); } + +| type ASTERISK NAME SEMI_COLON + { decl_stmt($1, VC_POINTER, $3, NULL, NULL, NULL); } + +| type ASTERISK NAME subscript SEMI_COLON + { decl_stmt($1, VC_ARRAYP, $3, $4, NULL, NULL); } ; type /* types for variables defined in SNL */ @@ -153,8 +184,14 @@ type /* types for variables defined in SNL */ ; sync_stmt /* sync */ -: SYNC NAME TO NAME SEMI_COLON { sync_stmt($2, $4); } -| SYNC NAME NAME SEMI_COLON { sync_stmt($2, $3); /* archaic syntax */ } +: SYNC NAME TO NAME SEMI_COLON { sync_stmt($2, NULL, $4); } +| SYNC NAME NAME SEMI_COLON { sync_stmt($2, NULL, $3); } +| SYNC NAME subscript TO NAME SEMI_COLON { sync_stmt($2, $3, $5); } +| SYNC NAME subscript NAME SEMI_COLON { sync_stmt($2, $3, $4); } +; + +defn_c_stmt /* escaped C in definitions */ +: escaped_c_list { defn_c_stmt($1); } ; option_stmt /* option +/-