Sequencer V1.9.0(3.12.1) form lanl.

This commit is contained in:
Janet B. Anderson
1995-10-19 21:35:38 +00:00
parent c7b5592846
commit b0177729b8
20 changed files with 2941 additions and 1706 deletions

View File

@@ -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=../../..

View File

@@ -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

View File

@@ -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

View File

@@ -1,2 +1,3 @@
1.8.3
1.9.0(3.12.1)

View File

@@ -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
#

View File

@@ -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 <stdio.h>
#include "parse.h"
#include "cadef.h"
#include <dbDefs.h>
#include <seqU.h>
#include <dbDefs.h>
#include <seqCom.h>
/*+************************************************************************
* 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)(<some expression>));
*/
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: <db variable>[<expression>] */
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);

View File

@@ -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 <stdio.h>
#include "parse.h"
#include <dbDefs.h>
#include <seqU.h>
#include <seqCom.h>
/*+************************************************************************
* 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 */

View File

@@ -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 <stdio.h>
#include "parse.h" /* defines linked list structures */
#include <math.h>
#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 <variable> to <string;
* Note: Variable may be subscripted.
*/
assign_single(name, db_name)
char *name; /* ptr to variable name */
char *db_name; /* ptr to db name */
{
Chan *cp;
Var *vp;
int subNum;
extern int line_num;
#ifdef DEBUG
fprintf(stderr, "assign_stmt: name=%s, db_name=%s\n", name, db_name);
#endif /* DEBUG */
fprintf(stderr, "assign %s to \"%s\";\n", name, db_name);
#endif DEBUG
/* Find the variable */
vp = (Var *)findVar(name);
if (vp == 0)
@@ -176,29 +197,240 @@ char *db_name; /* ptr to db name */
return;
}
/* Build structure for this channel */
cp = allocChan();
addChan(cp); /* add to Chan list */
cp->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 <variable>[<subscr>] to <string>; */
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 <variable> to { <string>, <string>, ... };
* Assignments for double dimensioned arrays:
* <var>[0][0] assigned to 1st db name,
* <var>[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 <var>; - monitor a single variable or all elements in an array.
* monitor <var>[<m>]; - 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_?" };

View File

@@ -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 */

View File

@@ -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 <stdio.h>
#include "parse.h"
#include <dbDefs.h>
#include <seqU.h>
#include <seqCom.h>
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:

View File

@@ -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 <string.h>
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);

616
src/sequencer/seq_if.c Normal file
View File

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

View File

@@ -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 <string.h>
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;
}

View File

@@ -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: <user's message>".
* 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);
}

View File

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

View File

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

View File

@@ -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 <taskwd.h>
/* 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().

View File

@@ -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 <stdio.h>
#include <ctype.h>
#include <string.h>
#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 <ival> type
%type <pchar> subscript binop asgnop unop
%type <pexpr> state_set_list state_set state_list state transition_list transition
%type <pexpr> parameter expr
%type <pexpr> expr compound_expr assign_list bracked_expr
%type <pexpr> statement stmt_list compound_stmt if_stmt else_stmt while_stmt
%type <pexpr> for_stmt
%type <pexpr> 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 <var name> to <db name>;' */
: ASSIGN NAME TO STRING SEMI_COLON { assign_stmt($2, $4); }
assign_stmt /* assign <var name> to <db name>; */
: ASSIGN NAME TO STRING SEMI_COLON { assign_single($2, $4); }
/* assign <var name>[<n>] to <db name>; */
| ASSIGN NAME subscript TO STRING SEMI_COLON { assign_subscr($2, $3, $5); }
/* assign <var name> to {<db name>, ... }; */
| ASSIGN NAME TO L_BRACKET assign_list R_BRACKET SEMI_COLON
{ assign_list($2, $5); }
;
assign_list /* {"<db name>", .... } */
: 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 <variable> <event flag> */
: 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 +/-<option>; e.g. option +a; */
@@ -201,7 +238,8 @@ transition /* define a transition ("when" statment ) */
expr /* general expr: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */
/* Expr *expression(int type, char *value, Expr *left, Expr *right) */
: expr binop expr { $$ = expression(E_BINOP, $2, $1, $3); }
: compound_expr { $$ = $1; }
| expr binop expr %prec UOP { $$ = expression(E_BINOP, $2, $1, $3); }
| expr asgnop expr { $$ = expression(E_ASGNOP, $2, $1, $3); }
| unop expr %prec UOP { $$ = expression(E_UNOP, $1, $2, 0); }
| AUTO_INCR expr %prec UOP { $$ = expression(E_PRE, "++", $2, 0); }
@@ -211,12 +249,20 @@ expr /* general expr: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */
| NUMBER { $$ = expression(E_CONST, $1, 0, 0); }
| STRING { $$ = expression(E_STRING, $1, 0, 0); }
| NAME { $$ = expression(E_VAR, $1, 0, 0); }
| NAME L_PAREN parameter R_PAREN { $$ = expression(E_FUNC, $1, $3, 0); }
| EXIT L_PAREN parameter R_PAREN { $$ = expression(E_FUNC, "exit", $3, 0); }
| NAME L_PAREN expr R_PAREN { $$ = expression(E_FUNC, $1, $3, 0); }
| EXIT L_PAREN expr R_PAREN { $$ = expression(E_FUNC, "exit", $3, 0); }
| L_PAREN expr R_PAREN { $$ = expression(E_PAREN, "", $2, 0); }
| expr L_SQ_BRACKET expr R_SQ_BRACKET %prec SUBSCRIPT
{ $$ = expression(E_SUBSCR, "", $1, $3); }
| /* empty */ { $$ = expression(E_EMPTY, "", 0, 0); }
| expr bracked_expr %prec SUBSCRIPT { $$ = expression(E_SUBSCR, "", $1, $2); }
| /* empty */ { $$ = 0; }
;
compound_expr
: expr COMMA expr { $$ = link_expr($1, $3); }
| compound_expr COMMA expr { $$ = link_expr($1, $3); }
;
bracked_expr /* e.g. [k-1] */
: L_SQ_BRACKET expr R_SQ_BRACKET { $$ = $2; }
;
unop /* Unary operators */
@@ -246,7 +292,6 @@ binop /* Binary operators */
| BIT_AND { $$ = "&"; }
| COMPLEMENT { $$ = "^"; }
| MODULO { $$ = "%"; }
| COMMA { $$ = ","; }
| PERIOD { $$ = "."; } /* fudges structure elements */
| POINTER { $$ = "->"; } /* fudges ptr to structure elements */
;
@@ -265,12 +310,6 @@ asgnop /* Assignment operators */
| CMPL_EQUAL { $$ = "^="; }
;
parameter /* expr, expr, .... */
: expr { $$ = $1; }
| parameter COMMA expr { $$ = link_expr($1, $3); }
| /* empty */ { $$ = 0; }
;
compound_stmt /* compound statement e.g. { ...; ...; ...; } */
: L_BRACKET stmt_list R_BRACKET { $$ = expression(E_CMPND, "",$2, 0); }
| error { snc_err("action statements"); }
@@ -319,8 +358,21 @@ pp_code /* pre-processor code (e.g. # 1 "test.st") */
;
global_c
: C_STMT { global_c_stmt($1); }
: escaped_c_list { global_c_stmt($1); }
;
escaped_c_list
: C_STMT { $$ = expression(E_TEXT, "", $1, 0); }
| escaped_c_list C_STMT { $$ = link_expr($1, expression(E_TEXT, "", $2, 0)); }
;
%%
#include "snc_lex.c"
#include "snc_main.c"
#include "snc_lex.c"
static int yyparse (void);
/* yyparse() is static, so we create global access to it */
void Global_yyparse (void)
{
yyparse ();
}

View File

@@ -4,7 +4,7 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
snc_lex.l,v 1.2 1995/06/27 15:26:09 wright Exp
ENVIRONMENT: UNIX
HISTORY:
20nov91,ajk Added OPTION token.
@@ -12,6 +12,14 @@
17Jul92,rcz changed warn_flag to warn_opt
17Jul92,rcz Ported ajk version from lanl
04apr93,ajk Increased STR_BFR_SIZE from 30000 to 300000
19nov93,ajk Added definitions for octal and hex numbers.
19nov93,ajk Removed optional "-" from definition of FPNUM. This was
causing problems with statements like "k-1".
27man94,ajk Implemented dynamic allocation of strings, thus eliminating
huge string buffer.
31may94,ajk Changed handling of escaped C code.
17feb95,ajk Removed includes "parse.h" & "snc.h", because this module
now gets included in snc.y.
***************************************************************************/
/* Lexical analyzer for State Notation Compiler (snc).
*
@@ -22,10 +30,8 @@
* Comments are recognized as part of the syntax.
*/
/*
#include "parse.h"
#include "snc.h"
*/
#include "string.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
@@ -36,16 +42,14 @@
#else
#define RETURN(param) return(param);
#endif
#define STR_BFR_SIZE 300000
#define STR_BFR_SIZE 1000
extern int line_num, c_line_num; /* input line number */
extern int warn_opt; /* compiler warning flag */
char str_bfr[STR_BFR_SIZE]; /* holding place for strings */
char *str_next = str_bfr; /* current ptr to str_bfr */
char *c_str; /* Start of current string in str_bfr */
int nc;
extern int line_num, c_line_num; /* input line number */
extern int warn_opt; /* compiler warning flag */
char strBfr[STR_BFR_SIZE]; /* holding place for strings */
char *pStr; /* current ptr to strBfr */
double atof();
int one_line_c_code;
int one_line_c_code; /* TRUE for %%; FALSE for %{...}% */
%}
@@ -53,24 +57,25 @@ int one_line_c_code;
%Start SNL C_CODE COMMENT STR PP PP_STR
NAME [a-zA-Z][a-zA-Z0-9_]*
FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
FPNUM (([0-9]+)(\.[0-9]*)?)|(\.[0-9]+)
OCTAL 0[0-7]+
HEX 0x([0-9a-fA-F])+
%% /* Begin rules */
<C_CODE>. *str_next++ = yytext[0];
<C_CODE>. *pStr++ = yytext[0];
<C_CODE>\n {
*str_next++ = '\n';
*pStr++ = 0;
line_num++;
c_line_num = line_num;
yylval.pchar = strdup(strBfr);
pStr = strBfr;
if (one_line_c_code)
{
*str_next++ = 0;
yylval.pchar = c_str;
BEGIN SNL;
RETURN(C_STMT);
}
RETURN(C_STMT);
}
<C_CODE>"}%" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN SNL;
RETURN(C_STMT);
}
@@ -78,29 +83,26 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<COMMENT>"*/" BEGIN SNL;
<COMMENT>. ;
<STR>"\\\"" {
*str_next++ = yytext[0];
*str_next++ = yytext[1];
*pStr++ = yytext[0];
*pStr++ = yytext[1];
}
<STR>\" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN SNL;
RETURN(STRING);
}
<STR>. { *str_next++ = yytext[0]; }
<STR>\n { *str_next++ = '?';
<STR>. { *pStr++ = yytext[0]; }
<STR>\n { *pStr++ = '?';
if (warn_opt)
fprintf(stderr, "Warning: newline in string, line %d\n",
line_num);
line_num++;
}
<PP>{FPNUM} { nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
<PP>{FPNUM} { yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<PP>\" { c_str = str_next; BEGIN PP_STR; }
<PP>\" { pStr = strBfr; BEGIN PP_STR; }
<PP>\n {
BEGIN SNL;
RETURN(CR);
@@ -109,22 +111,22 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<PP>. {
}
<PP_STR>\" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN PP;
RETURN(STRING);
}
<PP_STR>. { *str_next++ = yytext[0]; }
<PP_STR>\n { *str_next++ = '?'; line_num++; }
<PP_STR>. { *pStr++ = yytext[0]; }
<PP_STR>\n { *pStr++ = '?'; line_num++; }
<SNL>\n { line_num++; }
<SNL>"%{" {
c_str = str_next;
pStr = strBfr;
one_line_c_code = FALSE;
c_line_num = line_num;
BEGIN C_CODE;
}
<SNL>"%%" {
c_str = str_next;
pStr = strBfr;
one_line_c_code = TRUE;
c_line_num = line_num;
BEGIN C_CODE;
@@ -134,7 +136,7 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
RETURN(PP_SYMBOL);
}
<SNL>"/*" BEGIN COMMENT;
<SNL>\" { c_str = str_next; BEGIN STR; }
<SNL>\" { pStr = strBfr; BEGIN STR; }
<SNL>"ss" RETURN(STATE_SET);
<SNL>"state" RETURN(STATE);
<SNL>"when" RETURN(WHEN);
@@ -167,10 +169,7 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
RETURN(NUMBER);
}
<SNL>{NAME} {
nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
yylval.pchar = strdup(yytext);
RETURN(NAME);
}
<SNL>"++" RETURN(AUTO_INCR);
@@ -217,11 +216,16 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<SNL>"(" RETURN(L_PAREN);
<SNL>")" RETURN(R_PAREN);
<SNL>"," RETURN(COMMA);
<SNL>{HEX} {
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>{OCTAL} {
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>{FPNUM} {
nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>[\t\ ]* /* no action */ ;

View File

@@ -3,7 +3,9 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
snc_main.c,v 1.2 1995/06/27 15:26:11 wright Exp
DESCRIPTION: Main program and miscellaneous routines for
State Notation Compiler.
@@ -12,11 +14,17 @@
20nov91,ajk Removed call to init_snc().
20nov91,ajk Removed some debug stuff.
28apr92,ajk Implemented new event flag mode.
29oct93,ajk Added 'v' (vxWorks include) option.
17may94,ajk Changed setlinebuf() to setvbuf().
17may94,ajk Removed event flag option (-e).
17feb95,ajk Changed yyparse() to Global_yyparse(), because FLEX makes
yyparse() static.
02mar95,ajk Changed bcopy () to strcpy () in 2 places.
26jun95,ajk Due to popular demand, reinstated event flag (-e) option.
***************************************************************************/
extern char *sncVersion; /* snc version and date created */
#include <stdio.h>
#include <string.h>
#ifndef TRUE
#define TRUE 1
@@ -33,10 +41,11 @@ int c_line_num; /* line number for beginning of C code */
int async_opt = FALSE; /* do pvGet() asynchronously */
int conn_opt = TRUE; /* wait for all connections to complete */
int debug_opt = FALSE; /* run-time debug */
int newef_opt = TRUE; /* use new event flag mode */
int newef_opt = TRUE; /* new event flag mode */
int line_opt = TRUE; /* line numbering */
int reent_opt = FALSE; /* reentrant at run-time */
int warn_opt = TRUE; /* compiler warnings */
int vx_opt = TRUE; /* include vxWorks def's */
/*+************************************************************************
* NAME: main
@@ -62,7 +71,6 @@ int argc;
char *argv[];
{
FILE *infp, *outfp, *freopen();
extern char in_file[], out_file[];
/* Get command arguments */
get_args(argc, argv);
@@ -87,17 +95,13 @@ char *argv[];
src_file = in_file;
/* Use line buffered output */
setvbuf(stdout,NULL,_IOLBF,0);
setvbuf(stderr,NULL,_IOLBF,0);
/* setlinebuf() isn't ANSI-C or XPG2/3/4
setlinebuf(stdout);
setlinebuf(stderr);
*/
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
printf("/* %s: %s */\n\n", sncVersion, in_file);
/* Call the SNC parser */
yyparse();
Global_yyparse();
}
/*+************************************************************************
* NAME: get_args
@@ -129,10 +133,11 @@ char *argv[];
fprintf(stderr, " +a - do async. pvGet\n");
fprintf(stderr, " -c - don't wait for all connects\n");
fprintf(stderr, " +d - turn on debug run-time option\n");
fprintf(stderr, " -e - don't use new event flag mode\n");
fprintf(stderr, " -l - supress line numbering\n");
fprintf(stderr, " +r - make reentrant at run-time\n");
fprintf(stderr, " -w - supress compiler warnings\n");
fprintf(stderr, " -e - don't use new event flag mode\n");
fprintf(stderr, " -v - don't include VxWorks definitions\n");
fprintf(stderr, "example:\n snc +a -c vacuum.st\n");
exit(1);
}
@@ -151,7 +156,6 @@ get_options(s)
char *s;
{
int opt_val;
extern int debug_opt, line_opt, reent_opt, warn_opt, async_opt, newef_opt;
if (*s == '+')
opt_val = TRUE;
@@ -172,6 +176,10 @@ char *s;
debug_opt = opt_val;
break;
case 'e':
newef_opt = opt_val;
break;
case 'l':
line_opt = opt_val;
break;
@@ -184,8 +192,8 @@ char *s;
warn_opt = opt_val;
break;
case 'e':
newef_opt = opt_val;
case 'v':
vx_opt = opt_val;
break;
default:
@@ -194,17 +202,15 @@ char *s;
}
}
get_in_file(s)
get_in_file (s)
char *s;
{
extern char in_file[], out_file[];
int ls;
ls = strlen(s);
memcpy(in_file, s, ls);
in_file[ls] = 0;
memcpy(out_file, s, ls);
if ( strcmp(&in_file[ls-3], ".st") == 0 )
ls = strlen (s);
strcpy (in_file, s);
strcpy (out_file, s);
if ( strcmp (&in_file[ls-3], ".st") == 0 )
{
out_file[ls-2] = 'c';
out_file[ls-1] = 0;
@@ -260,9 +266,6 @@ char *err_txt;
yyerror(err)
char *err;
{
extern char *src_file;
extern int line_num;
fprintf(stderr, "%s: line no. %d (%s)\n", err, line_num, src_file);
return;
}
@@ -287,8 +290,6 @@ print_line_num(line_num, src_file)
int line_num;
char *src_file;
{
extern int line_opt;
if (line_opt)
printf("# line %d \"%s\"\n", line_num, src_file);
return;