moved to src/vxWorks
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
#YACCOPT = -l
|
||||
#LEXOPT = -L
|
||||
|
||||
#USR_LDLIBS = -ll
|
||||
YACCOPT = -d -v
|
||||
|
||||
SYS_PROD_LIBS_DEFAULT := m
|
||||
SYS_PROD_LIBS_WIN32 := -nil-
|
||||
|
||||
INC += seq.h
|
||||
INC += seqCom.h
|
||||
|
||||
SRCS += snc_main.c
|
||||
SRCS += parse.c
|
||||
SRCS += phase2.c
|
||||
SRCS += gen_ss_code.c
|
||||
SRCS += gen_tables.c
|
||||
SRCS += sncVersion.c
|
||||
SRCS += snc.c
|
||||
|
||||
PROD_DEFAULT += snc
|
||||
PROD_vxWorks +=
|
||||
|
||||
seq_CFLAGS =
|
||||
|
||||
seq_SRCS = \
|
||||
seq_main.c seq_ca.c seq_qry.c seq_task.c \
|
||||
seq_mac.c seq_prog.c seq_if.c seqVersion.c
|
||||
|
||||
LIBRARY_vxWorks = seq
|
||||
|
||||
include $(TOP)/configure/RULES_BUILD
|
||||
|
||||
#
|
||||
# The generated lex file includes snc.h
|
||||
#
|
||||
snc.c: snc_lex.c
|
||||
|
||||
sncVersion.c: ../Version ../makeVersion.pl
|
||||
$(PERL) ../makeVersion.pl ../Version sncVersion
|
||||
|
||||
clean::
|
||||
@$(RM) y.output sncVersion.c snc_lex.c snc.c snc.h
|
||||
|
||||
seqVersion.c: ../Version ../makeVersion.pl
|
||||
$(PERL) ../makeVersion.pl ../Version seqVersion
|
||||
@@ -1,6 +0,0 @@
|
||||
###
|
||||
### 3 Apr. 1991 (MDA) moved seq.c to seq_main.c for consistency with
|
||||
### snc, and for ease of use in Imakefiles...
|
||||
###
|
||||
### 03jan92,ajk s_*.c files are VxWorks version 5 compatable.
|
||||
###
|
||||
@@ -1 +0,0 @@
|
||||
1.9.2.Beta12
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/sh
|
||||
# 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
|
||||
#
|
||||
# Experimental Physics and Industrial Control System (EPICS)
|
||||
#
|
||||
# Copyright 1991, 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:
|
||||
# -----------------
|
||||
# .01 08-20-91 rac initial version
|
||||
|
||||
# set execute permission for shell scripts in this directory (this avoids
|
||||
# the need to manually maintain a list of file names)
|
||||
|
||||
# the name of this file is magic for ~epics/release/sccsGet. Whenever that
|
||||
# that script sees a file named "chmod.sh" it executes the file.
|
||||
|
||||
L=""
|
||||
for F in `find * \( -type d -prune \) -o -type f -print`; do
|
||||
if [ "`sed -n -e '/^\#\!/p' -e 1q $F`" ]; then
|
||||
L="$L $F"
|
||||
fi
|
||||
done
|
||||
if [ "$L" ]; then
|
||||
chmod +x $L
|
||||
fi
|
||||
@@ -1,687 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
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.
|
||||
13jan98,wfl Fixed handling of compound expressions, using E_COMMA.
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "parse.h"
|
||||
#include "cadef.h"
|
||||
#include <dbDefs.h>
|
||||
#include <seqCom.h>
|
||||
|
||||
/*+************************************************************************
|
||||
* NAME: gen_ss_code
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* ---------------------------------------------------
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* FUNCTION: Generate state set C code from tables.
|
||||
*
|
||||
* NOTES: All inputs are external globals.
|
||||
*-*************************************************************************/
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#define EVENT_STMT 1
|
||||
#define ACTION_STMT 2
|
||||
#define DELAY_STMT 3
|
||||
#define EXIT_STMT 4
|
||||
|
||||
gen_ss_code()
|
||||
{
|
||||
extern Expr *ss_list;
|
||||
Expr *ssp;
|
||||
Expr *sp;
|
||||
|
||||
/* For each state set ... */
|
||||
for (ssp = ss_list; ssp != NULL; ssp = ssp->next)
|
||||
{
|
||||
/* For each state ... */
|
||||
for (sp = ssp->left; sp != NULL; sp = sp->next)
|
||||
{
|
||||
printf("\f/* Code for state \"%s\" in state set \"%s\" */\n",
|
||||
sp->value, ssp->value);
|
||||
|
||||
/* Generate function to set up for delay processing */
|
||||
gen_delay_func(sp, ssp);
|
||||
|
||||
/* Generate event processing function */
|
||||
gen_event_func(sp, ssp);
|
||||
|
||||
/* Generate action processing function */
|
||||
gen_action_func(sp, ssp);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 void 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:
|
||||
Each state has one action routine. It's name is derived from the
|
||||
state set name and the state name.
|
||||
*/
|
||||
gen_action_func(sp, ssp)
|
||||
Expr *sp;
|
||||
Expr *ssp; /* Parent state set */
|
||||
{
|
||||
Expr *tp;
|
||||
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);
|
||||
printf("static void 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(transNum)\n\t{\n");
|
||||
trans_num = 0;
|
||||
line_num = 0;
|
||||
/* For each transition ("when" statement) ... */
|
||||
for (tp = sp->left; tp != NULL; tp = tp->next)
|
||||
{
|
||||
/* "case" for each transition */
|
||||
printf("\tcase %d:\n", trans_num);
|
||||
/* For each action statement insert action code */
|
||||
for (ap = tp->right; ap != NULL; ap = ap->next)
|
||||
{
|
||||
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);
|
||||
}
|
||||
/* end of case */
|
||||
printf("\t\treturn;\n");
|
||||
trans_num++;
|
||||
}
|
||||
/* end of switch stmt */
|
||||
printf("\t}\n");
|
||||
/* end of function */
|
||||
printf("}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate a C function that checks events for a particular state */
|
||||
gen_event_func(sp, ssp)
|
||||
Expr *sp;
|
||||
Expr *ssp;
|
||||
{
|
||||
Expr *tp;
|
||||
int index, trans_num;
|
||||
|
||||
printf("\n/* Event function for state \"%s\" in state set \"%s\" */\n",
|
||||
sp->value, ssp->value);
|
||||
printf("static long 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 (");
|
||||
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);
|
||||
if (index < 0)
|
||||
{
|
||||
fprintf(stderr, "Line %d: ", tp->line_num);
|
||||
fprintf(stderr, "No state %s in state set %s\n",
|
||||
tp->value, ssp->value);
|
||||
index = 0; /* default to 1-st state */
|
||||
printf("\t\t/* state %s does not exist */\n",
|
||||
tp->value);
|
||||
}
|
||||
printf("\t\t*pNextState = %d;\n", index);
|
||||
printf("\t\t*pTransNum = %d;\n", trans_num);
|
||||
printf("\t\treturn TRUE;\n\t}\n");
|
||||
trans_num++;
|
||||
}
|
||||
printf("\treturn FALSE;\n");
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
/* Given a state name and state set struct, find the corresponding
|
||||
state struct and return its index (1-st one is 0) */
|
||||
state_block_index_from_name(ssp, state_name)
|
||||
Expr *ssp;
|
||||
char *state_name;
|
||||
{
|
||||
Expr *sp;
|
||||
int index;
|
||||
|
||||
index = 0;
|
||||
for (sp = ssp->left; sp != NULL; sp = sp->next)
|
||||
{
|
||||
if (strcmp(state_name, sp->value) == 0)
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
return -1; /* State name non-existant */
|
||||
}
|
||||
/* Evaluate an expression.
|
||||
*/
|
||||
eval_expr(stmt_type, ep, sp, level)
|
||||
int stmt_type; /* EVENT_STMT, ACTION_STMT, or DELAY_STMT */
|
||||
Expr *ep; /* ptr to expression */
|
||||
Expr *sp; /* ptr to current State struct */
|
||||
int level; /* indentation level */
|
||||
{
|
||||
Expr *epf;
|
||||
int nexprs;
|
||||
extern int reent_opt;
|
||||
extern int line_num;
|
||||
|
||||
if (ep == 0)
|
||||
return;
|
||||
|
||||
switch(ep->type)
|
||||
{
|
||||
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:
|
||||
indent(level);
|
||||
if (ep->type == E_IF)
|
||||
printf("if (");
|
||||
else
|
||||
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);
|
||||
else
|
||||
eval_expr(stmt_type, ep->right, sp, level+1);
|
||||
break;
|
||||
case E_FOR:
|
||||
indent(level);
|
||||
printf("for (");
|
||||
eval_expr(stmt_type, ep->left->left, sp, 0);
|
||||
printf("; ");
|
||||
eval_expr(stmt_type, ep->left->right, sp, 0);
|
||||
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);
|
||||
else
|
||||
eval_expr(stmt_type, epf, sp, level+1);
|
||||
break;
|
||||
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)
|
||||
eval_expr(stmt_type, ep->left, sp, level);
|
||||
else
|
||||
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("(pVar->%s)", ep->value);
|
||||
else
|
||||
printf("%s", ep->value);
|
||||
}
|
||||
else
|
||||
printf("%s", ep->value);
|
||||
break;
|
||||
case E_CONST:
|
||||
printf("%s", ep->value);
|
||||
break;
|
||||
case E_STRING:
|
||||
printf("\"%s\"", ep->value);
|
||||
break;
|
||||
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);
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
printf(") ");
|
||||
break;
|
||||
case E_COMMA:
|
||||
for (epf = ep->left, nexprs = 0; epf != 0; epf = epf->next, nexprs++)
|
||||
{
|
||||
if (nexprs > 0)
|
||||
printf(" ,");
|
||||
eval_expr(stmt_type, epf, sp, 0);
|
||||
}
|
||||
break;
|
||||
case E_ASGNOP:
|
||||
case E_BINOP:
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
printf(" %s ", ep->value);
|
||||
eval_expr(stmt_type, ep->right, sp, 0);
|
||||
break;
|
||||
case E_PAREN:
|
||||
printf("(");
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
printf(")");
|
||||
break;
|
||||
case E_UNOP:
|
||||
printf("%s", ep->value);
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
break;
|
||||
case E_PRE:
|
||||
printf("%s", ep->value);
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
break;
|
||||
case E_POST:
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
printf("%s", ep->value);
|
||||
break;
|
||||
case E_SUBSCR:
|
||||
eval_expr(stmt_type, ep->left, sp, 0);
|
||||
printf("[");
|
||||
eval_expr(stmt_type, ep->right, sp, 0);
|
||||
printf("]");
|
||||
break;
|
||||
case E_TEXT:
|
||||
printf("%s\n", ep->left);
|
||||
line_num += 1;
|
||||
break;
|
||||
default:
|
||||
if (stmt_type == EVENT_STMT)
|
||||
printf("TRUE"); /* empty event statement defaults to TRUE */
|
||||
else
|
||||
printf(" ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
indent(level)
|
||||
int level;
|
||||
{
|
||||
while (level-- > 0)
|
||||
printf("\t");
|
||||
}
|
||||
/* 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_PVTIMESTAMP, F_PVASSIGN,
|
||||
F_PVMONITOR, F_PVSTOPMONITOR, F_PVCOUNT, F_PVINDEX,
|
||||
F_PVSTATUS, F_PVSEVERITY, F_PVFLUSH, F_PVERROR, F_PVGETCOMPLETE,
|
||||
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", "pvTimeStamp", "pvAssign",
|
||||
"pvMonitor", "pvStopMonitor", "pvCount", "pvIndex",
|
||||
"pvStatus", "pvSeverity", "pvFlush", "pvError", "pvGetComplete",
|
||||
"pvAssigned", "pvConnected",
|
||||
"pvChannelCount", "pvConnectCount", "pvAssignCount",
|
||||
"pvDisconnect", "seqLog", "macValueGet", "optGet",
|
||||
NULL };
|
||||
|
||||
enum fcode func_name_to_code(fname)
|
||||
char *fname;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; fcode_str[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp(fname, fcode_str[i]) == 0)
|
||||
return (enum fcode)i;
|
||||
}
|
||||
|
||||
return F_NONE;
|
||||
}
|
||||
|
||||
/* Process special function (returns TRUE if this is a special function)
|
||||
Checks for one of the following special 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 */
|
||||
Expr *ep; /* ptr to function in the expression */
|
||||
Expr *sp; /* current State struct */
|
||||
{
|
||||
char *fname; /* function name */
|
||||
Expr *ep1, *ep2, *ep3; /* parameters */
|
||||
Chan *cp;
|
||||
Var *vp;
|
||||
enum fcode func_code;
|
||||
int delay_id;
|
||||
|
||||
fname = ep->value;
|
||||
func_code = func_name_to_code(fname);
|
||||
if (func_code == F_NONE)
|
||||
return FALSE; /* not a special function */
|
||||
|
||||
#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:
|
||||
/* Event flag funtions */
|
||||
gen_ef_func(stmt_type, ep, sp, fname, func_code);
|
||||
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:
|
||||
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:
|
||||
case F_PVASSIGNCOUNT:
|
||||
/* DB functions NOT requiring a channel structure */
|
||||
printf("seq_%s(ssId)", fname);
|
||||
return TRUE;
|
||||
|
||||
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 */
|
||||
ep1 = ep->left;
|
||||
if (ep1 != 0 && ep1->type == E_COMMA)
|
||||
ep1 = ep1->left;
|
||||
for (; ep1 != 0; ep1 = ep1->next)
|
||||
{
|
||||
printf(", ");
|
||||
eval_expr(stmt_type, ep1, sp, 0);
|
||||
}
|
||||
printf(") ");
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
/* Not a special function */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 *ep1, *ep2, *ep3;
|
||||
Var *vp;
|
||||
Chan *cp;
|
||||
|
||||
ep1 = ep->left; /* ptr to 1-st parameters */
|
||||
if (ep1 != 0 && ep1->type == E_COMMA)
|
||||
ep1 = ep1->left;
|
||||
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 && ep1->type == E_COMMA)
|
||||
ep1 = ep1->left;
|
||||
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, "gen_pv_func: var=%s\n", ep1->value);
|
||||
#endif /*DEBUG*/
|
||||
cp = vp->chan;
|
||||
index = cp->index;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
printf("seq_%s(ssId, %d", fname, index);
|
||||
|
||||
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()
|
||||
{
|
||||
extern Expr *exit_code_list;
|
||||
Expr *ep;
|
||||
|
||||
printf("/* Exit handler */\n");
|
||||
printf("static void 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);
|
||||
}
|
||||
printf("}\n\n");
|
||||
}
|
||||
@@ -1,546 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
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.
|
||||
20jul95,ajk Added unsigned types.
|
||||
22jul96,ajk Added castS to action, event, delay, and exit functions.
|
||||
09mar98,wfl Avoided compilation warnings under Tornado
|
||||
11mar98,wfl Corrected calculation of number of event words.
|
||||
***************************************************************************/
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "parse.h"
|
||||
#include <dbDefs.h>
|
||||
#include <seqCom.h>
|
||||
|
||||
/*+************************************************************************
|
||||
* NAME: gen_tables
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* ---------------------------------------------------
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Generate C code from tables.
|
||||
*
|
||||
* NOTES: All inputs are external globals.
|
||||
*-*************************************************************************/
|
||||
|
||||
gen_tables()
|
||||
{
|
||||
extern Expr *ss_list; /* state sets (from parse) */
|
||||
extern char *global_c_code; /* global C code */
|
||||
|
||||
printf("\f/************************ Tables ***********************/\n");
|
||||
|
||||
/* Generate DB blocks */
|
||||
gen_db_blocks();
|
||||
|
||||
/* Generate State Blocks */
|
||||
gen_state_blocks();
|
||||
|
||||
/* Generate State Set Blocks */
|
||||
gen_ss_array();
|
||||
|
||||
/* generate program parameter string */
|
||||
gen_prog_params();
|
||||
|
||||
/* Generate state program table */
|
||||
gen_prog_table();
|
||||
|
||||
return;
|
||||
}
|
||||
/* Generate database blocks with structure and data for each defined channel */
|
||||
gen_db_blocks()
|
||||
{
|
||||
extern Chan *chan_list;
|
||||
Chan *cp;
|
||||
int nchan, elem_num;
|
||||
|
||||
printf("\n/* Database Blocks */\n");
|
||||
printf("static struct seqChan seqChan[NUM_CHANNELS] = {\n");
|
||||
nchan = 0;
|
||||
|
||||
for (cp = chan_list; cp != NULL; cp = cp->next)
|
||||
{
|
||||
#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");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fill in a db block with data (all elements for "seqChan" struct) */
|
||||
fill_db_block(cp, elem_num)
|
||||
Chan *cp;
|
||||
int elem_num;
|
||||
{
|
||||
Var *vp;
|
||||
char *type_string, *suffix, elem_str[20], *db_name;
|
||||
extern char *prog_name;
|
||||
extern int reent_opt;
|
||||
extern int num_events;
|
||||
int size, count, ef_num, mon_flag;
|
||||
char *db_type_str();
|
||||
|
||||
vp = cp->var;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
if (db_name == NULL)
|
||||
db_name = ""; /* not assigned */
|
||||
|
||||
/* Now, fill in the dbCom structure */
|
||||
|
||||
printf(" {\"%s\", ", db_name);/* unexpanded db channel name */
|
||||
|
||||
/* Ptr or offset to user variable */
|
||||
printf("(void *)");
|
||||
if (reent_opt)
|
||||
printf("OFFSET(struct UserVar, %s%s%s), ", vp->name, elem_str, suffix);
|
||||
else
|
||||
printf("&%s%s%s, ", vp->name, elem_str, suffix); /* variable ptr */
|
||||
|
||||
/* variable name with optional elem num */
|
||||
printf("\"%s%s\", ", vp->name, elem_str);
|
||||
|
||||
/* variable type */
|
||||
printf("\n \"%s\", ", db_type_str(vp->type) );
|
||||
|
||||
/* count for db requests */
|
||||
printf("%d, ", cp->count);
|
||||
|
||||
/* event number */
|
||||
printf("%d, ", cp->index + elem_num + num_events + 1);
|
||||
|
||||
/* event flag number (or 0) */
|
||||
printf("%d, ", ef_num);
|
||||
|
||||
/* monitor flag */
|
||||
printf("%d", mon_flag);
|
||||
|
||||
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_UCHAR: return "unsigned char";
|
||||
case V_USHORT:return "unsigned short";
|
||||
case V_UINT: return "unsigned int";
|
||||
case V_ULONG: return "unsigned 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 */
|
||||
gen_state_blocks()
|
||||
{
|
||||
extern Expr *ss_list;
|
||||
Expr *ssp;
|
||||
Expr *sp;
|
||||
int nstates, n;
|
||||
extern int num_events, num_channels;
|
||||
int numEventWords;
|
||||
bitMask *pEventMask;
|
||||
|
||||
|
||||
/* Allocate an array for event mask bits (NB, bit zero is not used) */
|
||||
numEventWords = (num_events + num_channels + NBITS)/NBITS;
|
||||
pEventMask = (bitMask *)calloc(numEventWords, sizeof (bitMask));
|
||||
|
||||
/* for all state sets ... */
|
||||
for (ssp = ss_list; ssp != NULL; ssp = ssp->next)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
nstates++;
|
||||
fill_state_block(sp, ssp->value);
|
||||
}
|
||||
printf("\n};\n");
|
||||
}
|
||||
|
||||
free(pEventMask);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fill in data for a state block (see seqState in seqCom.h) */
|
||||
fill_state_block(sp, ss_name)
|
||||
Expr *sp;
|
||||
char *ss_name;
|
||||
{
|
||||
|
||||
printf("\t/* State \"%s\" */ {\n", sp->value);
|
||||
|
||||
printf("\t/* state name */ \"%s\",\n", sp->value);
|
||||
|
||||
printf("\t/* action function */ (ACTION_FUNC) A_%s_%s,\n", ss_name, sp->value);
|
||||
|
||||
printf("\t/* event function */ (EVENT_FUNC) E_%s_%s,\n", ss_name, sp->value);
|
||||
|
||||
printf("\t/* delay function */ (DELAY_FUNC) D_%s_%s,\n", ss_name, sp->value);
|
||||
|
||||
printf("\t/* event mask array */ EM_%s_%s},\n\n", ss_name, sp->value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate the program parameter list */
|
||||
gen_prog_params()
|
||||
{
|
||||
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("struct seqProgram %s = {\n", prog_name);
|
||||
|
||||
printf("\t/* magic number */ %d,\n", MAGIC); /* magic number */
|
||||
|
||||
printf("\t/* *name */ \"%s\",\n", prog_name);/* program name */
|
||||
|
||||
printf("\t/* *pChannels */ seqChan,\n"); /* table of db channels */
|
||||
|
||||
printf("\t/* numChans */ NUM_CHANNELS,\n"); /* number of db channels */
|
||||
|
||||
printf("\t/* *pSS */ seqSS,\n"); /* array of SS blocks */
|
||||
|
||||
printf("\t/* numSS */ NUM_SS,\n"); /* number of state sets */
|
||||
|
||||
if (reent_opt)
|
||||
printf("\t/* user variable size */ sizeof(struct UserVar),\n");
|
||||
else
|
||||
printf("\t/* user variable size */ 0,\n");
|
||||
|
||||
printf("\t/* *pParams */ prog_param,\n"); /* program parameters */
|
||||
|
||||
printf("\t/* numEvents */ NUM_EVENTS,\n"); /* number event flags */
|
||||
|
||||
printf("\t/* encoded options */ ");
|
||||
encode_options();
|
||||
|
||||
printf("\t/* exit handler */ (EXIT_FUNC) exit_handler,\n");
|
||||
|
||||
printf("};\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
encode_options()
|
||||
{
|
||||
extern int async_opt, debug_opt, reent_opt,
|
||||
newef_opt, conn_opt, vx_opt;
|
||||
|
||||
printf("(0");
|
||||
if (async_opt)
|
||||
printf(" | OPT_ASYNC");
|
||||
if (conn_opt)
|
||||
printf(" | OPT_CONN");
|
||||
if (debug_opt)
|
||||
printf(" | OPT_DEBUG");
|
||||
if (newef_opt)
|
||||
printf(" | OPT_NEWEF");
|
||||
if (reent_opt)
|
||||
printf(" | OPT_REENT");
|
||||
if (vx_opt)
|
||||
printf(" | OPT_VXWORKS");
|
||||
printf("),\n");
|
||||
|
||||
return;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
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");
|
||||
nss++;
|
||||
|
||||
printf("\t/* State set \"%s\" */ {\n", ssp->value);
|
||||
|
||||
printf("\t/* ss name */ \"%s\",\n", ssp->value);
|
||||
|
||||
printf("\t/* ptr to state block */ state_%s,\n", ssp->value);
|
||||
|
||||
nstates = exprCount(ssp->left);
|
||||
printf("\t/* number of states */ %d,\n", nstates, ssp->value);
|
||||
|
||||
printf("\t/* error state */ %d},\n", find_error_state(ssp));
|
||||
|
||||
}
|
||||
printf("};\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the state named "error" in a state set */
|
||||
find_error_state(ssp)
|
||||
Expr *ssp;
|
||||
{
|
||||
Expr *sp;
|
||||
int error_state;
|
||||
for (sp = ssp->left, error_state = 0; sp != 0; sp = sp->next, error_state++)
|
||||
{
|
||||
if (strcmp(sp->value, "error") == 0)
|
||||
return error_state;
|
||||
}
|
||||
return -1; /* no state named "error" in this state set */
|
||||
}
|
||||
|
||||
/* Evaluate composite event mask for a single state */
|
||||
eval_state_event_mask(sp, pEventWords, numEventWords)
|
||||
Expr *sp;
|
||||
bitMask *pEventWords;
|
||||
int numEventWords;
|
||||
{
|
||||
int n;
|
||||
int eval_event_mask(), eval_event_mask_subscr();
|
||||
Expr *tp;
|
||||
|
||||
/* 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;
|
||||
|
||||
for (tp = sp->left; tp != 0; tp = tp->next)
|
||||
{
|
||||
/* 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 (when() statement).
|
||||
* Called from traverseExprTree() when ep->type==E_VAR.
|
||||
*/
|
||||
eval_event_mask(ep, pEventWords)
|
||||
Expr *ep;
|
||||
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_event_mask: %s, ef_num=%d\n",
|
||||
vp->name, vp->ef_num);
|
||||
#endif /*DEBUG*/
|
||||
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 /*DEBUG*/
|
||||
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 /*DEBUG*/
|
||||
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 /*DEBUG*/
|
||||
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 /*DEBUG*/
|
||||
for (n = 0; n < vp->length1; n++)
|
||||
{
|
||||
bitSet(pEventWords, cp->index + n + num_events + 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Count the number of linked expressions */
|
||||
exprCount(ep)
|
||||
Expr *ep;
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; ep != 0; ep = ep->next)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# makeSeqVersion - create the sequencer version module
|
||||
#
|
||||
VERSION=`cat $1`
|
||||
DATE=`date`
|
||||
echo '/* seqVersion.c - version & date */'
|
||||
echo '/* Created by makeVersion */'
|
||||
echo 'char *seqVersion = "@(#)SEQ Version '${VERSION}': '${DATE}'";'
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# makeVersion - create the snc version module
|
||||
#
|
||||
|
||||
VERSION=`cat $1`
|
||||
DATE=`date`
|
||||
echo '/* sncVersion.c - version & date */'
|
||||
echo '/* Created by makeVersion */'
|
||||
echo 'char *sncVersion = "@(#)SNC Version '${VERSION}': '${DATE}'";'
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# makeVersion - create the snc version module
|
||||
#
|
||||
# Usage: perl makeVersion.pl {Version_file} {Symbol Name}
|
||||
|
||||
$version_file = $ARGV[0];
|
||||
$symbol = $ARGV[1];
|
||||
$out = "$symbol.c";
|
||||
|
||||
open IN, $version_file or die "Cannot open $version_file";
|
||||
$version=<IN>;
|
||||
chomp $version;
|
||||
close IN;
|
||||
|
||||
$date = localtime();
|
||||
|
||||
open OUT, ">$out" or die "Cannot create $out";
|
||||
print OUT "/* $out - version & date */\n";
|
||||
print OUT "/* Created by makeVersion.pl */\n";
|
||||
print OUT "char *$symbol = \"\@(#)SNC/SEQ Version $version : $date\";\n";
|
||||
close OUT;
|
||||
@@ -1,726 +0,0 @@
|
||||
/*#define DEBUG 1*/
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
< 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.
|
||||
|
||||
ENVIRONMENT: UNIX
|
||||
HISTORY:
|
||||
19nov91,ajk Replaced lstLib calls with built-in links.
|
||||
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 ====================*/
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "parse.h" /* defines linked list structures */
|
||||
#include <math.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif /*TRUE*/
|
||||
|
||||
int debug_print_opt = 0; /* Debug level (set by source file) */
|
||||
|
||||
char *prog_name; /* ptr to program name (string) */
|
||||
|
||||
char *prog_param; /* parameter string for program stmt */
|
||||
|
||||
Expr *defn_c_list; /* definition C code list */
|
||||
|
||||
Expr *ss_list; /* Start of state set list */
|
||||
|
||||
Expr *exit_code_list; /* Start of exit code list */
|
||||
|
||||
Var *var_list = NULL; /* start of variable list */
|
||||
Var *var_tail = NULL; /* tail of variable list */
|
||||
|
||||
Chan *chan_list = NULL; /* start of DB channel list */
|
||||
Chan *chan_tail = NULL; /* tail of DB channel list */
|
||||
|
||||
Expr *global_c_list; /* global C code following state program */
|
||||
|
||||
/*+************************************************************************
|
||||
* NAME: program_name
|
||||
*
|
||||
* CALLING SEQUENCE: none
|
||||
* type argument I/O description
|
||||
* -----------------------------------------------------------------
|
||||
* char *pname I ptr to program name string
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* FUNCTION: Save program name for global use.
|
||||
*
|
||||
*-*************************************************************************/
|
||||
program_name(pname, pparam)
|
||||
char *pname, *pparam;
|
||||
{
|
||||
prog_name = pname;
|
||||
prog_param = pparam;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "program name = %s\n", prog_name);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parsing a declaration statement */
|
||||
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_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 length1, length2;
|
||||
extern int line_num;
|
||||
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
if (vp != 0)
|
||||
{
|
||||
fprintf(stderr, "variable %s already declared, line %d\n",
|
||||
name, line_num);
|
||||
return;
|
||||
}
|
||||
/* Build a struct for this variable */
|
||||
vp = allocVar();
|
||||
addVar(vp); /* add to var list */
|
||||
vp->name = name;
|
||||
vp->class = class;
|
||||
vp->type = type;
|
||||
vp->length1 = length1;
|
||||
vp->length2 = length2;
|
||||
vp->value = value; /* initial value or NULL */
|
||||
vp->chan = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Option statement */
|
||||
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, vx_opt, newef_opt;
|
||||
|
||||
switch(*option)
|
||||
{
|
||||
case 'a':
|
||||
async_opt = value;
|
||||
break;
|
||||
case 'c':
|
||||
conn_opt = value;
|
||||
break;
|
||||
case 'd':
|
||||
debug_opt = value;
|
||||
break;
|
||||
case 'e':
|
||||
newef_opt = value;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
line_opt = value;
|
||||
break;
|
||||
case 'r':
|
||||
reent_opt = value;
|
||||
break;
|
||||
case 'w':
|
||||
warn_opt = value;
|
||||
break;
|
||||
case 'v':
|
||||
vx_opt = value;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* "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 %s to \"%s\";\n", name, 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* "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;
|
||||
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 = vp->chan;
|
||||
if (cp == 0)
|
||||
{
|
||||
fprintf(stderr, "monitor: variable %s not assigned, line %d\n",
|
||||
name, line_num);
|
||||
return;
|
||||
}
|
||||
|
||||
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, subscript, ef_name)
|
||||
char *name;
|
||||
char *subscript;
|
||||
char *ef_name;
|
||||
{
|
||||
Chan *cp;
|
||||
Var *vp;
|
||||
extern int line_num;
|
||||
int subNum;
|
||||
|
||||
#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",
|
||||
name, line_num);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the event flag varible */
|
||||
vp = (Var *)findVar(ef_name);
|
||||
if (vp == 0 || vp->type != V_EVFLAG)
|
||||
{
|
||||
fprintf(stderr, "sync: e-f variable %s not declared, line %d\n",
|
||||
ef_name, line_num);
|
||||
return;
|
||||
}
|
||||
|
||||
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_list)
|
||||
Expr *c_list; /* ptr to C code */
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "defn_c_stmt\n");
|
||||
#endif
|
||||
if (defn_c_list == 0)
|
||||
defn_c_list = c_list;
|
||||
else
|
||||
link_expr(defn_c_list, c_list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Global C code (follows state program) */
|
||||
global_c_stmt(c_list)
|
||||
Expr *c_list; /* ptr to C code */
|
||||
{
|
||||
global_c_list = c_list;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Add a variable to the variable linked list */
|
||||
addVar(vp)
|
||||
Var *vp;
|
||||
{
|
||||
if (var_list == NULL)
|
||||
var_list = vp;
|
||||
else
|
||||
var_tail->next = vp;
|
||||
var_tail = vp;
|
||||
vp->next = NULL;
|
||||
}
|
||||
|
||||
/* Find a variable by name; returns a pointer to the Var struct;
|
||||
returns 0 if the variable is not found. */
|
||||
Var *findVar(name)
|
||||
char *name;
|
||||
{
|
||||
Var *vp;
|
||||
|
||||
for (vp = var_list; vp != NULL; vp = vp->next)
|
||||
{
|
||||
if (strcmp(vp->name, name) == 0)
|
||||
{
|
||||
return vp;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add a channel to the channel linked list */
|
||||
addChan(cp)
|
||||
Chan *cp;
|
||||
{
|
||||
if (chan_list == NULL)
|
||||
chan_list = cp;
|
||||
else
|
||||
chan_tail->next = cp;
|
||||
chan_tail = cp;
|
||||
cp->next = NULL;
|
||||
}
|
||||
|
||||
/* Set debug print opt */
|
||||
set_debug_print(opt)
|
||||
char *opt;
|
||||
{
|
||||
debug_print_opt = atoi(opt);
|
||||
}
|
||||
|
||||
/* Parsing "program" statement */
|
||||
program(prog_list)
|
||||
Expr *prog_list;
|
||||
{
|
||||
ss_list = prog_list;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "----Phase2---\n");
|
||||
#endif /*DEBUG*/
|
||||
phase2(ss_list);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Exit code */
|
||||
exit_code(ep)
|
||||
Expr *ep;
|
||||
{
|
||||
exit_code_list = ep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build an expression list (hierarchical):
|
||||
Builds a node on a binary tree for each expression primitive.
|
||||
*/
|
||||
Expr *expression(type, value, left, right)
|
||||
int type; /* E_BINOP, E_ASGNOP, etc */
|
||||
char *value; /* "==", "+=", var name, contstant, etc. */
|
||||
Expr *left; /* LH side */
|
||||
Expr *right; /* RH side */
|
||||
{
|
||||
Expr *ep;
|
||||
extern int line_num, c_line_num;
|
||||
extern char *src_file;
|
||||
#ifdef DEBUG
|
||||
extern char *stype[];
|
||||
#endif
|
||||
/* Allocate a structure for this item or expression */
|
||||
ep = allocExpr();
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"expression: ep=%d, type=%s, value=\"%s\", left=%d, right=%d\n",
|
||||
ep, stype[type], value, left, right);
|
||||
#endif
|
||||
/* Fill in the structure */
|
||||
ep->next = (Expr *)0;
|
||||
ep->last = ep;
|
||||
ep->type = type;
|
||||
ep->value = value;
|
||||
ep->left = left;
|
||||
ep->right = right;
|
||||
if (type == E_TEXT)
|
||||
ep->line_num = c_line_num;
|
||||
else
|
||||
ep->line_num = line_num;
|
||||
ep->src_file = src_file;
|
||||
|
||||
return ep;
|
||||
}
|
||||
|
||||
/* Link two expression structures and/or lists. Returns ptr to combined list.
|
||||
Note: ->last ptrs are correct only for 1-st and last structures in the list */
|
||||
Expr *link_expr(ep1, ep2)
|
||||
Expr *ep1; /* beginning of 1-st structure or list */
|
||||
Expr *ep2; /* beginning 2-nd (append it to 1-st) */
|
||||
{
|
||||
Expr *ep;
|
||||
|
||||
if (ep1 == 0)
|
||||
return ep2; /* shouldn't happen */
|
||||
else if (ep2 == 0)
|
||||
return ep1;
|
||||
|
||||
(ep1->last)->next = ep2;
|
||||
ep1->last = ep2->last;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "link_expr(");
|
||||
for (ep = ep1; ; ep = ep->next)
|
||||
{
|
||||
fprintf(stderr, "%d, ", ep);
|
||||
if (ep == ep1->last)
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, ")\n");
|
||||
#endif /*DEBUG*/
|
||||
return ep1;
|
||||
}
|
||||
|
||||
/* Interpret pre-processor code */
|
||||
pp_code(line, fname)
|
||||
char *line;
|
||||
char *fname;
|
||||
{
|
||||
extern int line_num;
|
||||
extern char *src_file;
|
||||
|
||||
line_num = atoi(line);
|
||||
src_file = fname;
|
||||
}
|
||||
|
||||
/* The ordering of this list must correspond with the ordering in parse.h */
|
||||
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_FOR", "E_X", "E_PRE", "E_POST", "E_BREAK", "E_COMMA",
|
||||
"E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?" };
|
||||
@@ -1,125 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1989-93, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
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
|
||||
** for the sequencer. This decouples the parsing implementation from
|
||||
** the run-time code implementation.
|
||||
*/
|
||||
|
||||
struct expression /* Expression block */
|
||||
{
|
||||
struct expression *next; /* link to next expression */
|
||||
struct expression *last; /* link to last in list */
|
||||
struct expression *left; /* ptr to left expression */
|
||||
struct expression *right; /* ptr to right expression */
|
||||
int type; /* expression type (E_*) */
|
||||
char *value; /* operator or value string */
|
||||
int line_num; /* line number */
|
||||
char *src_file; /* effective source file */
|
||||
};
|
||||
typedef struct expression Expr;
|
||||
|
||||
struct var /* Variable or function definition */
|
||||
{
|
||||
struct var *next; /* link to next item in list */
|
||||
char *name; /* variable name */
|
||||
char *value; /* initial value or NULL */
|
||||
int type; /* var type */
|
||||
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 assignment info */
|
||||
{
|
||||
struct db_chan *next; /* link to next item in list */
|
||||
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 */
|
||||
int count; /* count for db access */
|
||||
int mon_flag; /* TRUE if channel is "monitored" */
|
||||
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 *)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 */
|
||||
#define V_LONG 4 /* long */
|
||||
#define V_FLOAT 5 /* float */
|
||||
#define V_DOUBLE 6 /* double */
|
||||
#define V_STRING 7 /* strings (array of char) */
|
||||
#define V_EVFLAG 8 /* event flag */
|
||||
#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 */
|
||||
#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 */
|
||||
#define E_VAR 2 /* variable */
|
||||
#define E_FUNC 3 /* function */
|
||||
#define E_STRING 4 /* ptr to string consatant */
|
||||
#define E_UNOP 5 /* unary operator: OP expr (-, +, or !) */
|
||||
#define E_BINOP 6 /* binary operator: expr OP expr */
|
||||
#define E_ASGNOP 7 /* assign operatro: (=, +=, *=, etc.) */
|
||||
#define E_PAREN 8 /* parenthesis around an expression */
|
||||
#define E_SUBSCR 9 /* subscript */
|
||||
#define E_TEXT 10 /* C code or other text to be inserted */
|
||||
#define E_STMT 11 /* simple statement */
|
||||
#define E_CMPND 12 /* begin compound statement: {...} */
|
||||
#define E_IF 13 /* if statement */
|
||||
#define E_ELSE 14 /* if statement */
|
||||
#define E_WHILE 15 /* while statement */
|
||||
#define E_SS 16 /* state set statement */
|
||||
#define E_STATE 17 /* state statement */
|
||||
#define E_WHEN 18 /* when statement */
|
||||
#define E_FOR 19 /* for statement */
|
||||
#define E_X 20 /* eXpansion (e.g. for(;;) */
|
||||
#define E_PRE 21 /* ++expr or --expr */
|
||||
#define E_POST 22 /* expr++ or expr-- */
|
||||
#define E_BREAK 23 /* break stmt */
|
||||
#define E_COMMA 24 /* expr , expr */
|
||||
@@ -1,555 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
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 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.
|
||||
13jan98,wfl Supported E_COMMA token (for compound expressions).
|
||||
09mar98,wfl Avoided compilation warnings under Tornado
|
||||
01oct98,wfl Supported setting initial value on declaration.
|
||||
***************************************************************************/
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "parse.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 */
|
||||
|
||||
/*+************************************************************************
|
||||
* NAME: phase2
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* ---------------------------------------------------
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Generate C code from parsing lists.
|
||||
*
|
||||
* NOTES: All inputs are external globals.
|
||||
*-*************************************************************************/
|
||||
phase2()
|
||||
{
|
||||
extern Var *var_list; /* variables (from parse) */
|
||||
extern Expr *ss_list; /* state sets (from parse) */
|
||||
extern Expr *global_c_list; /* global C code */
|
||||
|
||||
/* Count number of db channels and state sets defined */
|
||||
num_channels = db_chan_count();
|
||||
num_ss = exprCount(ss_list);
|
||||
|
||||
/* Reconcile all variable and tie each to the appropriate VAR struct */
|
||||
reconcile_variables();
|
||||
|
||||
/* 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();
|
||||
|
||||
/* Generate variable declarations */
|
||||
gen_var_decl();
|
||||
|
||||
/* Generate definition C code */
|
||||
gen_defn_c_code();
|
||||
|
||||
/* Generate code for each state set */
|
||||
gen_ss_code();
|
||||
|
||||
/* Generate tables */
|
||||
gen_tables();
|
||||
|
||||
/* Output global C code */
|
||||
gen_global_c_code();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
/* Generate preamble (includes, defines, etc.) */
|
||||
gen_preamble()
|
||||
{
|
||||
extern char *prog_name;
|
||||
extern int async_opt, conn_opt, debug_opt, reent_opt;
|
||||
|
||||
/* Program name (comment) */
|
||||
printf("/* Program \"%s\" */\n", prog_name);
|
||||
|
||||
/* Include files */
|
||||
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");
|
||||
gen_opt_defn(conn_opt, "CONN_OPT" );
|
||||
gen_opt_defn(debug_opt, "DEBUG_OPT");
|
||||
gen_opt_defn(reent_opt, "REENT_OPT");
|
||||
printf("\n");
|
||||
|
||||
/* Forward references of tables: */
|
||||
printf("\nextern struct seqProgram %s;\n", prog_name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate defines for compiler options */
|
||||
gen_opt_defn(opt, defn_name)
|
||||
int opt;
|
||||
char *defn_name;
|
||||
{
|
||||
if (opt)
|
||||
printf("#define %s TRUE\n", defn_name);
|
||||
else
|
||||
printf("#define %s FALSE\n", defn_name);
|
||||
}
|
||||
|
||||
/* Reconcile all variables in an expression,
|
||||
* and tie each to the appropriate VAR structure.
|
||||
*/
|
||||
int printTree = FALSE; /* For debugging only */
|
||||
|
||||
reconcile_variables()
|
||||
{
|
||||
extern Expr *ss_list, *exit_code_list;
|
||||
Expr *ssp, *ep;
|
||||
int connect_variable();
|
||||
|
||||
for (ssp = ss_list; ssp != 0; ssp = ssp->next)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "reconcile_variables: ss=%s\n", ssp->value);
|
||||
#endif /*DEBUG*/
|
||||
traverseExprTree(ssp, E_VAR, 0, connect_variable, 0);
|
||||
}
|
||||
|
||||
/* Same for exit procedure */
|
||||
for (ep = exit_code_list; ep != 0; ep = ep->next)
|
||||
{
|
||||
traverseExprTree(ep, E_VAR, 0, connect_variable, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Connect a variable in an expression to the the Var structure */
|
||||
int connect_variable(ep)
|
||||
Expr *ep;
|
||||
{
|
||||
Var *vp;
|
||||
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 */
|
||||
if (warn_opt)
|
||||
fprintf(stderr,
|
||||
"Warning: variable \"%s\" is used but not declared.\n",
|
||||
ep->value);
|
||||
vp = allocVar();
|
||||
addVar(vp);
|
||||
vp->name = ep->value;
|
||||
vp->type = V_NONE; /* undeclared type */
|
||||
vp->length1 = 1;
|
||||
vp->length2 = 1;
|
||||
vp->value = 0;
|
||||
}
|
||||
ep->left = (Expr *)vp; /* make connection */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reconcile state names */
|
||||
reconcile_states()
|
||||
{
|
||||
|
||||
extern Expr *ss_list;
|
||||
|
||||
extern int num_errors;
|
||||
Expr *ssp, *sp, *sp1, tr;
|
||||
|
||||
for (ssp = ss_list; ssp != 0; ssp = ssp->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)
|
||||
{
|
||||
if (strcmp(sp->value, sp1->value) == 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"State \"%s\" is duplicated in state set \"%s\"\n",
|
||||
sp->value, ssp->value);
|
||||
num_errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find a state by name */
|
||||
Expr *find_state(name, sp)
|
||||
char *name; /* state name */
|
||||
Expr *sp; /* beginning of state list */
|
||||
{
|
||||
while (sp != 0)
|
||||
{
|
||||
if (strcmp(name, sp->value) == 0)
|
||||
return sp;
|
||||
sp = sp->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Generate a C variable declaration for each variable declared in SNL */
|
||||
gen_var_decl()
|
||||
{
|
||||
extern Var *var_list;
|
||||
Var *vp;
|
||||
char *vstr;
|
||||
int nv;
|
||||
extern int reent_opt;
|
||||
|
||||
printf("\n/* Variable declarations */\n");
|
||||
|
||||
/* Convert internal type to `C' type */
|
||||
if (reent_opt)
|
||||
printf("struct UserVar {\n");
|
||||
for (nv=0, vp = var_list; vp != NULL; nv++, vp = vp->next)
|
||||
{
|
||||
switch (vp->type)
|
||||
{
|
||||
case V_CHAR:
|
||||
vstr = "char";
|
||||
break;
|
||||
case V_INT:
|
||||
vstr = "int";
|
||||
break;
|
||||
case V_LONG:
|
||||
vstr = "long";
|
||||
break;
|
||||
case V_SHORT:
|
||||
vstr = "short";
|
||||
break;
|
||||
case V_UCHAR:
|
||||
vstr = "unsigned char";
|
||||
break;
|
||||
case V_UINT:
|
||||
vstr = "unsigned int";
|
||||
break;
|
||||
case V_ULONG:
|
||||
vstr = "unsigned long";
|
||||
break;
|
||||
case V_USHORT:
|
||||
vstr = "unsigned short";
|
||||
break;
|
||||
case V_FLOAT:
|
||||
vstr = "float";
|
||||
break;
|
||||
case V_DOUBLE:
|
||||
vstr = "double";
|
||||
break;
|
||||
case V_STRING:
|
||||
vstr = "char";
|
||||
break;
|
||||
case V_EVFLAG:
|
||||
case V_NONE:
|
||||
vstr = NULL;
|
||||
break;
|
||||
default:
|
||||
vstr = "int";
|
||||
break;
|
||||
}
|
||||
if (vstr == NULL)
|
||||
continue;
|
||||
|
||||
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]");
|
||||
|
||||
if (vp->value != NULL)
|
||||
printf(" = %s", vp->value);
|
||||
|
||||
printf(";\n");
|
||||
}
|
||||
if (reent_opt)
|
||||
printf("};\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate definition C code (C code in definition section) */
|
||||
gen_defn_c_code()
|
||||
{
|
||||
extern Expr *defn_c_list;
|
||||
Expr *ep;
|
||||
|
||||
ep = defn_c_list;
|
||||
if (ep != NULL)
|
||||
{
|
||||
printf("\n\t/* C code definitions */\n");
|
||||
for (; ep != NULL; ep = ep->next)
|
||||
{
|
||||
print_line_num(ep->line_num, ep->src_file);
|
||||
printf("%s\n", ep->left);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Generate global C code (C code following state program) */
|
||||
gen_global_c_code()
|
||||
{
|
||||
extern Expr *global_c_list;
|
||||
Expr *ep;
|
||||
|
||||
ep = global_c_list;
|
||||
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)
|
||||
{
|
||||
printf("%s\n", ep->left);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sets cp->index for each variable, & returns number of db channels defined.
|
||||
*/
|
||||
db_chan_count()
|
||||
{
|
||||
extern Chan *chan_list;
|
||||
int nchan;
|
||||
Chan *cp;
|
||||
|
||||
nchan = 0;
|
||||
for (cp = chan_list; cp != NULL; cp = cp->next)
|
||||
{
|
||||
cp->index = nchan;
|
||||
if (cp->num_elem == 0)
|
||||
nchan += 1;
|
||||
else
|
||||
nchan += cp->num_elem; /* array with multiple channels */
|
||||
}
|
||||
|
||||
return nchan;
|
||||
}
|
||||
|
||||
|
||||
/* Assign event bits to event flags and associate db channels with
|
||||
* event flags.
|
||||
*/
|
||||
assign_ef_bits()
|
||||
{
|
||||
extern Var *var_list;
|
||||
extern Chan *chan_list;
|
||||
Var *vp;
|
||||
Chan *cp;
|
||||
extern int num_events;
|
||||
int n;
|
||||
|
||||
/* Assign event flag numbers (starting at 1) */
|
||||
printf("\n/* Event flags */\n");
|
||||
num_events = 0;
|
||||
for (vp = var_list; vp != NULL; vp = vp->next)
|
||||
{
|
||||
if (vp->type == V_EVFLAG)
|
||||
{
|
||||
num_events++;
|
||||
vp->ef_num = num_events;
|
||||
printf("#define %s\t%d\n", vp->name, num_events);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Assign a delay id to each "delay()" in an event (when()) expression */
|
||||
assign_delay_ids()
|
||||
{
|
||||
extern Expr *ss_list;
|
||||
Expr *ssp, *sp, *tp;
|
||||
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)
|
||||
{
|
||||
/* Each state has it's own delay id's */
|
||||
delay_id = 0;
|
||||
for (tp = sp->left; tp != 0; tp = tp->next)
|
||||
{ /* traverse event expression only */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assign_next_delay_id(ep, delay_id)
|
||||
Expr *ep;
|
||||
int *delay_id;
|
||||
{
|
||||
ep->right = (Expr *)*delay_id;
|
||||
*delay_id += 1;
|
||||
}
|
||||
/* 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 */
|
||||
char *value; /* with optional matching value */
|
||||
void (*funcp)(); /* function to call */
|
||||
void *argp; /* ptr to argument to pass on to function */
|
||||
{
|
||||
Expr *ep1;
|
||||
extern char *stype[];
|
||||
|
||||
if (ep == 0)
|
||||
return;
|
||||
|
||||
if (printTree)
|
||||
fprintf(stderr, "traverseExprTree: type=%s, value=%s\n",
|
||||
stype[ep->type], ep->value);
|
||||
|
||||
/* Call the function? */
|
||||
if ((ep->type == type) && (value == 0 || strcmp(ep->value, value) == 0) )
|
||||
{
|
||||
funcp(ep, argp);
|
||||
}
|
||||
|
||||
/* Continue traversing the expression tree */
|
||||
switch(ep->type)
|
||||
{
|
||||
case E_VAR:
|
||||
case E_CONST:
|
||||
case E_STRING:
|
||||
case E_TEXT:
|
||||
case E_BREAK:
|
||||
break;
|
||||
|
||||
case E_PAREN:
|
||||
case E_UNOP:
|
||||
case E_SS:
|
||||
case E_STATE:
|
||||
case E_FUNC:
|
||||
case E_COMMA:
|
||||
case E_CMPND:
|
||||
case E_STMT:
|
||||
case E_ELSE:
|
||||
case E_PRE:
|
||||
case E_POST:
|
||||
for (ep1 = ep->left; ep1 != 0; ep1 = ep1->next)
|
||||
{
|
||||
traverseExprTree(ep1, type, value, funcp, argp);
|
||||
}
|
||||
break;
|
||||
|
||||
case E_WHEN:
|
||||
case E_ASGNOP:
|
||||
case E_BINOP:
|
||||
case E_SUBSCR:
|
||||
case E_IF:
|
||||
case E_WHILE:
|
||||
case E_FOR:
|
||||
case E_X:
|
||||
for (ep1 = ep->left; ep1 != 0; ep1 = ep1->next)
|
||||
{
|
||||
traverseExprTree(ep1, type, value, funcp, argp);
|
||||
}
|
||||
for (ep1 = ep->right; ep1 != 0; ep1 = ep1->next)
|
||||
{
|
||||
traverseExprTree(ep1, type, value, funcp, argp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "traverseExprTree: type=%d???\n", ep->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/* /share/epicsH %W% %G%
|
||||
*
|
||||
* DESCRIPTION: Definitions for the run-time sequencer.
|
||||
*
|
||||
* Author: Andy Kozubal
|
||||
* Date:
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991,2,3, 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:
|
||||
* -----------------
|
||||
* 07mar91,ajk Changed SSCB semaphore id names.
|
||||
* 05jul91,ajk Added function prototypes.
|
||||
* 16dec91,ajk Setting up for VxWorks version 5.
|
||||
* 27apr92,ajk Changed to new event flag mode (SSCB & PROG changed).
|
||||
* 27apr92,ajk Removed getSemId from CHAN.
|
||||
* 28apr92,ajk Implemented new event flag mode.
|
||||
* 17feb93,ajk Fixed some functions prototypes.
|
||||
* 10jun93,ajk Removed VxWorks V4/V5 conditional compile.
|
||||
* 20jul93,ajk Removed non-ANSI function definitions.
|
||||
* 21mar94,ajk Implemented new i/f with snc (see seqCom.h).
|
||||
* 21mar94,ajk Implemented assignment of array elements to db. Also,
|
||||
allow "unlimited" number of channels.
|
||||
* 28mar94,ajk Added time stamp support.
|
||||
* 29mar94,ajk Added dbOffset in db_channel structure; allows faster processing
|
||||
of values returned with monitors and pvGet().
|
||||
*/
|
||||
#ifndef INCLseqh
|
||||
#define INCLseqh
|
||||
|
||||
#ifndef TRUE
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "seqCom.h"
|
||||
|
||||
#ifndef VOID
|
||||
#include "cadef.h"
|
||||
#include "db_access.h"
|
||||
#include "alarm.h"
|
||||
#include "vxWorks.h"
|
||||
#include "ioLib.h"
|
||||
#include "semLib.h"
|
||||
#include "taskLib.h"
|
||||
#endif
|
||||
|
||||
/* Structure to hold information about database channels */
|
||||
struct db_channel
|
||||
{
|
||||
/* These are supplied by SNC */
|
||||
char *dbAsName; /* channel name from assign statement */
|
||||
char *pVar; /* ptr to variable */
|
||||
char *pVarName; /* variable name string */
|
||||
char *pVarType; /* variable type string (e.g. ("int") */
|
||||
long count; /* number of elements in array */
|
||||
long efId; /* event flag id if synced */
|
||||
long eventNum; /* event number */
|
||||
BOOL monFlag; /* TRUE if channel is to be monitored */
|
||||
|
||||
/* These are filled in at run time */
|
||||
char *dbName; /* channel name after macro expansion */
|
||||
long index; /* index in array of db channels */
|
||||
chid chid; /* ptr to channel id (from ca_search()) */
|
||||
BOOL assigned; /* TRUE only if channel is assigned */
|
||||
BOOL connected; /* TRUE only if channel is connected */
|
||||
BOOL getComplete; /* TRUE if previous pvGet completed */
|
||||
short dbOffset; /* Offset to value in db access structure */
|
||||
short status; /* last db access status code */
|
||||
TS_STAMP timeStamp; /* time stamp */
|
||||
long dbCount; /* actual count for db access */
|
||||
short severity; /* last db access severity code */
|
||||
short size; /* size (in bytes) of single variable element */
|
||||
short getType; /* db get type (e.g. DBR_STS_INT) */
|
||||
short putType; /* db put type (e.g. DBR_INT) */
|
||||
BOOL monitored; /* TRUE if channel IS monitored */
|
||||
evid evid; /* event id (supplied by CA) */
|
||||
SEM_ID getSemId; /* semaphore id for async get */
|
||||
struct state_program *sprog; /* state program that owns this structure */
|
||||
};
|
||||
typedef struct db_channel CHAN;
|
||||
|
||||
/* Structure to hold information about a state */
|
||||
struct state_info_block
|
||||
{
|
||||
char *pStateName; /* state name */
|
||||
ACTION_FUNC actionFunc; /* ptr to action routine for this state */
|
||||
EVENT_FUNC eventFunc; /* ptr to event routine for this state */
|
||||
DELAY_FUNC delayFunc; /* ptr to delay setup routine for this state */
|
||||
bitMask *pEventMask; /* event mask for this state */
|
||||
};
|
||||
typedef struct state_info_block STATE;
|
||||
|
||||
#define MAX_NDELAY 20 /* max # delays allowed in each SS */
|
||||
/* Structure to hold information about a State Set */
|
||||
struct state_set_control_block
|
||||
{
|
||||
char *pSSName; /* state set name (for debugging) */
|
||||
long taskId; /* task id */
|
||||
long taskPriority; /* task priority */
|
||||
SEM_ID syncSemId; /* semaphore for event sync */
|
||||
SEM_ID getSemId; /* semaphore for synchronous pvGet() */
|
||||
long numStates; /* number of states */
|
||||
STATE *pStates; /* ptr to array of state blocks */
|
||||
short currentState; /* current state index */
|
||||
short nextState; /* next state index */
|
||||
short prevState; /* previous state index */
|
||||
short errorState; /* error state index (-1 if none defined) */
|
||||
short transNum; /* highest priority trans. # that triggered */
|
||||
bitMask *pMask; /* current event mask */
|
||||
long numDelays; /* number of delays activated */
|
||||
ULONG delay[MAX_NDELAY]; /* queued delay value in tics */
|
||||
BOOL delayExpired[MAX_NDELAY]; /* TRUE if delay expired */
|
||||
ULONG timeEntered; /* time that a state was entered */
|
||||
struct state_program *sprog; /* ptr back to state program block */
|
||||
};
|
||||
typedef struct state_set_control_block SSCB;
|
||||
|
||||
/* Macro table */
|
||||
typedef struct macro {
|
||||
char *pName;
|
||||
char *pValue;
|
||||
} MACRO;
|
||||
|
||||
/* All information about a state program.
|
||||
The address of this structure is passed to the run-time sequencer:
|
||||
*/
|
||||
struct state_program
|
||||
{
|
||||
char *pProgName; /* program name (for debugging) */
|
||||
long taskId; /* task id (main task) */
|
||||
BOOL task_is_deleted;/* TRUE if main task has been deleted */
|
||||
long taskPriority; /* task priority */
|
||||
SEM_ID caSemId; /* semiphore for locking CA events */
|
||||
CHAN *pChan; /* table of channels */
|
||||
long numChans; /* number of db channels, incl. unassigned */
|
||||
long assignCount; /* number of db channels assigned */
|
||||
long connCount; /* number of channels connected */
|
||||
SSCB *pSS; /* array of state set control blocks */
|
||||
long numSS; /* number of state sets */
|
||||
char *pVar; /* ptr to user variable area */
|
||||
long varSize; /* # bytes in user variable area */
|
||||
MACRO *pMacros; /* ptr to macro table */
|
||||
char *pParams; /* program paramters */
|
||||
bitMask *pEvents; /* event bits for event flags & db */
|
||||
long numEvents; /* number of events */
|
||||
long options; /* options (bit-encoded) */
|
||||
EXIT_FUNC exitFunc; /* exit function */
|
||||
SEM_ID logSemId; /* logfile locking semaphore */
|
||||
long logFd; /* logfile file descr. */
|
||||
};
|
||||
typedef struct state_program SPROG;
|
||||
|
||||
#define MAX_MACROS 50
|
||||
|
||||
/* Task parameters */
|
||||
#define SPAWN_STACK_SIZE 10000
|
||||
#define SPAWN_OPTIONS VX_DEALLOC_STACK | VX_FP_TASK | VX_STDIO
|
||||
#define SPAWN_PRIORITY 100
|
||||
|
||||
/* Function declarations for internal sequencer funtions */
|
||||
long seqConnect (SPROG *);
|
||||
VOID seqEventHandler (struct event_handler_args);
|
||||
VOID seqConnHandler (struct connection_handler_args);
|
||||
VOID seqCallbackHandler(struct event_handler_args);
|
||||
VOID seqWakeup (SPROG *, long);
|
||||
long seq (struct seqProgram *, char *, long);
|
||||
VOID seqFree (SPROG *);
|
||||
long sequencer (SPROG *, long, char *);
|
||||
VOID ssEntry (SPROG *, SSCB *);
|
||||
long sprogDelete (long);
|
||||
long seqMacParse (char *, SPROG *);
|
||||
char *seqMacValGet (MACRO *, char *);
|
||||
VOID seqMacEval (char *, char *, long, MACRO *);
|
||||
STATUS seq_log ();
|
||||
SPROG *seqFindProg (long);
|
||||
|
||||
#endif /*INCLseqh*/
|
||||
@@ -1,158 +0,0 @@
|
||||
/* * base/include seqCom.h,v 1.3 1995/10/10 01:25:08 wright Exp
|
||||
*
|
||||
* DESCRIPTION: Common definitions for state programs and run-time sequencer.
|
||||
*
|
||||
* Author: Andy Kozubal
|
||||
* Date: 01mar94
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1993 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
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* 11jul96,ajk Changed all int types to long.
|
||||
* 22jul96,ajk Changed PFUNC to ACTION_FUNC, EVENT_FUNC, DELAY_FUNC, & EXIT_FUNC.
|
||||
*
|
||||
*/
|
||||
#ifndef INCLseqComh
|
||||
#define INCLseqComh
|
||||
|
||||
#define MAGIC 940501 /* current magic number for SPROG */
|
||||
|
||||
#include "tsDefs.h" /* time stamp defs */
|
||||
#include "stdio.h" /* standard i/o defs */
|
||||
|
||||
/* Bit encoding for run-time options */
|
||||
#define OPT_DEBUG (1<<0) /* turn on debugging */
|
||||
#define OPT_ASYNC (1<<1) /* use async. gets */
|
||||
#define OPT_CONN (1<<2) /* wait for all connections */
|
||||
#define OPT_REENT (1<<3) /* generate reentrant code */
|
||||
#define OPT_NEWEF (1<<4) /* new event flag mode */
|
||||
#define OPT_TIME (1<<5) /* get time stamps */
|
||||
#define OPT_VXWORKS (1<<6) /* include VxWorks files */
|
||||
|
||||
/* Macros to handle set & clear event bits */
|
||||
#define NBITS 32 /* # bits in bitMask word */
|
||||
typedef long bitMask;
|
||||
|
||||
#define bitSet(word, bitnum) (word[(bitnum)/NBITS] |= (1<<((bitnum)%NBITS)))
|
||||
#define bitClear(word, bitnum) (word[(bitnum)/NBITS] &= ~(1<<((bitnum)%NBITS)))
|
||||
#define bitTest(word, bitnum) ((word[(bitnum)/NBITS] & (1<<((bitnum)%NBITS))) != 0)
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif /*TRUE*/
|
||||
|
||||
typedef long SS_ID; /* state set id */
|
||||
|
||||
/* Prototype for action, event, delay, and exit functions */
|
||||
typedef long (*PFUNC)();
|
||||
typedef void (*ACTION_FUNC)();
|
||||
typedef long (*EVENT_FUNC)();
|
||||
typedef void (*DELAY_FUNC)();
|
||||
typedef void (*EXIT_FUNC)();
|
||||
|
||||
#ifdef OFFSET
|
||||
#undef OFFSET
|
||||
#endif
|
||||
/* The OFFSET macro calculates the byte offset of a structure member
|
||||
* from the start of a structure */
|
||||
#define OFFSET(structure, member) ((long) &(((structure *) 0) -> member))
|
||||
|
||||
/* Structure to hold information about database channels */
|
||||
struct seqChan
|
||||
{
|
||||
char *dbAsName; /* assigned channel name */
|
||||
void *pVar; /* ptr to variable (-r option)
|
||||
* or structure offset (+r option) */
|
||||
char *pVarName; /* variable name, including subscripts */
|
||||
char *pVarType; /* variable type, e.g. "int" */
|
||||
long count; /* element count for arrays */
|
||||
long eventNum; /* event number for this channel */
|
||||
long efId; /* event flag id if synced */
|
||||
long monFlag; /* TRUE if channel is to be monitored */
|
||||
};
|
||||
|
||||
/* Structure to hold information about a state */
|
||||
struct seqState
|
||||
{
|
||||
char *pStateName; /* state name */
|
||||
ACTION_FUNC actionFunc; /* action routine for this state */
|
||||
EVENT_FUNC eventFunc; /* event routine for this state */
|
||||
DELAY_FUNC delayFunc; /* delay setup routine for this state */
|
||||
bitMask *pEventMask; /* event mask for this state */
|
||||
};
|
||||
|
||||
/* Structure to hold information about a State Set */
|
||||
struct seqSS
|
||||
{
|
||||
char *pSSName; /* state set name */
|
||||
struct seqState *pStates; /* array of state blocks */
|
||||
long numStates; /* number of states in this state set */
|
||||
long errorState; /* error state index (-1 if none defined) */
|
||||
};
|
||||
|
||||
/* All information about a state program */
|
||||
struct seqProgram
|
||||
{
|
||||
long magic; /* magic number */
|
||||
char *pProgName; /* program name (for debugging) */
|
||||
struct seqChan *pChan; /* table of channels */
|
||||
long numChans; /* number of db channels */
|
||||
struct seqSS *pSS; /* array of state set info structs */
|
||||
long numSS; /* number of state sets */
|
||||
long varSize; /* # bytes in user variable area */
|
||||
char *pParams; /* program paramters */
|
||||
long numEvents; /* number of event flags */
|
||||
long options; /* options (bit-encoded) */
|
||||
EXIT_FUNC exitFunc; /* exit function */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Function declarations for interface between state program & sequencer.
|
||||
* Notes:
|
||||
* "seq_" is added by SNC to guarantee global uniqueness.
|
||||
* These functions appear in the module seq_if.c.
|
||||
* The SNC must generate these modules--see gen_ss_code.c.
|
||||
*/
|
||||
void seq_efSet(SS_ID, long); /* set an event flag */
|
||||
long seq_efTest(SS_ID, long); /* test an event flag */
|
||||
long seq_efClear(SS_ID, long); /* clear an event flag */
|
||||
long seq_efTestAndClear(SS_ID, long);/* test & clear an event flag */
|
||||
long seq_pvGet(SS_ID, long); /* get pv value */
|
||||
long seq_pvPut(SS_ID, long); /* put pv value */
|
||||
TS_STAMP seq_pvTimeStamp(SS_ID, long); /* get time stamp value */
|
||||
long seq_pvAssign(SS_ID, long, char *);/* assign/connect to a pv */
|
||||
long seq_pvMonitor(SS_ID, long); /* enable monitoring on pv */
|
||||
long seq_pvStopMonitor(SS_ID, long); /* disable monitoring on pv */
|
||||
long seq_pvStatus(SS_ID, long); /* returns pv alarm status code */
|
||||
long seq_pvSeverity(SS_ID, long); /* returns pv alarm severity */
|
||||
long seq_pvAssigned(SS_ID, long); /* returns TRUE if assigned */
|
||||
long seq_pvConnected(SS_ID, long); /* TRUE if connected */
|
||||
long seq_pvGetComplete(SS_ID, long); /* TRUE if last get completed */
|
||||
long seq_pvChannelCount(SS_ID); /* returns number of channels */
|
||||
long seq_pvConnectCount(SS_ID); /* returns number of channels connected */
|
||||
long seq_pvAssignCount(SS_ID); /* returns number of channels assigned */
|
||||
long seq_pvCount(SS_ID, long); /* returns number of elements in array */
|
||||
void seq_pvFlush(); /* flush put/get requests */
|
||||
long seq_pvIndex(SS_ID, long); /* returns index of pv */
|
||||
long seq_seqLog(); /* Logging: variable number of parameters */
|
||||
void seq_delayInit(SS_ID, long, float);/* initialize a delay entry */
|
||||
long seq_delay(SS_ID, long); /* test a delay entry */
|
||||
char *seq_macValueGet(SS_ID, char *); /* Given macro name, return ptr to value */
|
||||
long seq_optGet (SS_ID ssId, char *opt); /* check an option for TRUE/FALSE */
|
||||
|
||||
#endif /*INCLseqComh*/
|
||||
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
seq_ca.c,v 1.2 1995/06/27 15:25:54 wright Exp
|
||||
|
||||
* DESCRIPTION: Channel access interface for sequencer.
|
||||
*
|
||||
* Author: Andy Kozubal
|
||||
* Date: July, 1991
|
||||
*
|
||||
* 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:
|
||||
* -----------------
|
||||
* 03jul91,ajk .
|
||||
* 11dec91,ajk Cosmetic changes (comments & names)
|
||||
* 13feb92,ajk All seqLog() calls compile only if DEBUG is defined.
|
||||
* 28apr92,ajk Implemented new event flag mode.
|
||||
* 21may92,ajk Will periodically announce number of connected channels
|
||||
* if waiting form some to connect.
|
||||
* 17feb93,ajk Implemented code to allow sharing of a single CA task by
|
||||
* 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.
|
||||
* 17jan96,ajk Removed ca_import_cancel(), which is now in channel access lib.
|
||||
* 17jan96,ajk Many routines changed to use ANSI-style function headers.
|
||||
*/
|
||||
|
||||
#define ANSI
|
||||
#include "seq.h"
|
||||
#include "string.h"
|
||||
#include "taskVarLib.h"
|
||||
|
||||
LOCAL VOID proc_db_events(union db_access_val *, CHAN *, long);
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef LOCAL
|
||||
#define LOCAL
|
||||
#endif /*DEBUG*/
|
||||
/*
|
||||
* seq_connect() - Connect to all database channels through channel access.
|
||||
*/
|
||||
long seq_connect(SPROG *pSP)
|
||||
{
|
||||
CHAN *pDB;
|
||||
int status, i;
|
||||
extern VOID seq_conn_handler();
|
||||
|
||||
/*
|
||||
* For each channel: connect to db & isssue monitor (if monFlag is TRUE).
|
||||
*/
|
||||
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
|
||||
logMsg("seq_connect: connect %s to %s\n",
|
||||
pDB->pVarName, pDB->dbName);
|
||||
#endif /*DEBUG*/
|
||||
/* Connect to it */
|
||||
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)
|
||||
{
|
||||
SEVCHK(status, "ca_search");
|
||||
ca_task_exit();
|
||||
return -1;
|
||||
}
|
||||
/* Clear monitor indicator */
|
||||
pDB->monitored = FALSE;
|
||||
|
||||
/*
|
||||
* Issue monitor request
|
||||
*/
|
||||
if (pDB->monFlag)
|
||||
{
|
||||
seq_pvMonitor((SS_ID)pSP->pSS, i);
|
||||
}
|
||||
}
|
||||
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 *).
|
||||
*/
|
||||
VOID seq_event_handler(struct event_handler_args args)
|
||||
{
|
||||
/* Process event handling in each state set */
|
||||
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(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(union db_access_val *pAccess, CHAN *pDB, long complete_type)
|
||||
{
|
||||
SPROG *pSP;
|
||||
void *pVal;
|
||||
|
||||
#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 *)((long)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;
|
||||
|
||||
/* Indicate completed pvGet() */
|
||||
if (complete_type == GET_COMPLETE)
|
||||
{
|
||||
pDB->getComplete = TRUE;
|
||||
}
|
||||
|
||||
/* 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 synchronous (-a) pvGet() */
|
||||
if ( (complete_type == GET_COMPLETE) && ((pSP->options & OPT_ASYNC) == 0) )
|
||||
semGive(pDB->getSemId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disconnect all database channels */
|
||||
/*#define DEBUG_DISCONNECT*/
|
||||
|
||||
long seq_disconnect(SPROG *pSP)
|
||||
{
|
||||
CHAN *pDB;
|
||||
STATUS status;
|
||||
int i;
|
||||
extern int seqAuxTaskId;
|
||||
SPROG *pMySP; /* will be NULL if this task is not a sequencer task */
|
||||
|
||||
/* Did we already disconnect? */
|
||||
if (pSP->connCount < 0)
|
||||
return 0;
|
||||
|
||||
/* Import Channel Access context from the auxillary seq. task */
|
||||
pMySP = seqFindProg(taskIdSelf() );
|
||||
if (pMySP == NULL)
|
||||
{
|
||||
status = ca_import(seqAuxTaskId); /* not a sequencer task */
|
||||
SEVCHK (status, "seq_disconnect: ca_import");
|
||||
}
|
||||
|
||||
pDB = pSP->pChan;
|
||||
for (i = 0; i < pSP->numChans; i++, pDB++)
|
||||
{
|
||||
if (!pDB->assigned)
|
||||
continue;
|
||||
#ifdef DEBUG_DISCONNECT
|
||||
logMsg("seq_disconnect: disconnect %s from %s\n",
|
||||
pDB->pVarName, pDB->dbName);
|
||||
taskDelay(30);
|
||||
#endif /*DEBUG_DISCONNECT*/
|
||||
/* Disconnect this channel */
|
||||
status = ca_clear_channel(pDB->chid);
|
||||
SEVCHK (status, "seq_disconnect: ca_clear_channel");
|
||||
|
||||
/* Clear monitor & connect indicators */
|
||||
pDB->monitored = FALSE;
|
||||
pDB->connected = FALSE;
|
||||
}
|
||||
|
||||
pSP->connCount = -1; /* flag to indicate all disconnected */
|
||||
|
||||
ca_flush_io();
|
||||
|
||||
/* Cancel CA context if it was imported above */
|
||||
if (pMySP == NULL)
|
||||
{
|
||||
#ifdef DEBUG_DISCONNECT
|
||||
logMsg("seq_disconnect: ca_import_cancel\n");
|
||||
#endif /*DEBUG_DISCONNECT*/
|
||||
SEVCHK(ca_import_cancel(taskIdSelf()),
|
||||
"seq_disconnect: ca_import_cancel() failed!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_conn_handler() - Sequencer connection handler.
|
||||
* Called each time a connection is established or broken.
|
||||
*/
|
||||
VOID seq_conn_handler(struct connection_handler_args args)
|
||||
{
|
||||
CHAN *pDB;
|
||||
SPROG *pSP;
|
||||
|
||||
/* User argument is db ptr (specified at ca_search() ) */
|
||||
pDB = (CHAN *)ca_puser(args.chid);
|
||||
|
||||
/* State program that owns this db entry */
|
||||
pSP = pDB->sprog;
|
||||
|
||||
/* Check for connected */
|
||||
if (ca_field_type(args.chid) == TYPENOTCONN)
|
||||
{
|
||||
pDB->connected = FALSE;
|
||||
pSP->connCount--;
|
||||
pDB->monitored = FALSE;
|
||||
#ifdef DEBUG
|
||||
logMsg("%s disconnected from %s\n", pDB->VarName, pDB->dbName);
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
else /* PV connected */
|
||||
{
|
||||
pDB->connected = TRUE;
|
||||
pSP->connCount++;
|
||||
if (pDB->monFlag)
|
||||
pDB->monitored = TRUE;
|
||||
#ifdef 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 */
|
||||
seqWakeup(pSP, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 seqWakeup(SPROG *pSP, long eventNum)
|
||||
{
|
||||
int nss;
|
||||
SSCB *pSS;
|
||||
|
||||
/* Check event number against mask for all state sets: */
|
||||
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1,580 +0,0 @@
|
||||
/*
|
||||
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:
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define ANSI
|
||||
#include "seq.h"
|
||||
#include "tickLib.h"
|
||||
#include "logLib.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).
|
||||
*/
|
||||
long seq_pvGet(SS_ID ssId, long 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) == 0)
|
||||
{
|
||||
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 (status != ECA_NORMAL)
|
||||
{
|
||||
pDB->getComplete = TRUE;
|
||||
SEVCHK(status, "pvGet");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ca_flush_io();
|
||||
if ((pSP->options & OPT_ASYNC) != 0)
|
||||
{ /* +a option: return immediately */
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/* Synchronous (-a option): wait for completion (10s timeout) */
|
||||
sem_status = semTake(pSS->getSemId, 600);
|
||||
if (sem_status != OK)
|
||||
{
|
||||
logMsg ("semTake error=%d\n", sem_status, 0,0,0,0,0);
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvGetComplete() - returns TRUE if the last get completed.
|
||||
*/
|
||||
long seq_pvGetComplete(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
return pDB->getComplete;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* seq_pvPut() - Put DB value.
|
||||
*/
|
||||
long seq_pvPut(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
int status, count;
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
#ifdef DEBUG
|
||||
logMsg("seq_pvPut: pv name=%s, pVar=0x%x\n", pDB->dbName, pDB->pVar, 0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if (!pDB->connected)
|
||||
return ECA_DISCONN;
|
||||
|
||||
count = pDB->count;
|
||||
if (count > pDB->dbCount)
|
||||
count = pDB->dbCount; /* don't try to put more than db count */
|
||||
status = ca_array_put(pDB->putType, count, pDB->chid, pDB->pVar);
|
||||
|
||||
#ifdef DEBUG
|
||||
logMsg("seq_pvPut: status=%d\n", status, 0,0,0,0,0);
|
||||
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, count);
|
||||
}
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return status;
|
||||
}
|
||||
/*
|
||||
* seq_pvAssign() - Assign/Connect to a channel.
|
||||
* Assign to a zero-lth string ("") disconnects/de-assignes.
|
||||
*/
|
||||
long seq_pvAssign(SS_ID ssId, long 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.
|
||||
*/
|
||||
long seq_pvMonitor(SS_ID ssId, long 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
|
||||
*/
|
||||
long seq_pvStopMonitor(SS_ID ssId, long 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.
|
||||
*/
|
||||
long seq_pvChannelCount(SS_ID ssId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
return pSP->numChans;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvConnectCount() - returns number of database channels connected.
|
||||
*/
|
||||
long seq_pvConnectCount(SS_ID ssId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
return pSP->connCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvAssignCount() - returns number of database channels assigned.
|
||||
*/
|
||||
long seq_pvAssignCount(SS_ID ssId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
return pSP->assignCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvConnected() - returns TRUE if database channel is connected.
|
||||
*/
|
||||
long seq_pvConnected(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB;
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
return pDB->connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvAssigned() - returns TRUE if database channel is assigned.
|
||||
*/
|
||||
long seq_pvAssigned(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB;
|
||||
|
||||
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.
|
||||
*/
|
||||
long seq_pvCount(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
return pDB->dbCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvStatus() - returns channel alarm status.
|
||||
*/
|
||||
long seq_pvStatus(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
return pDB->status;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvSeverity() - returns channel alarm severity.
|
||||
*/
|
||||
long seq_pvSeverity(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
pDB = pSP->pChan + pvId;
|
||||
return pDB->severity;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvIndex() - returns index of database variable.
|
||||
*/
|
||||
long seq_pvIndex(SS_ID ssId, long pvId)
|
||||
{
|
||||
return pvId; /* index is same as pvId */
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_pvTimeStamp() - returns channel time stamp.
|
||||
*/
|
||||
TS_STAMP seq_pvTimeStamp(SS_ID ssId, long pvId)
|
||||
{
|
||||
SPROG *pSP; /* ptr to state program */
|
||||
CHAN *pDB; /* ptr to channel struct */
|
||||
|
||||
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(SS_ID ssId, long ev_flag)
|
||||
{
|
||||
SPROG *pSP;
|
||||
SSCB *pSS;
|
||||
|
||||
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,
|
||||
0,0,0);
|
||||
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.
|
||||
*/
|
||||
long seq_efTest(SS_ID ssId, long 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, 0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
return isSet;
|
||||
}
|
||||
|
||||
/*
|
||||
* seq_efClear() - Test event flag against outstanding events, then clear it.
|
||||
*/
|
||||
long seq_efClear(SS_ID ssId, long ev_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.
|
||||
*/
|
||||
long seq_efTestAndClear(SS_ID ssId, long ev_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 */
|
||||
long seq_delay(SS_ID ssId, long 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 (in seconds) on entering a state.
|
||||
*/
|
||||
VOID seq_delayInit(SS_ID ssId, long delayId, float delay)
|
||||
{
|
||||
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 (e.g. "a").
|
||||
* FALSE means "-" and TRUE means "+".
|
||||
*/
|
||||
long seq_optGet(SS_ID ssId, char *opt)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
|
||||
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.
|
||||
|
||||
ENVIRONMENT: VxWorks
|
||||
|
||||
HISTORY:
|
||||
01mar94,ajk Added seq_macValueGet() as state program interface routine.
|
||||
|
||||
***************************************************************************/
|
||||
#define ANSI
|
||||
#include "seq.h"
|
||||
#include "string.h"
|
||||
|
||||
LOCAL int seqMacParseName(char *);
|
||||
LOCAL int seqMacParseValue(char *);
|
||||
LOCAL char *skipBlanks(char *);
|
||||
LOCAL MACRO *seqMacTblGet(MACRO *, char *);
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
/*
|
||||
*seqMacEval - substitute macro value into a string containing:
|
||||
* ....{mac_name}....
|
||||
*/
|
||||
VOID seqMacEval(pInStr, pOutStr, maxChar, pMac)
|
||||
char *pInStr;
|
||||
char *pOutStr;
|
||||
long maxChar;
|
||||
MACRO *pMac;
|
||||
{
|
||||
char name[50], *pValue, *pTmp;
|
||||
int nameLth, valLth;
|
||||
|
||||
#ifdef DEBUG
|
||||
logMsg("seqMacEval: InStr=%s\n", pInStr);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
pTmp = pOutStr;
|
||||
while (*pInStr != 0 && maxChar > 0)
|
||||
{
|
||||
if (*pInStr == '{')
|
||||
{ /* Do macro substitution */
|
||||
pInStr++; /* points to macro name */
|
||||
/* 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
|
||||
logMsg("Macro name=%s\n", name);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
/* Find macro value from macro name */
|
||||
pValue = seqMacValGet(pMac, name);
|
||||
if (pValue != NULL)
|
||||
{ /* Substitute macro value */
|
||||
valLth = strlen(pValue);
|
||||
if (valLth > maxChar)
|
||||
valLth = maxChar;
|
||||
#ifdef DEBUG
|
||||
logMsg("Value=%s\n", pValue);
|
||||
#endif
|
||||
strncpy(pOutStr, pValue, valLth);
|
||||
maxChar -= valLth;
|
||||
pOutStr += valLth;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{ /* Straight susbstitution */
|
||||
*pOutStr++ = *pInStr++;
|
||||
maxChar--;
|
||||
}
|
||||
}
|
||||
*pOutStr = 0;
|
||||
#ifdef DEBUG
|
||||
logMsg("OutStr=%s\n", pTmp);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* seq_macValueGet - given macro name, return pointer to its value.
|
||||
*/
|
||||
char *seq_macValueGet(ssId, pName)
|
||||
SS_ID ssId;
|
||||
char *pName;
|
||||
{
|
||||
SPROG *pSP;
|
||||
MACRO *pMac;
|
||||
|
||||
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 (pMac->pName != NULL)
|
||||
{
|
||||
if (strcmp(pName, pMac->pName) == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
logMsg(", value=%s\n", pMac->pValue);
|
||||
#endif /*DEBUG*/
|
||||
return pMac->pValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
logMsg(", no value\n");
|
||||
#endif /*DEBUG*/
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* seqMacParse - parse the macro definition string and build
|
||||
* the macro table (name/value pairs). Returns number of macros parsed.
|
||||
* Assumes the table may already contain entries (values may be changed).
|
||||
* String for name and value are allocated dynamically from pool.
|
||||
*/
|
||||
long seqMacParse(pMacStr, pSP)
|
||||
char *pMacStr; /* macro definition string */
|
||||
SPROG *pSP;
|
||||
{
|
||||
int nChar;
|
||||
char *skipBlanks();
|
||||
MACRO *pMac; /* macro table */
|
||||
MACRO *pMacTbl; /* macro tbl entry */
|
||||
char *pName, *pValue;
|
||||
|
||||
pMac = pSP->pMacros;
|
||||
for ( ;; )
|
||||
{
|
||||
/* Skip blanks */
|
||||
pMacStr = skipBlanks(pMacStr);
|
||||
|
||||
/* Parse the macro name */
|
||||
|
||||
nChar = seqMacParseName(pMacStr);
|
||||
if (nChar == 0)
|
||||
break; /* finished or error */
|
||||
pName = (char *)calloc(nChar+1, 1);
|
||||
if (pName == NULL)
|
||||
break;
|
||||
bcopy(pMacStr, pName, nChar);
|
||||
pName[nChar] = 0;
|
||||
#ifdef DEBUG
|
||||
logMsg("name=%s, nChar=%d\n", pName, nChar);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
pMacStr += nChar;
|
||||
|
||||
/* Find a slot in the table */
|
||||
pMacTbl = seqMacTblGet(pMac, pName);
|
||||
if (pMacTbl == NULL)
|
||||
break; /* table is full */
|
||||
if (pMacTbl->pName == NULL)
|
||||
{ /* Empty slot, insert macro name */
|
||||
pMacTbl->pName = pName;
|
||||
}
|
||||
|
||||
/* Skip over blanks and equal sign or comma */
|
||||
pMacStr = skipBlanks(pMacStr);
|
||||
if (*pMacStr == ',')
|
||||
{ /* no value after the macro name */
|
||||
pMacStr++;
|
||||
continue;
|
||||
}
|
||||
if (*pMacStr++ != '=')
|
||||
break;
|
||||
pMacStr = skipBlanks(pMacStr);
|
||||
|
||||
/* Parse the value */
|
||||
nChar = seqMacParseValue(pMacStr);
|
||||
if (nChar == 0)
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
pMacTbl->pValue = pValue;
|
||||
bcopy(pMacStr, pValue, nChar);
|
||||
pValue[nChar] = 0;
|
||||
#ifdef DEBUG
|
||||
logMsg("value=%s, nChar=%d\n", pValue, nChar);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
|
||||
/* Skip past last value and over blanks and comma */
|
||||
pMacStr += nChar;
|
||||
pMacStr = skipBlanks(pMacStr);
|
||||
if (*pMacStr++ != ',')
|
||||
break;
|
||||
}
|
||||
if (*pMacStr == 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* seqMacParseName() - Parse a macro name from the input string.
|
||||
*/
|
||||
LOCAL int seqMacParseName(pStr)
|
||||
char *pStr;
|
||||
{
|
||||
int nChar;
|
||||
|
||||
/* First character must be [A-Z,a-z] */
|
||||
if (!isalpha(*pStr))
|
||||
return 0;
|
||||
pStr++;
|
||||
nChar = 1;
|
||||
/* Character must be [A-Z,a-z,0-9,_] */
|
||||
while ( isalnum(*pStr) || *pStr == '_' )
|
||||
{
|
||||
pStr++;
|
||||
nChar++;
|
||||
}
|
||||
/* Loop terminates on any non-name character */
|
||||
return nChar;
|
||||
}
|
||||
|
||||
/*
|
||||
* seqMacParseValue() - Parse a macro value from the input string.
|
||||
*/
|
||||
LOCAL int seqMacParseValue(pStr)
|
||||
char *pStr;
|
||||
{
|
||||
int nChar;
|
||||
|
||||
nChar = 0;
|
||||
/* Character string terminates on blank, comma, or EOS */
|
||||
while ( (*pStr != ' ') && (*pStr != ',') && (*pStr != 0) )
|
||||
{
|
||||
pStr++;
|
||||
nChar++;
|
||||
}
|
||||
return nChar;
|
||||
}
|
||||
|
||||
/* skipBlanks() - skip blank characters */
|
||||
LOCAL char *skipBlanks(pChar)
|
||||
char *pChar;
|
||||
{
|
||||
while (*pChar == ' ')
|
||||
pChar++;
|
||||
return pChar;
|
||||
}
|
||||
|
||||
/*
|
||||
* seqMacTblGet - find a match for the specified name, otherwise
|
||||
* return an empty slot in macro table.
|
||||
*/
|
||||
LOCAL MACRO *seqMacTblGet(pMac, pName)
|
||||
MACRO *pMac;
|
||||
char *pName; /* macro name */
|
||||
{
|
||||
int i;
|
||||
MACRO *pMacTbl;
|
||||
|
||||
#ifdef DEBUG
|
||||
logMsg("seqMacTblGet: name=%s\n", pName);
|
||||
taskDelay(30);
|
||||
#endif
|
||||
for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++)
|
||||
{
|
||||
if (pMacTbl->pName != NULL)
|
||||
{
|
||||
if (strcmp(pName, pMacTbl->pName) == 0)
|
||||
{
|
||||
return pMacTbl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found, find an empty slot */
|
||||
for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++)
|
||||
{
|
||||
if (pMacTbl->pName == NULL)
|
||||
{
|
||||
return pMacTbl;
|
||||
}
|
||||
}
|
||||
|
||||
/* No empty slots available */
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,652 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
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
|
||||
|
||||
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
|
||||
programs.
|
||||
|
||||
ENVIRONMENT: VxWorks
|
||||
|
||||
HISTORY:
|
||||
23apr91,ajk Fixed problem with state program invoking the sequencer.
|
||||
01jul91,ajk Added ANSI functional prototypes.
|
||||
05jul91,ajk Changed semCreate() in three places to semBCreate.
|
||||
Modified semTake() second param. to WAIT_FOREVER.
|
||||
These provide VX5.0 compatability.
|
||||
16aug91,ajk Improved "magic number" error message.
|
||||
25oct91,ajk Code to create semaphores "pSS->getSemId" was left out.
|
||||
Added this code to init_sscb().
|
||||
25nov91,ajk Removed obsolete seqLog() code dealing with global locking.
|
||||
04dec91,ajk Implemented state program linked list, eliminating need for
|
||||
task variables.
|
||||
11dec91,ajk Cleaned up comments.
|
||||
05feb92,ajk Decreased minimum allowable stack size to SPAWN_STACK_SIZE/2.
|
||||
24feb92,ajk Print error code for log file failure.
|
||||
28apr92,ajk Implemented new event flag mode.
|
||||
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 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.
|
||||
19jul95,ajk Added unsigned types (unsigned char, short, int, long).
|
||||
20jul95,ajk Added priority specification at run time.
|
||||
03aug95,ajk Fixed problem with +r option: user variable space (pSP->pVar)
|
||||
was not being allocated.
|
||||
03jun96,ajk Now compiles with -wall and -pedantic switches.
|
||||
***************************************************************************/
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "seqCom.h"
|
||||
#include "seq.h"
|
||||
#include "taskLib.h"
|
||||
#include "taskHookLib.h"
|
||||
#include "logLib.h"
|
||||
#include "errnoLib.h"
|
||||
#include "usrLib.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef LOCAL
|
||||
#define LOCAL
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* ANSI functional prototypes for local routines */
|
||||
LOCAL SPROG *seqInitTables(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 VOID selectDBtype(char *, short *, short *, short *, short *);
|
||||
|
||||
#define SCRATCH_SIZE (MAX_MACROS*(MAX_STRING_SIZE+1)*12)
|
||||
/* Globals */
|
||||
/* Flag to indicate that "taskDeleteHookAdd()" was called */
|
||||
int seqDeleteHookAdded = FALSE;
|
||||
|
||||
/* Auxillary sequencer task id; used to share CA context. */
|
||||
int seqAuxTaskId = 0;
|
||||
|
||||
/*
|
||||
* seq: User-callable routine to initiate a state program.
|
||||
* Usage: seq(<pSP>, <macros string>, <stack size>)
|
||||
* pSP is the ptr to the state program structure.
|
||||
* Example: seq(&myprog, "logfile=mylog", 0)
|
||||
* When called from the shell, the 2nd & 3rd parameters are optional.
|
||||
*
|
||||
* Creates the initial state program task and returns its task id.
|
||||
* Most initialization is performed here.
|
||||
*/
|
||||
long seq (pSeqProg, macro_def, stack_size)
|
||||
struct seqProgram *pSeqProg; /* state program info generated by snc */
|
||||
char *macro_def; /* optional macro def'n string */
|
||||
long stack_size; /* optional stack size (bytes) */
|
||||
{
|
||||
int tid;
|
||||
extern sprog_delete(); /* Task delete routine */
|
||||
extern char *seqVersion;
|
||||
SPROG *pSP;
|
||||
char *pValue, *ptask_name;
|
||||
extern seqAuxTask();
|
||||
|
||||
/* Print version & date of sequencer */
|
||||
printf("%s\n", seqVersion);
|
||||
|
||||
/* Spawn the sequencer auxillary task */
|
||||
if (seqAuxTaskId == 0)
|
||||
{
|
||||
taskSpawn("seqAux", SPAWN_PRIORITY-1, VX_FP_TASK, 4000, seqAuxTask,
|
||||
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, 0,0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
|
||||
/* Specify a routine to run at task delete */
|
||||
if (!seqDeleteHookAdded)
|
||||
{
|
||||
taskDeleteHookAdd(sprog_delete);
|
||||
seqDeleteHookAdded = TRUE;
|
||||
}
|
||||
|
||||
/* Exit if no parameters specified */
|
||||
if (pSeqProg == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for correct state program format */
|
||||
if (pSeqProg->magic != MAGIC)
|
||||
{ /* Oops */
|
||||
logMsg("Illegal magic number in state program.\n", 0,0,0,0,0,0);
|
||||
logMsg(" - Possible mismatch between SNC & SEQ versions\n", 0,0,0,0,0,0);
|
||||
logMsg(" - Re-compile your program?\n", 0,0,0,0,0,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the sequencer tables */
|
||||
pSP = seqInitTables(pSeqProg);
|
||||
|
||||
/* Parse the macro definitions from the "program" statement */
|
||||
seqMacParse(pSeqProg->pParams, pSP);
|
||||
|
||||
/* Parse the macro definitions from the command line */
|
||||
seqMacParse(macro_def, pSP);
|
||||
|
||||
/* Do macro substitution on channel names */
|
||||
seqChanNameEval(pSP);
|
||||
|
||||
/* Initialize sequencer logging */
|
||||
seq_logInit(pSP);
|
||||
|
||||
/* Specify stack size */
|
||||
if (stack_size == 0)
|
||||
stack_size = SPAWN_STACK_SIZE;
|
||||
pValue = seqMacValGet(pSP->pMacros, "stack");
|
||||
if (pValue != NULL && strlen(pValue) > 0)
|
||||
{
|
||||
sscanf(pValue, "%ld", &stack_size);
|
||||
}
|
||||
if (stack_size < SPAWN_STACK_SIZE/2)
|
||||
stack_size = SPAWN_STACK_SIZE/2;
|
||||
|
||||
/* Specify task name */
|
||||
pValue = seqMacValGet(pSP->pMacros, "name");
|
||||
if (pValue != NULL && strlen(pValue) > 0)
|
||||
ptask_name = pValue;
|
||||
else
|
||||
ptask_name = pSP->pProgName;
|
||||
|
||||
/* Spawn the initial sequencer task */
|
||||
#ifdef DEBUG
|
||||
logMsg("Spawning task %s, stack_size=%d\n", ptask_name, stack_size, 0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
/* Specify task priority */
|
||||
pSP->taskPriority = SPAWN_PRIORITY;
|
||||
pValue = seqMacValGet(pSP->pMacros, "priority");
|
||||
if (pValue != NULL && strlen(pValue) > 0)
|
||||
{
|
||||
sscanf(pValue, "%ld", &(pSP->taskPriority));
|
||||
}
|
||||
if (pSP->taskPriority < SPAWN_PRIORITY)
|
||||
pSP->taskPriority = SPAWN_PRIORITY;
|
||||
if (pSP->taskPriority > 255)
|
||||
pSP->taskPriority = 255;
|
||||
|
||||
tid = taskSpawn(ptask_name, pSP->taskPriority, SPAWN_OPTIONS,
|
||||
stack_size, (FUNCPTR)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->pProgName, ptask_name);
|
||||
seq_log(pSP, " Task id = %d = 0x%x\n", tid, tid);
|
||||
|
||||
/* Return task id to calling program */
|
||||
return tid;
|
||||
}
|
||||
/* seqInitTables - initialize sequencer tables */
|
||||
LOCAL SPROG *seqInitTables(pSeqProg)
|
||||
struct seqProgram *pSeqProg;
|
||||
{
|
||||
SPROG *pSP;
|
||||
|
||||
pSP = (SPROG *)calloc(1, sizeof (SPROG));
|
||||
|
||||
/* Initialize state program block */
|
||||
init_sprog(pSeqProg, pSP);
|
||||
|
||||
/* Initialize state set control blocks */
|
||||
init_sscb(pSeqProg, pSP);
|
||||
|
||||
/* Initialize database channel blocks */
|
||||
init_chan(pSeqProg, pSP);
|
||||
|
||||
/* Initialize the macro table */
|
||||
init_mac(pSP);
|
||||
|
||||
|
||||
return pSP;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
{
|
||||
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 = (EXIT_FUNC)pSeqProg->exitFunc;
|
||||
pSP->varSize = pSeqProg->varSize;
|
||||
/* Allocate user variable area if reentrant option (+r) is set */
|
||||
if ((pSP->options & OPT_REENT) != 0)
|
||||
pSP->pVar = (char *)calloc(pSP->varSize, 1);
|
||||
|
||||
#ifdef 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*/
|
||||
|
||||
/* Create a semaphore for resource locking on CA events */
|
||||
pSP->caSemId = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (pSP->caSemId == NULL)
|
||||
{
|
||||
logMsg("can't create caSemId\n", 0,0,0,0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
pSP->task_is_deleted = FALSE;
|
||||
pSP->connCount = 0;
|
||||
pSP->assignCount = 0;
|
||||
pSP->logFd = 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(pSeqProg, pSP)
|
||||
struct seqProgram *pSeqProg;
|
||||
SPROG *pSP;
|
||||
{
|
||||
SSCB *pSS;
|
||||
STATE *pState;
|
||||
int nss, nstates;
|
||||
struct seqSS *pSeqSS;
|
||||
struct seqState *pSeqState;
|
||||
|
||||
|
||||
/* 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++)
|
||||
{
|
||||
/* 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, 0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
/* Create a binary semaphore for synchronizing events in a SS */
|
||||
pSS->syncSemId = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (pSS->syncSemId == NULL)
|
||||
{
|
||||
logMsg("can't create syncSemId\n", 0,0,0,0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a binary semaphore for synchronous pvGet() (-a) */
|
||||
if ((pSP->options & OPT_ASYNC) == 0)
|
||||
{
|
||||
pSS->getSemId =
|
||||
semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (pSS->getSemId == NULL)
|
||||
{
|
||||
logMsg("can't create getSemId\n", 0,0,0,0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 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 = (ACTION_FUNC)pSeqState->actionFunc;
|
||||
pState->eventFunc = (EVENT_FUNC)pSeqState->eventFunc;
|
||||
pState->delayFunc = (DELAY_FUNC)pSeqState->delayFunc;
|
||||
pState->pEventMask = pSeqState->pEventMask;
|
||||
#ifdef DEBUG
|
||||
logMsg("init_sscb: State Name=%s, Event Mask=0x%x\n",
|
||||
pState->pStateName, *pState->pEventMask, 0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
logMsg("init_sscb: numSS=%d\n", pSP->numSS, 0,0,0,0,0);
|
||||
#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, 0,0,0,0,0);
|
||||
#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) != 0)
|
||||
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, 0,0);
|
||||
logMsg(" size=%d, dbOffset=%d\n", pDB->size, pDB->dbOffset, 0,0,0,0);
|
||||
logMsg(" efId=%d, monFlag=%d, eventNum=%d\n",
|
||||
pDB->efId, pDB->monFlag, pDB->eventNum, 0,0,0);
|
||||
#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, 0,0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
|
||||
for (i = 0 ; i < MAX_MACROS; i++, pMac++)
|
||||
{
|
||||
pMac->pName = NULL;
|
||||
pMac->pValue = NULL;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Evaluate channel names by macro substitution.
|
||||
*/
|
||||
#define MACRO_STR_LEN (MAX_STRING_SIZE+1)
|
||||
LOCAL VOID seqChanNameEval(pSP)
|
||||
SPROG *pSP;
|
||||
{
|
||||
CHAN *pDB;
|
||||
int i;
|
||||
|
||||
pDB = pSP->pChan;
|
||||
for (i = 0; i < pSP->numChans; i++, pDB++)
|
||||
{
|
||||
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, 0,0,0,0);
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
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)
|
||||
},
|
||||
|
||||
{
|
||||
"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)
|
||||
},
|
||||
|
||||
{
|
||||
"unsigned char", DBR_CHAR, DBR_TIME_CHAR,
|
||||
sizeof (char), OFFSET(struct dbr_time_char, value)
|
||||
},
|
||||
|
||||
{
|
||||
"unsigned short", DBR_SHORT, DBR_TIME_SHORT,
|
||||
sizeof (short), OFFSET(struct dbr_time_short, value)
|
||||
},
|
||||
|
||||
{
|
||||
"unsigned int", DBR_LONG, DBR_TIME_LONG,
|
||||
sizeof (long), OFFSET(struct dbr_time_long, value)
|
||||
},
|
||||
|
||||
{
|
||||
"unsigned 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++)
|
||||
{
|
||||
if (strcmp(pUserType, pMap->pTypeStr) == 0)
|
||||
{
|
||||
*pGetType = pMap->getType;
|
||||
*pPutType = pMap->putType;
|
||||
*pSize = pMap->size;
|
||||
*pOffset = pMap->offset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*pGetType = *pPutType = *pSize = *pOffset = 0; /* this shouldn't happen */
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* seq_logInit() - Initialize logging.
|
||||
* If "logfile" is not specified, then we log to standard output.
|
||||
*/
|
||||
LOCAL VOID seq_logInit(pSP)
|
||||
SPROG *pSP;
|
||||
{
|
||||
char *pValue;
|
||||
int fd;
|
||||
|
||||
/* Create a logging resource locking semaphore */
|
||||
pSP->logSemId = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (pSP->logSemId == NULL)
|
||||
{
|
||||
logMsg("can't create logSemId\n", 0,0,0,0,0,0);
|
||||
return;
|
||||
}
|
||||
pSP->logFd = ioGlobalStdGet(1); /* default fd is std out */
|
||||
|
||||
/* Check for logfile spec. */
|
||||
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);
|
||||
if (fd != ERROR)
|
||||
pSP->logFd = fd;
|
||||
printf("logfile=%s, fd=%d\n", pValue, fd);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* seq_log
|
||||
* 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
|
||||
|
||||
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 */
|
||||
{
|
||||
int fd, count, status;
|
||||
TS_STAMP timeStamp;
|
||||
char logBfr[LOG_BFR_SIZE], *pBfr;
|
||||
|
||||
pBfr = logBfr;
|
||||
|
||||
/* Enter taskname */
|
||||
sprintf(pBfr, "%s ", taskName(taskIdSelf()) );
|
||||
pBfr += strlen(pBfr);
|
||||
|
||||
/* Get time of day */
|
||||
tsLocalTime(&timeStamp); /* time stamp format */
|
||||
|
||||
/* Convert to text format: "mm/dd/yy hh:mm:ss.nano-sec" */
|
||||
tsStampToText(&timeStamp, TS_TEXT_MMDDYY, pBfr);
|
||||
/* Truncate the ".nano-sec" part */
|
||||
if (pBfr[2] == '/') /* valid t-s? */
|
||||
pBfr += 17;
|
||||
|
||||
/* Insert ": " */
|
||||
*pBfr++ = ':';
|
||||
*pBfr++ = ' ';
|
||||
|
||||
/* Append the user's msg to the buffer */
|
||||
sprintf(pBfr, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
pBfr += strlen(pBfr);
|
||||
|
||||
/* Write the msg */
|
||||
semTake(pSP->logSemId, WAIT_FOREVER); /* lock it */
|
||||
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 = \"%s\"\n",
|
||||
fd, errnoGet(), (int) strerror(errnoGet()),0,0,0);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* If this is an NSF file flush the buffer */
|
||||
if (fd != ioGlobalStdGet(1) )
|
||||
{
|
||||
ioctl(fd, FIOSYNC, 0);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
/*
|
||||
* seq_seqLog() - State program interface to seq_log().
|
||||
* Does not require ptr to state program block.
|
||||
*/
|
||||
long 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 */
|
||||
{
|
||||
SPROG *pSP;
|
||||
|
||||
pSP = ((SSCB *)ssId)->sprog;
|
||||
return seq_log(pSP, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/**************************************************************************
|
||||
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
|
||||
|
||||
|
||||
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.
|
||||
|
||||
ENVIRONMENT: VxWorks
|
||||
|
||||
HISTORY:
|
||||
09dec91,ajk original
|
||||
29apr92,ajk Added mutual exclusion locks
|
||||
17Jul92,rcz Changed semBCreate call for V5 vxWorks, maybe should be semMCreate ???
|
||||
***************************************************************************/
|
||||
/*#define DEBUG*/
|
||||
#define ANSI
|
||||
#include "seq.h"
|
||||
#include "lstLib.h"
|
||||
|
||||
LOCAL SEM_ID seqProgListSemId;
|
||||
LOCAL int seqProgListInited = FALSE;
|
||||
LOCAL LIST seqProgList;
|
||||
LOCAL VOID seqProgListInit();
|
||||
|
||||
typedef struct prog_node
|
||||
{
|
||||
NODE node;
|
||||
SPROG *pSP;
|
||||
} PROG_NODE;
|
||||
|
||||
#define seqListFirst(pList) (PROG_NODE *)lstFirst((LIST *)pList)
|
||||
|
||||
#define seqListNext(pNode) (PROG_NODE *)lstNext((NODE *)pNode)
|
||||
|
||||
/*
|
||||
* seqFindProg() - find a program in the state program list from task id.
|
||||
*/
|
||||
SPROG *seqFindProg(taskId)
|
||||
long taskId;
|
||||
{
|
||||
PROG_NODE *pNode;
|
||||
SPROG *pSP;
|
||||
SSCB *pSS;
|
||||
int n;
|
||||
|
||||
if (!seqProgListInited || taskId == 0)
|
||||
return NULL;
|
||||
|
||||
semTake(seqProgListSemId, WAIT_FOREVER);
|
||||
|
||||
for (pNode = seqListFirst(&seqProgList); pNode != NULL;
|
||||
pNode = seqListNext(pNode) )
|
||||
{
|
||||
pSP = pNode->pSP;
|
||||
if (pSP->taskId == taskId)
|
||||
{
|
||||
semGive(seqProgListSemId);
|
||||
return pSP;
|
||||
}
|
||||
pSS = pSP->pSS;
|
||||
for (n = 0; n < pSP->numSS; n++, pSS++)
|
||||
{
|
||||
if (pSS->taskId == taskId)
|
||||
{
|
||||
semGive(seqProgListSemId);
|
||||
return pSP;
|
||||
}
|
||||
}
|
||||
}
|
||||
semGive(seqProgListSemId);
|
||||
|
||||
return NULL; /* not in list */
|
||||
}
|
||||
|
||||
/*
|
||||
* seqTraverseProg() - travers programs in the state program list and
|
||||
* call the specified routine or function. Passes one parameter of
|
||||
* pointer size.
|
||||
*/
|
||||
STATUS seqTraverseProg(pFunc, param)
|
||||
VOID (*pFunc)(); /* function to call */
|
||||
VOID *param; /* any parameter */
|
||||
{
|
||||
PROG_NODE *pNode;
|
||||
SPROG *pSP;
|
||||
|
||||
if (!seqProgListInited)
|
||||
return ERROR;
|
||||
|
||||
semTake(seqProgListSemId, WAIT_FOREVER);
|
||||
for (pNode = seqListFirst(&seqProgList); pNode != NULL;
|
||||
pNode = seqListNext(pNode) )
|
||||
{
|
||||
pSP = pNode->pSP;
|
||||
pFunc(pSP, param);
|
||||
}
|
||||
|
||||
semGive(seqProgListSemId);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* seqAddProg() - add a program to the state program list.
|
||||
* Returns ERROR if program is already in list, else TRUE.
|
||||
*/
|
||||
STATUS seqAddProg(pSP)
|
||||
SPROG *pSP;
|
||||
{
|
||||
PROG_NODE *pNode;
|
||||
|
||||
if (!seqProgListInited)
|
||||
seqProgListInit(); /* Initialize list */
|
||||
|
||||
semTake(seqProgListSemId, WAIT_FOREVER);
|
||||
for (pNode = seqListFirst(&seqProgList); pNode != NULL;
|
||||
pNode = seqListNext(pNode) )
|
||||
{
|
||||
|
||||
if (pSP == pNode->pSP)
|
||||
{
|
||||
semGive(seqProgListSemId);
|
||||
#ifdef DEBUG
|
||||
printf("Task %d already in list\n", pSP->taskId);
|
||||
#endif
|
||||
return ERROR; /* already in list */
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert at head of list */
|
||||
pNode = (PROG_NODE *)malloc(sizeof(PROG_NODE) );
|
||||
if (pNode == NULL)
|
||||
{
|
||||
semGive(seqProgListSemId);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
pNode->pSP = pSP;
|
||||
lstAdd((LIST *)&seqProgList, (NODE *)pNode);
|
||||
semGive(seqProgListSemId);
|
||||
#ifdef DEBUG
|
||||
printf("Added task %d to list.\n", pSP->taskId);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*seqDelProg() - delete a program from the program list.
|
||||
* Returns TRUE if deleted, else FALSE.
|
||||
*/
|
||||
STATUS seqDelProg(pSP)
|
||||
SPROG *pSP;
|
||||
{
|
||||
PROG_NODE *pNode;
|
||||
|
||||
if (!seqProgListInited)
|
||||
return ERROR;
|
||||
|
||||
semTake(seqProgListSemId, WAIT_FOREVER);
|
||||
for (pNode = seqListFirst(&seqProgList); pNode != NULL;
|
||||
pNode = seqListNext(pNode) )
|
||||
{
|
||||
if (pNode->pSP == pSP)
|
||||
{
|
||||
lstDelete((LIST *)&seqProgList, (NODE *)pNode);
|
||||
semGive(seqProgListSemId);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Deleted task %d from list.\n", pSP->taskId);
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
semGive(seqProgListSemId);
|
||||
return ERROR; /* not in list */
|
||||
}
|
||||
|
||||
/*
|
||||
* seqProgListInit() - initialize the state program list.
|
||||
*/
|
||||
LOCAL VOID seqProgListInit()
|
||||
{
|
||||
/* Init linked list */
|
||||
lstInit(&seqProgList);
|
||||
|
||||
/* Create a semaphore for mutual exclusion */
|
||||
seqProgListSemId = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
semGive(seqProgListSemId);
|
||||
|
||||
seqProgListInited = TRUE;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,402 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
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
|
||||
|
||||
DESCRIPTION: Task querry & debug routines for run-time sequencer:
|
||||
seqShow - prints state set info.
|
||||
seqChanShow - printf channel (pv) info.
|
||||
|
||||
ENVIRONMENT: VxWorks
|
||||
HISTORY:
|
||||
25nov91,ajk Display task names(s) with id(s).
|
||||
Display logfile name and file descriptor.
|
||||
Moved wait_rtn() to top of loop.
|
||||
09dec91,ajk Modified to used state program linked list.
|
||||
Added option to display all programs when tid=0.
|
||||
19dec91,ajk Allow task name as well as task id.
|
||||
25feb92,ajk V5.0 accepts 0 as a valid task id: fixed it.
|
||||
26feb92,ajk Fixed formatting of task/program listing.
|
||||
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*/
|
||||
|
||||
#include "seq.h"
|
||||
#include "usrLib.h"
|
||||
#include "tickLib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* User functions */
|
||||
int seqShow(int);
|
||||
int seqChanShow(int, char *);
|
||||
|
||||
LOCAL int wait_rtn();
|
||||
LOCAL VOID printValue(char *, int, int);
|
||||
LOCAL SPROG *seqQryFind(int);
|
||||
LOCAL void seqShowAll();
|
||||
|
||||
/*
|
||||
* seqShow() - Querry the sequencer for state information.
|
||||
* If a non-zero task id is specified then print the information about
|
||||
* the state program, otherwise print a brief summary of all state programs
|
||||
*/
|
||||
int seqShow(tid)
|
||||
int tid;
|
||||
{
|
||||
SPROG *pSP;
|
||||
SSCB *pSS;
|
||||
STATE *pST;
|
||||
int nss, status;
|
||||
float time;
|
||||
char file_name[100];
|
||||
|
||||
/* 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->pProgName);
|
||||
printf(" initial task id=%lu=0x%lx\n",
|
||||
(unsigned long) pSP->taskId, (unsigned long) pSP->taskId);
|
||||
printf(" task priority=%ld\n", pSP->taskPriority);
|
||||
printf(" number of state sets=%ld\n", pSP->numSS);
|
||||
printf(" number of channels=%ld\n", pSP->numChans);
|
||||
printf(" number of channels assigned=%ld\n", pSP->assignCount);
|
||||
printf(" number of channels connected=%ld\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_NEWEF) != 0), ((pSP->options & OPT_REENT) != 0),
|
||||
((pSP->options & OPT_CONN) != 0) );
|
||||
if ((pSP->options & OPT_REENT) != 0)
|
||||
printf(" user variables: address=%lu=0x%lx, length=%ld=0x%lx bytes\n",
|
||||
(unsigned long)pSP->pVar, (unsigned long)pSP->pVar,
|
||||
pSP->varSize, pSP->varSize);
|
||||
printf(" log file fd=%ld\n", pSP->logFd);
|
||||
status = ioctl(pSP->logFd, FIOGETNAME, (int)file_name);
|
||||
if (status != ERROR)
|
||||
printf(" log file name=\"%s\"\n", file_name);
|
||||
|
||||
printf("\n");
|
||||
|
||||
/* Print state set info */
|
||||
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
printf(" State Set: \"%s\"\n", pSS->pSSName);
|
||||
|
||||
printf(" task name=%s; ", taskName(pSS->taskId));
|
||||
|
||||
printf(" task id=%lu=0x%lx\n",
|
||||
(unsigned long) pSS->taskId, (unsigned long) pSS->taskId);
|
||||
|
||||
pST = pSS->pStates;
|
||||
printf(" First state = \"%s\"\n", pST->pStateName);
|
||||
|
||||
pST = pSS->pStates + pSS->currentState;
|
||||
printf(" Current state = \"%s\"\n", pST->pStateName);
|
||||
|
||||
pST = pSS->pStates + pSS->prevState;
|
||||
printf(" Previous state = \"%s\"\n", pST->pStateName);
|
||||
|
||||
time = (tickGet() - pSS->timeEntered)/60.0;
|
||||
printf("\tElapsed time since state was entered = %.1f seconds)\n",
|
||||
time);
|
||||
#ifdef DEBUG
|
||||
printf(" Queued time delays:\n");
|
||||
for (n = 0; n < pSS->numDelays; n++)
|
||||
{
|
||||
printf("\tdelay[%2d]=%d", n, pSS->delay[n]);
|
||||
if (pSS->delayExpired[n])
|
||||
printf(" - expired");
|
||||
printf("\n");
|
||||
}
|
||||
#endif /*DEBUG*/
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* seqChanShow() - Show channel information for a state program.
|
||||
*/
|
||||
int seqChanShow(tid, pStr)
|
||||
int tid; /* task id or name */
|
||||
char *pStr; /* optional pattern matching string */
|
||||
{
|
||||
SPROG *pSP;
|
||||
CHAN *pDB;
|
||||
int nch, n;
|
||||
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;
|
||||
|
||||
printf("State Program: \"%s\"\n", pSP->pProgName);
|
||||
printf("Number of channels=%ld\n", pSP->numChans);
|
||||
|
||||
if (pStr != NULL)
|
||||
{
|
||||
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 %ld:\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 = %lu = 0x%lx\n",
|
||||
(unsigned long)pDB->pVar, (unsigned long)pDB->pVar);
|
||||
printf(" type = %s\n", pDB->pVarType);
|
||||
printf(" count = %ld\n", pDB->count);
|
||||
printValue(pDB->pVar, pDB->putType, pDB->count);
|
||||
printf(" Monitor flag=%d\n", pDB->monFlag);
|
||||
|
||||
if (pDB->monitored)
|
||||
printf(" Monitored\n");
|
||||
else
|
||||
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->getComplete)
|
||||
printf(" Last get completed\n");
|
||||
else
|
||||
printf(" Get not completed or no get issued\n");
|
||||
|
||||
printf(" Status=%d\n", pDB->status);
|
||||
printf(" Severity=%d\n", pDB->severity);
|
||||
|
||||
/* 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 int wait_rtn()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Print the current internal value of a database channel */
|
||||
LOCAL VOID printValue(pVal, type, count)
|
||||
char *pVal;
|
||||
int count, type;
|
||||
{
|
||||
int i;
|
||||
char *c;
|
||||
short *s;
|
||||
long *l;
|
||||
float *f;
|
||||
double *d;
|
||||
|
||||
if (count > 5)
|
||||
count = 5;
|
||||
|
||||
printf(" Value =");
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DBR_STRING:
|
||||
c = (char *)pVal;
|
||||
for (i = 0; i < count; i++, c += MAX_STRING_SIZE)
|
||||
{
|
||||
printf(" %s", c);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_CHAR:
|
||||
c = (char *)pVal;
|
||||
for (i = 0; i < count; i++, c++)
|
||||
{
|
||||
printf(" %d", *c);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_SHORT:
|
||||
s = (short *)pVal;
|
||||
for (i = 0; i < count; i++, s++)
|
||||
{
|
||||
printf(" %d", *s);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_LONG:
|
||||
l = (long *)pVal;
|
||||
for (i = 0; i < count; i++, l++)
|
||||
{
|
||||
printf(" %ld", *l);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_FLOAT:
|
||||
f = (float *)pVal;
|
||||
for (i = 0; i < count; i++, f++)
|
||||
{
|
||||
printf(" %g", *f);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBR_DOUBLE:
|
||||
d = (double *)pVal;
|
||||
for (i = 0; i < count; i++, d++)
|
||||
{
|
||||
printf(" %g", *d);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Find a state program associated with a given task id */
|
||||
LOCAL SPROG *seqQryFind(tid)
|
||||
int tid;
|
||||
{
|
||||
SPROG *pSP;
|
||||
extern SPROG *seqFindProg();
|
||||
|
||||
if (tid == 0)
|
||||
{
|
||||
seqShowAll();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a state program that has this task id */
|
||||
pSP = seqFindProg(tid);
|
||||
if (pSP == NULL)
|
||||
{
|
||||
printf("No state program exists for task id %d\n", tid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pSP;
|
||||
}
|
||||
|
||||
LOCAL int seqProgCount;
|
||||
|
||||
/* This routine is called by seqTraverseProg() for seqShowAll() */
|
||||
LOCAL void seqShowSP(pSP)
|
||||
SPROG *pSP;
|
||||
{
|
||||
SSCB *pSS;
|
||||
int nss;
|
||||
char *progName, *ptaskName;;
|
||||
|
||||
if (seqProgCount++ == 0)
|
||||
printf("Program Name Task ID Task Name SS Name\n\n");
|
||||
|
||||
progName = pSP->pProgName;
|
||||
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
if (pSS->taskId == 0)
|
||||
ptaskName = "(no task)";
|
||||
else
|
||||
ptaskName = taskName(pSS->taskId);
|
||||
printf("%-16s %-10lu %-16s %-16s\n",
|
||||
progName, (unsigned long) pSS->taskId,
|
||||
ptaskName, pSS->pSSName );
|
||||
progName = "";
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* The seqTraverseProg function is in seq_prog.c */
|
||||
STATUS seqTraverseProg(VOID (*pFunc)(), VOID *param);
|
||||
|
||||
/* Print a brief summary of all state programs */
|
||||
LOCAL void seqShowAll()
|
||||
{
|
||||
|
||||
seqProgCount = 0;
|
||||
seqTraverseProg(seqShowSP, 0);
|
||||
if (seqProgCount == 0)
|
||||
printf("No active state programs\n");
|
||||
return;
|
||||
}
|
||||
@@ -1,573 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
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
|
||||
|
||||
DESCRIPTION: Seq_tasks.c: Task creation and control for sequencer
|
||||
state sets.
|
||||
|
||||
ENVIRONMENT: VxWorks
|
||||
HISTORY
|
||||
04dec91,ajk Implemented linked list of state programs, eliminating task
|
||||
variables.
|
||||
11dec91,ajk Made cosmetic changes and cleaned up comments.
|
||||
19dec91,ajk Changed algoritm in seq_getTimeout().
|
||||
29apr92,ajk Implemented new event flag mode.
|
||||
30apr92,ajk Periodically call ca_pend_event() to detect connection failures.
|
||||
21may92,ajk In sprog_delete() wait for loggin semaphore before suspending tasks.
|
||||
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().
|
||||
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
|
||||
20jul95,ajk Add user-specified task priority to taskSpwan().
|
||||
***************************************************************************/
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define ANSI
|
||||
#include "seqCom.h"
|
||||
#include "seq.h"
|
||||
#include "taskwd.h"
|
||||
#include "logLib.h"
|
||||
#include "tickLib.h"
|
||||
#include "taskVarLib.h"
|
||||
|
||||
/* Function declarations */
|
||||
LOCAL VOID seq_waitConnect(SPROG *pSP, SSCB *pSS);
|
||||
LOCAL VOID ss_task_init(SPROG *, SSCB *);
|
||||
LOCAL VOID seq_clearDelay(SSCB *);
|
||||
LOCAL int seq_getTimeout(SSCB *);
|
||||
LOCAL long seq_cleanup(int tid, SPROG *pSP, SEM_ID cleanupSem);
|
||||
|
||||
#define TASK_NAME_SIZE 10
|
||||
|
||||
|
||||
STATUS seqAddProg(SPROG *pSP);
|
||||
long seq_connect(SPROG *pSP);
|
||||
long seq_disconnect(SPROG *pSP);
|
||||
/*
|
||||
* sequencer() - Sequencer main task entry point.
|
||||
*/
|
||||
long sequencer (pSP, stack_size, pTaskName)
|
||||
SPROG *pSP; /* ptr to original (global) state program table */
|
||||
long stack_size; /* stack size */
|
||||
char *pTaskName; /* Parent task name */
|
||||
{
|
||||
SSCB *pSS;
|
||||
int nss, task_id;
|
||||
char task_name[TASK_NAME_SIZE+10];
|
||||
extern VOID ss_entry();
|
||||
extern int seqAuxTaskId;
|
||||
|
||||
pSP->taskId = taskIdSelf(); /* my task id */
|
||||
pSS = pSP->pSS;
|
||||
pSS->taskId = pSP->taskId;
|
||||
|
||||
/* Add the program to the state program list */
|
||||
seqAddProg(pSP);
|
||||
|
||||
/* Import Channel Access context from the auxillary seq. task */
|
||||
ca_import(seqAuxTaskId);
|
||||
|
||||
/* Initiate connect & monitor requests to database channels. */
|
||||
seq_connect(pSP);
|
||||
|
||||
/* Additional state set task names are derived from the first ss */
|
||||
if (strlen(pTaskName) > TASK_NAME_SIZE)
|
||||
pTaskName[TASK_NAME_SIZE] = 0;
|
||||
|
||||
/* Create each additional state set task */
|
||||
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", pTaskName, nss);
|
||||
|
||||
/* Spawn the task */
|
||||
task_id = taskSpawn(
|
||||
task_name, /* task name */
|
||||
pSP->taskPriority, /* priority */
|
||||
SPAWN_OPTIONS, /* task options */
|
||||
stack_size, /* stack size */
|
||||
(FUNCPTR)ss_entry, /* entry point */
|
||||
(int)pSP, (int)pSS, 0,0,0,0,0,0,0,0); /* pass 2 parameters */
|
||||
|
||||
seq_log(pSP, "Spawning task %d: \"%s\"\n", task_id, task_name);
|
||||
}
|
||||
|
||||
/* First state set jumps directly to entry point */
|
||||
ss_entry(pSP, pSP->pSS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* ss_entry() - Task entry point for all state sets.
|
||||
* Provides the main loop for state set processing.
|
||||
*/
|
||||
VOID ss_entry(pSP, pSS)
|
||||
SPROG *pSP;
|
||||
SSCB *pSS;
|
||||
{
|
||||
BOOL ev_trig;
|
||||
STATE *pST, *pStNext;
|
||||
long delay;
|
||||
char *pVar;
|
||||
int nWords;
|
||||
SS_ID ssId;
|
||||
|
||||
/* Initialize all ss tasks */
|
||||
ss_task_init(pSP, pSS);
|
||||
|
||||
/* If "+c" option, wait for all channels to connect */
|
||||
if ((pSP->options & OPT_CONN) != 0)
|
||||
seq_waitConnect(pSP, pSS);
|
||||
|
||||
/* Initilaize state set to enter the first state */
|
||||
pST = pSS->pStates;
|
||||
pSS->currentState = 0;
|
||||
|
||||
/* Use the event mask for this state */
|
||||
pSS->pMask = (pST->pEventMask);
|
||||
nWords = (pSP->numEvents + NBITS - 1) / NBITS;
|
||||
|
||||
/* Local ptr to user variables (for reentrant code only) */
|
||||
pVar = pSP->pVar;
|
||||
|
||||
/* State set id */
|
||||
ssId = (SS_ID)pSS;
|
||||
|
||||
/*
|
||||
* ============= Main loop ==============
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
seq_clearDelay(pSS); /* Clear delay list */
|
||||
pST->delayFunc(ssId, pVar); /* Set up new delay list */
|
||||
|
||||
/* Setting this semaphor here guarantees that a when() is always
|
||||
* executed at least once when a state is first entered. */
|
||||
semGive(pSS->syncSemId);
|
||||
|
||||
/*
|
||||
* Loop until an event is triggered, i.e. when() returns TRUE
|
||||
*/
|
||||
do {
|
||||
/* Wake up on CA event, event flag, or expired time delay */
|
||||
delay = seq_getTimeout(pSS); /* min. delay from list */
|
||||
if (delay > 0)
|
||||
semTake(pSS->syncSemId, delay);
|
||||
|
||||
/* Call the event function to check for an event trigger.
|
||||
* The statement inside the when() statement is executed.
|
||||
* Note, we lock out CA events while doing this.
|
||||
*/
|
||||
semTake(pSP->caSemId, WAIT_FOREVER);
|
||||
|
||||
ev_trig = pST->eventFunc(ssId, pVar,
|
||||
&pSS->transNum, &pSS->nextState); /* check events */
|
||||
|
||||
/* 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 < 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->pStates + pSS->nextState;
|
||||
pSS->pMask = (pStNext->pEventMask);
|
||||
|
||||
/* Execute the action for this event */
|
||||
pST->actionFunc(ssId, pVar, pSS->transNum);
|
||||
|
||||
/* Flush any outstanding DB requests */
|
||||
ca_flush_io();
|
||||
|
||||
/* Change to next state */
|
||||
pSS->prevState = pSS->currentState;
|
||||
pSS->currentState = pSS->nextState;
|
||||
pST = pSS->pStates + pSS->currentState;
|
||||
}
|
||||
}
|
||||
/* Initialize state-set tasks */
|
||||
LOCAL VOID ss_task_init(pSP, pSS)
|
||||
SPROG *pSP;
|
||||
SSCB *pSS;
|
||||
{
|
||||
extern int seqAuxTaskId;
|
||||
|
||||
/* Get this task's id */
|
||||
pSS->taskId = taskIdSelf();
|
||||
|
||||
/* Import Channel Access context from the auxillary seq. task */
|
||||
if (pSP->taskId != pSS->taskId)
|
||||
ca_import(seqAuxTaskId);
|
||||
|
||||
/* Register this task with the EPICS watchdog (no callback function) */
|
||||
taskwdInsert(pSS->taskId, (VOIDFUNCPTR)0, (VOID *)0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all channels to connect */
|
||||
LOCAL VOID seq_waitConnect(SPROG *pSP, SSCB *pSS)
|
||||
{
|
||||
STATUS status;
|
||||
long delay;
|
||||
|
||||
delay = 600; /* 10, 20, 30, 40, 40,... sec */
|
||||
while (pSP->connCount < pSP->assignCount)
|
||||
{
|
||||
status = semTake(pSS->syncSemId, delay);
|
||||
if ((status != OK) && (pSP-> taskId == pSS->taskId))
|
||||
{
|
||||
logMsg("%d of %d assigned channels have connected\n",
|
||||
pSP->connCount, pSP->assignCount, 0,0,0,0);
|
||||
}
|
||||
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 INT_MAX if no delays pending
|
||||
* An "int" is returned because this is what semTake() expects
|
||||
*/
|
||||
LOCAL int seq_getTimeout(pSS)
|
||||
SSCB *pSS;
|
||||
{
|
||||
int ndelay, delayMinInit;
|
||||
ULONG cur, delay, delayMin, delayN;
|
||||
|
||||
if (pSS->numDelays == 0)
|
||||
return INT_MAX;
|
||||
|
||||
/*
|
||||
* calculate the delay since this state was entered
|
||||
*/
|
||||
cur = tickGet();
|
||||
if (cur >= pSS->timeEntered) {
|
||||
delay = cur - pSS->timeEntered;
|
||||
}
|
||||
else {
|
||||
delay = cur + (ULONG_MAX - pSS->timeEntered);
|
||||
}
|
||||
|
||||
delayMinInit = 0;
|
||||
delayMin = ULONG_MAX;
|
||||
|
||||
/* Find the minimum delay among all non-expired timeouts */
|
||||
for (ndelay = 0; ndelay < pSS->numDelays; ndelay++)
|
||||
{
|
||||
if (pSS->delayExpired[ndelay])
|
||||
continue; /* skip if this delay entry already expired */
|
||||
|
||||
delayN = pSS->delay[ndelay];
|
||||
if (delay >= delayN)
|
||||
{ /* just expired */
|
||||
pSS->delayExpired[ndelay] = TRUE; /* mark as expired */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delayN<=delayMin) {
|
||||
delayMinInit=1;
|
||||
delayMin = delayN; /* this is the min. delay so far */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no unexpired delay in the list
|
||||
* then wait forever until there is a PV state
|
||||
* change
|
||||
*/
|
||||
if (!delayMinInit) {
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* unexpired delay _is_ in the list
|
||||
*/
|
||||
if (delayMin>delay) {
|
||||
delay = delayMin - delay;
|
||||
|
||||
/*
|
||||
* clip to the range of a valid delay in semTake()
|
||||
*/
|
||||
if (delay<INT_MAX) {
|
||||
return delay;
|
||||
}
|
||||
else {
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all state set tasks and do general clean-up.
|
||||
* 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.
|
||||
* 4. Cancel the channel access context.
|
||||
* 5. Delete all state set tasks except self.
|
||||
* 6. Delete semaphores, close log file, and free allocated memory.
|
||||
* 7. Return, causing self to be deleted.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
long sprog_delete(tid)
|
||||
int tid; /* task being deleted */
|
||||
{
|
||||
SPROG *pSP;
|
||||
SEM_ID cleanupSem;
|
||||
int status;
|
||||
|
||||
pSP = seqFindProg(tid);
|
||||
if (pSP == NULL)
|
||||
return -1; /* not a state program task */
|
||||
|
||||
/* Create a semaphore for cleanup task */
|
||||
cleanupSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
|
||||
|
||||
/* Spawn the cleanup task */
|
||||
taskSpawn("tSeqCleanup", SPAWN_PRIORITY-1, VX_FP_TASK, 8000,
|
||||
(FUNCPTR)seq_cleanup, tid, (int)pSP, (int)cleanupSem, 0,0,0,0,0,0,0);
|
||||
|
||||
/* Wait for cleanup task completion */
|
||||
for (;;)
|
||||
{
|
||||
status = semTake(cleanupSem, 600);
|
||||
if (status == OK)
|
||||
break;
|
||||
logMsg("sprog_delete waiting for seq_cleanup\n", 0,0,0,0,0,0);
|
||||
}
|
||||
semDelete(cleanupSem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup task */
|
||||
/*#define DEBUG_CLEANUP*/
|
||||
STATUS seqDelProg(SPROG *pSP);
|
||||
|
||||
LOCAL long seq_cleanup(int tid, SPROG *pSP, SEM_ID cleanupSem)
|
||||
{
|
||||
int nss;
|
||||
SSCB *pSS;
|
||||
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg("Delete %s: pSP=%d=0x%x, tid=%d\n", pSP->pProgName, pSP, pSP, tid, 0,0);
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
|
||||
/* Wait for log semaphore (in case a task is doing a write) */
|
||||
semTake(pSP->logSemId, 600);
|
||||
|
||||
/* Remove tasks' watchdog & suspend all state set tasks except self */
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" Suspending state set tasks:\n");
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
pSS = pSP->pSS;
|
||||
for (nss = 0; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
if (pSS->taskId == 0)
|
||||
continue;
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" tid=%d\n", pSS->taskId);
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
/* Remove the task from EPICS watchdog */
|
||||
taskwdRemove(pSS->taskId);
|
||||
|
||||
/* Suspend the task */
|
||||
if (pSS->taskId != tid)
|
||||
taskSuspend(pSS->taskId);
|
||||
}
|
||||
|
||||
/* Give back log semaphore */
|
||||
semGive(pSP->logSemId);
|
||||
|
||||
/* Call user exit routine (only if task has run) */
|
||||
if (pSP->pSS->taskId != 0)
|
||||
{
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" Call exit function\n");
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
pSP->exitFunc( (SS_ID)pSP->pSS, pSP->pVar);
|
||||
}
|
||||
|
||||
/* Disconnect all channels */
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" Disconnect all channels\n");
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
|
||||
seq_disconnect(pSP);
|
||||
|
||||
/* Cancel the CA context for each state set task */
|
||||
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
if (pSS->taskId == 0)
|
||||
continue;
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" ca_import_cancel(0x%x)\n", pSS->taskId);
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
SEVCHK (ca_import_cancel(pSS->taskId),
|
||||
"seq_cleanup:ca_import_cancel() failed")
|
||||
}
|
||||
|
||||
/* Close the log file */
|
||||
if ( (pSP->logFd > 0) && (pSP->logFd != ioGlobalStdGet(1)) )
|
||||
{
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg("Closing log fd=%d\n", pSP->logFd);
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
close(pSP->logFd);
|
||||
pSP->logFd = ioGlobalStdGet(1);
|
||||
}
|
||||
|
||||
/* Remove the state program from the state program list */
|
||||
seqDelProg(pSP);
|
||||
|
||||
/* Delete state set tasks (except self) & delete their semaphores */
|
||||
pSS = pSP->pSS;
|
||||
for (nss = 0; nss < pSP->numSS; nss++, pSS++)
|
||||
{
|
||||
if ( (pSS->taskId != tid) && (pSS->taskId != 0) )
|
||||
{
|
||||
#ifdef DEBUG_CLEANUP
|
||||
logMsg(" delete ss task: tid=%d\n", pSS->taskId);
|
||||
#endif /*DEBUG_CLEANUP*/
|
||||
taskDelete(pSS->taskId);
|
||||
}
|
||||
|
||||
if (pSS->syncSemId != 0)
|
||||
semDelete(pSS->syncSemId);
|
||||
|
||||
if (pSS->getSemId != 0)
|
||||
semDelete(pSS->getSemId);
|
||||
}
|
||||
|
||||
/* Delete program-wide semaphores */
|
||||
semDelete(pSP->caSemId);
|
||||
semDelete(pSP->logSemId);
|
||||
|
||||
/* Free all allocated memory */
|
||||
taskDelay(5);
|
||||
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().
|
||||
*/
|
||||
long seqAuxTask()
|
||||
{
|
||||
extern int seqAuxTaskId;
|
||||
|
||||
/* Register this task with the EPICS watchdog */
|
||||
taskwdInsert(taskIdSelf(),(VOIDFUNCPTR)0, (VOID *)0);
|
||||
/* Set up so all state program tasks will use a common CA context */
|
||||
ca_task_initialize();
|
||||
seqAuxTaskId = taskIdSelf(); /* must follow ca_task_initialize() */
|
||||
|
||||
/* This loop allows CA to check for connect/disconnect on channels */
|
||||
for (;;)
|
||||
{
|
||||
ca_pend_event(10.0); /* returns every 10 sec. */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
%{
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
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.
|
||||
20jul95,ajk Added "unsigned" types (see UNSIGNED token).
|
||||
11jul96,ajk Added character constants (CHAR_CONST).
|
||||
13jan98,wfl Added "down a level" handling of compound expressions
|
||||
09jun98,wfl Permitted pre-processor "#" lines between state-sets
|
||||
***************************************************************************/
|
||||
/* SNC - State Notation Compiler.
|
||||
* The general structure of a state program is:
|
||||
* program-name
|
||||
* declarations
|
||||
* ss { state { event { action ...} new-state } ... } ...
|
||||
*
|
||||
* The following yacc definitions call the various parsing routines, which
|
||||
* are coded in the file "parse.c". Their major action is to build
|
||||
* a structure for each SNL component (state, event, action, etc.) and
|
||||
* build linked lists from these structures. The linked lists have a
|
||||
* hierarchical structure corresponding to the SNL block structure.
|
||||
* For instance, a "state" structure is linked to a chain of "event",
|
||||
* structures, which are, in turn, linked to a chain of "action"
|
||||
* structures.
|
||||
* The lexical analyser (see snc_lax.l) reads the input
|
||||
* stream and passes tokens to the yacc-generated code. The snc_lex
|
||||
* and parsing routines may also pass data elements that take on one
|
||||
* of the types defined under the %union definition.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "parse.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif /* TRUE */
|
||||
|
||||
extern int line_num; /* input file line no. */
|
||||
%}
|
||||
|
||||
%start state_program
|
||||
|
||||
%union
|
||||
{
|
||||
int ival;
|
||||
char *pchar;
|
||||
void *pval;
|
||||
Expr *pexpr;
|
||||
}
|
||||
%token <pchar> STATE STATE_SET
|
||||
%token <pchar> NUMBER NAME
|
||||
%token <pchar> CHAR_CONST
|
||||
%token <pchar> DEBUG_PRINT
|
||||
%token PROGRAM EXIT OPTION
|
||||
%token R_SQ_BRACKET L_SQ_BRACKET
|
||||
%token BAD_CHAR L_BRACKET R_BRACKET
|
||||
%token COLON SEMI_COLON EQUAL
|
||||
%token L_PAREN R_PAREN PERIOD POINTER COMMA OR AND
|
||||
%token MONITOR ASSIGN TO WHEN
|
||||
%token UNSIGNED CHAR SHORT INT LONG FLOAT DOUBLE STRING_DECL
|
||||
%token EVFLAG SYNC
|
||||
%token ASTERISK AMPERSAND
|
||||
%token AUTO_INCR AUTO_DECR
|
||||
%token PLUS MINUS SLASH GT GE EQ LE LT NE NOT BIT_OR BIT_AND
|
||||
%token L_SHIFT R_SHIFT COMPLEMENT MODULO
|
||||
%token PLUS_EQUAL MINUS_EQUAL MULT_EQUAL DIV_EQUAL AND_EQUAL OR_EQUAL
|
||||
%token MODULO_EQUAL LEFT_EQUAL RIGHT_EQUAL CMPL_EQUAL
|
||||
%token <pchar> STRING
|
||||
%token <pchar> C_STMT
|
||||
%token IF ELSE WHILE FOR BREAK
|
||||
%token PP_SYMBOL CR
|
||||
%type <ival> type
|
||||
%type <pchar> subscript binop asgnop unop
|
||||
%type <pexpr> state_set_list state_set state_list state transition_list transition
|
||||
%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 escaped_c_list
|
||||
/* precidence rules for expr evaluation */
|
||||
%right EQUAL COMMA
|
||||
%left OR AND
|
||||
%left GT GE EQ NE LE LT
|
||||
%left PLUS MINUS
|
||||
%left ASTERISK SLASH
|
||||
%left NOT UOP /* unary operators: e.g. -x */
|
||||
%left SUBSCRIPT
|
||||
|
||||
%% /* Begin rules */
|
||||
|
||||
state_program /* define a state program */
|
||||
: program_name definitions state_set_list { program($3); }
|
||||
| program_name definitions state_set_list global_c { program($3); }
|
||||
| pp_code program_name definitions state_set_list { program($4); }
|
||||
| pp_code program_name definitions state_set_list global_c{ program($4); }
|
||||
| error { snc_err("state program"); }
|
||||
;
|
||||
|
||||
program_name /* program name */
|
||||
: PROGRAM NAME { program_name($2, ""); }
|
||||
| PROGRAM NAME L_PAREN STRING R_PAREN { program_name($2, $4); }
|
||||
;
|
||||
|
||||
definitions /* definitions block */
|
||||
: defn_stmt
|
||||
| definitions defn_stmt
|
||||
;
|
||||
|
||||
defn_stmt /* individual definitions for SNL (preceeds state sets) */
|
||||
: assign_stmt
|
||||
| monitor_stmt
|
||||
| decl_stmt
|
||||
| debug_stmt
|
||||
| sync_stmt
|
||||
| option_stmt
|
||||
| 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_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, NULL); }
|
||||
| MONITOR NAME subscript SEMI_COLON { monitor_stmt($2, $3); }
|
||||
;
|
||||
|
||||
subscript /* e.g. [10] */
|
||||
: 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];)
|
||||
* 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 */
|
||||
: CHAR { $$ = V_CHAR; }
|
||||
| SHORT { $$ = V_SHORT; }
|
||||
| INT { $$ = V_INT; }
|
||||
| LONG { $$ = V_LONG; }
|
||||
| UNSIGNED CHAR { $$ = V_UCHAR; }
|
||||
| UNSIGNED SHORT { $$ = V_USHORT; }
|
||||
| UNSIGNED INT { $$ = V_UINT; }
|
||||
| UNSIGNED LONG { $$ = V_ULONG; }
|
||||
| FLOAT { $$ = V_FLOAT; }
|
||||
| DOUBLE { $$ = V_DOUBLE; }
|
||||
| STRING_DECL { $$ = V_STRING; }
|
||||
| EVFLAG { $$ = V_EVFLAG; }
|
||||
;
|
||||
|
||||
sync_stmt /* sync <variable> <event flag> */
|
||||
: 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; */
|
||||
: OPTION PLUS NAME SEMI_COLON { option_stmt($3, TRUE); }
|
||||
| OPTION MINUS NAME SEMI_COLON { option_stmt($3, FALSE); }
|
||||
;
|
||||
|
||||
state_set_list /* a program body is one or more state sets */
|
||||
: state_set { $$ = $1; }
|
||||
| state_set_list state_set { $$ = link_expr($1, $2); }
|
||||
;
|
||||
|
||||
state_set /* define a state set */
|
||||
: STATE_SET NAME L_BRACKET state_list R_BRACKET
|
||||
{ $$ = expression(E_SS, $2, $4, 0); }
|
||||
| EXIT L_BRACKET stmt_list R_BRACKET
|
||||
{ exit_code($3); $$ = 0; }
|
||||
| pp_code { $$ = 0; }
|
||||
| error { snc_err("state set"); }
|
||||
;
|
||||
|
||||
state_list /* define a state set body (one or more states) */
|
||||
: state { $$ = $1; }
|
||||
| state_list state { $$ = link_expr($1, $2); }
|
||||
| error { snc_err("state set"); }
|
||||
;
|
||||
|
||||
state /* a block that defines a single state */
|
||||
: STATE NAME L_BRACKET transition_list R_BRACKET
|
||||
{ $$ = expression(E_STATE, $2, $4, 0); }
|
||||
| error { snc_err("state block"); }
|
||||
;
|
||||
|
||||
transition_list /* all transitions for one state */
|
||||
: transition { $$ = $1; }
|
||||
| transition_list transition { $$ = link_expr($1, $2); }
|
||||
| error { snc_err("transition"); }
|
||||
;
|
||||
|
||||
transition /* define a transition ("when" statment ) */
|
||||
: WHEN L_PAREN expr R_PAREN L_BRACKET stmt_list R_BRACKET STATE NAME
|
||||
{ $$ = expression(E_WHEN, $9, $3, $6); }
|
||||
;
|
||||
|
||||
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) */
|
||||
: compound_expr { $$ = expression(E_COMMA, "", $1, 0); }
|
||||
| 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); }
|
||||
| AUTO_DECR expr %prec UOP { $$ = expression(E_PRE, "--", $2, 0); }
|
||||
| expr AUTO_INCR %prec UOP { $$ = expression(E_POST, "++", $1, 0); }
|
||||
| expr AUTO_DECR %prec UOP { $$ = expression(E_POST, "--", $1, 0); }
|
||||
| NUMBER { $$ = expression(E_CONST, $1, 0, 0); }
|
||||
| CHAR_CONST { $$ = expression(E_CONST, $1, 0, 0); }
|
||||
| STRING { $$ = expression(E_STRING, $1, 0, 0); }
|
||||
| NAME { $$ = expression(E_VAR, $1, 0, 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 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 */
|
||||
: PLUS { $$ = "+"; }
|
||||
| MINUS { $$ = "-"; }
|
||||
| ASTERISK { $$ = "*"; }
|
||||
| AMPERSAND { $$ = "&"; }
|
||||
| NOT { $$ = "!"; }
|
||||
;
|
||||
|
||||
binop /* Binary operators */
|
||||
: MINUS { $$ = "-"; }
|
||||
| PLUS { $$ = "+"; }
|
||||
| ASTERISK { $$ = "*"; }
|
||||
| SLASH { $$ = "/"; }
|
||||
| GT { $$ = ">"; }
|
||||
| GE { $$ = ">="; }
|
||||
| EQ { $$ = "=="; }
|
||||
| NE { $$ = "!="; }
|
||||
| LE { $$ = "<="; }
|
||||
| LT { $$ = "<"; }
|
||||
| OR { $$ = "||"; }
|
||||
| AND { $$ = "&&"; }
|
||||
| L_SHIFT { $$ = "<<"; }
|
||||
| R_SHIFT { $$ = ">>"; }
|
||||
| BIT_OR { $$ = "|"; }
|
||||
| BIT_AND { $$ = "&"; }
|
||||
| COMPLEMENT { $$ = "^"; }
|
||||
| MODULO { $$ = "%"; }
|
||||
| PERIOD { $$ = "."; } /* fudges structure elements */
|
||||
| POINTER { $$ = "->"; } /* fudges ptr to structure elements */
|
||||
;
|
||||
|
||||
asgnop /* Assignment operators */
|
||||
: EQUAL { $$ = "="; }
|
||||
| PLUS_EQUAL { $$ = "+="; }
|
||||
| MINUS_EQUAL { $$ = "-="; }
|
||||
| AND_EQUAL { $$ = "&="; }
|
||||
| OR_EQUAL { $$ = "|="; }
|
||||
| DIV_EQUAL { $$ = "/="; }
|
||||
| MULT_EQUAL { $$ = "*="; }
|
||||
| MODULO_EQUAL { $$ = "%="; }
|
||||
| LEFT_EQUAL { $$ = "<<="; }
|
||||
| RIGHT_EQUAL { $$ = ">>="; }
|
||||
| CMPL_EQUAL { $$ = "^="; }
|
||||
;
|
||||
|
||||
compound_stmt /* compound statement e.g. { ...; ...; ...; } */
|
||||
: L_BRACKET stmt_list R_BRACKET { $$ = expression(E_CMPND, "",$2, 0); }
|
||||
| error { snc_err("action statements"); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: statement { $$ = $1; }
|
||||
| stmt_list statement { $$ = link_expr($1, $2); }
|
||||
| /* empty */ { $$ = 0; }
|
||||
;
|
||||
|
||||
statement
|
||||
: compound_stmt { $$ = $1; }
|
||||
| expr SEMI_COLON { $$ = expression(E_STMT, "", $1, 0); }
|
||||
| BREAK SEMI_COLON { $$ = expression(E_BREAK, "", 0, 0); }
|
||||
| if_stmt { $$ = $1; }
|
||||
| else_stmt { $$ = $1; }
|
||||
| while_stmt { $$ = $1; }
|
||||
| for_stmt { $$ = $1; }
|
||||
| C_STMT { $$ = expression(E_TEXT, "", $1, 0); }
|
||||
| pp_code { $$ = 0; }
|
||||
| error { snc_err("action statement"); }
|
||||
;
|
||||
|
||||
if_stmt
|
||||
: IF L_PAREN expr R_PAREN statement { $$ = expression(E_IF, "", $3, $5); }
|
||||
;
|
||||
|
||||
else_stmt
|
||||
: ELSE statement { $$ = expression(E_ELSE, "", $2, 0); }
|
||||
;
|
||||
|
||||
while_stmt
|
||||
: WHILE L_PAREN expr R_PAREN statement { $$ = expression(E_WHILE, "", $3, $5); }
|
||||
;
|
||||
|
||||
for_stmt
|
||||
: FOR L_PAREN expr SEMI_COLON expr SEMI_COLON expr R_PAREN statement
|
||||
{ $$ = expression(E_FOR, "", expression(E_X, "", $3, $5),
|
||||
expression(E_X, "", $7, $9) ); }
|
||||
;
|
||||
|
||||
pp_code /* pre-processor code (e.g. # 1 "test.st") */
|
||||
: PP_SYMBOL NUMBER STRING CR { pp_code($2, $3, ""); }
|
||||
| PP_SYMBOL NUMBER STRING NUMBER CR { pp_code($2, $3, $4); }
|
||||
;
|
||||
|
||||
global_c
|
||||
: 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"
|
||||
|
||||
static int yyparse (void);
|
||||
|
||||
/* yyparse() is static, so we create global access to it */
|
||||
void Global_yyparse (void)
|
||||
{
|
||||
yyparse ();
|
||||
}
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
%{
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
snc_lex.l,v 1.2 1995/06/27 15:26:09 wright Exp
|
||||
ENVIRONMENT: UNIX
|
||||
HISTORY:
|
||||
20nov91,ajk Added OPTION token.
|
||||
15jan92,ajk Fixed to allow "!" as a unary operator.
|
||||
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.
|
||||
20jul95,ajk Added unsigned types.
|
||||
11jul96,ajk Added character constants
|
||||
01oct98,wfl Replaced FPNUM with version from Sun lex manual ("E" support)
|
||||
***************************************************************************/
|
||||
/* Lexical analyzer for State Notation Compiler (snc).
|
||||
*
|
||||
* This routine recognizes State Notation Language (SNL) syntax,
|
||||
* and passes tokens to yacc().
|
||||
* All C code is passed through as a stream, without conversion.
|
||||
* Hence, the C compiler may find errors not reported by SNC.
|
||||
* Comments are recognized as part of the syntax.
|
||||
*/
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
/*#define DEBUG 1*/
|
||||
#ifdef DEBUG
|
||||
#define RETURN(param) { fprintf(stderr, "return(param)\n"); return(param); }
|
||||
#else
|
||||
#define RETURN(param) return(param);
|
||||
#endif
|
||||
#define STR_BFR_SIZE 1000
|
||||
|
||||
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; /* TRUE for %%; FALSE for %{...}% */
|
||||
|
||||
%}
|
||||
|
||||
/* Start conditions (SNL, C code, comment, string, pre-processor, pre-proc. string) */
|
||||
%Start SNL C_CODE COMMENT STR PP PP_STR
|
||||
|
||||
/* FPNUM was:
|
||||
FPNUM (([0-9]+)(\.[0-9]*)?)|(\.[0-9]+)
|
||||
replaced 01-Oct-98 */
|
||||
|
||||
NAME [a-zA-Z][a-zA-Z0-9_]*
|
||||
DIG [0-9]
|
||||
EXP [DEde][-+]?{DIG}+
|
||||
FPNUM {DIG}+({EXP})?|{DIG}+\.{DIG}*({EXP})?|{DIG}*\.{DIG}+({EXP})?
|
||||
OCTAL 0[0-7]+
|
||||
HEX 0x([0-9a-fA-F])+
|
||||
CCONST \'.\'
|
||||
|
||||
%% /* Begin rules */
|
||||
<C_CODE>. *pStr++ = yytext[0];
|
||||
<C_CODE>\n {
|
||||
*pStr++ = 0;
|
||||
line_num++;
|
||||
c_line_num = line_num;
|
||||
yylval.pchar = strdup(strBfr);
|
||||
pStr = strBfr;
|
||||
if (one_line_c_code)
|
||||
BEGIN SNL;
|
||||
RETURN(C_STMT);
|
||||
}
|
||||
<C_CODE>"}%" {
|
||||
*pStr++ = 0;
|
||||
yylval.pchar = strdup(strBfr);
|
||||
BEGIN SNL;
|
||||
RETURN(C_STMT);
|
||||
}
|
||||
<COMMENT>\n line_num++;
|
||||
<COMMENT>"*/" BEGIN SNL;
|
||||
<COMMENT>. ;
|
||||
<STR>"\\\"" {
|
||||
*pStr++ = yytext[0];
|
||||
*pStr++ = yytext[1];
|
||||
}
|
||||
<STR>\" {
|
||||
*pStr++ = 0;
|
||||
yylval.pchar = strdup(strBfr);
|
||||
BEGIN SNL;
|
||||
RETURN(STRING);
|
||||
}
|
||||
<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} { yylval.pchar = strdup(yytext);
|
||||
RETURN(NUMBER);
|
||||
}
|
||||
<PP>\" { pStr = strBfr; BEGIN PP_STR; }
|
||||
<PP>\n {
|
||||
BEGIN SNL;
|
||||
RETURN(CR);
|
||||
}
|
||||
<PP>[\t\ ]* /* no action */ ;
|
||||
<PP>. {
|
||||
}
|
||||
<PP_STR>\" {
|
||||
*pStr++ = 0;
|
||||
yylval.pchar = strdup(strBfr);
|
||||
BEGIN PP;
|
||||
RETURN(STRING);
|
||||
}
|
||||
<PP_STR>. { *pStr++ = yytext[0]; }
|
||||
<PP_STR>\n { *pStr++ = '?'; line_num++; }
|
||||
<SNL>\n { line_num++; }
|
||||
<SNL>"%{" {
|
||||
pStr = strBfr;
|
||||
one_line_c_code = FALSE;
|
||||
c_line_num = line_num;
|
||||
BEGIN C_CODE;
|
||||
}
|
||||
<SNL>"%%" {
|
||||
pStr = strBfr;
|
||||
one_line_c_code = TRUE;
|
||||
c_line_num = line_num;
|
||||
BEGIN C_CODE;
|
||||
}
|
||||
<SNL>^# {
|
||||
BEGIN PP;
|
||||
RETURN(PP_SYMBOL);
|
||||
}
|
||||
<SNL>"/*" BEGIN COMMENT;
|
||||
<SNL>\" { pStr = strBfr; BEGIN STR; }
|
||||
<SNL>"ss" RETURN(STATE_SET);
|
||||
<SNL>"state" RETURN(STATE);
|
||||
<SNL>"when" RETURN(WHEN);
|
||||
<SNL>"monitor" RETURN(MONITOR);
|
||||
<SNL>"assign" RETURN(ASSIGN);
|
||||
<SNL>"unsigned" RETURN(UNSIGNED);
|
||||
<SNL>"char" RETURN(CHAR);
|
||||
<SNL>"short" RETURN(SHORT);
|
||||
<SNL>"int" RETURN(INT);
|
||||
<SNL>"long" RETURN(LONG);
|
||||
<SNL>"float" RETURN(FLOAT);
|
||||
<SNL>"double" RETURN(DOUBLE);
|
||||
<SNL>"string" RETURN(STRING_DECL);
|
||||
<SNL>"to" RETURN(TO);
|
||||
<SNL>"program" RETURN(PROGRAM);
|
||||
<SNL>"option" RETURN(OPTION);
|
||||
<SNL>"debug" RETURN(DEBUG_PRINT);
|
||||
<SNL>"evflag" RETURN(EVFLAG);
|
||||
<SNL>"sync" RETURN(SYNC);
|
||||
<SNL>"if" RETURN(IF);
|
||||
<SNL>"else" RETURN(ELSE);
|
||||
<SNL>"while" RETURN(WHILE);
|
||||
<SNL>"for" RETURN(FOR);
|
||||
<SNL>"break" RETURN(BREAK);
|
||||
<SNL>"exit" RETURN(EXIT);
|
||||
<SNL>"TRUE" { yylval.pchar = "1";
|
||||
RETURN(NUMBER);
|
||||
}
|
||||
<SNL>"FALSE" {
|
||||
yylval.pchar = "0";
|
||||
RETURN(NUMBER);
|
||||
}
|
||||
<SNL>{NAME} {
|
||||
yylval.pchar = strdup(yytext);
|
||||
RETURN(NAME);
|
||||
}
|
||||
<SNL>"++" RETURN(AUTO_INCR);
|
||||
<SNL>"--" RETURN(AUTO_DECR);
|
||||
<SNL>"||" RETURN(OR);
|
||||
<SNL>"<<=" RETURN(LEFT_EQUAL);
|
||||
<SNL>">>=" RETURN(RIGHT_EQUAL);
|
||||
<SNL>"&&" RETURN(AND);
|
||||
<SNL>">>" RETURN(R_SHIFT);
|
||||
<SNL>">=" RETURN(GE);
|
||||
<SNL>"==" RETURN(EQ);
|
||||
<SNL>"+=" RETURN(PLUS_EQUAL);
|
||||
<SNL>"-=" RETURN(MINUS_EQUAL);
|
||||
<SNL>"*=" RETURN(MULT_EQUAL);
|
||||
<SNL>"/=" RETURN(DIV_EQUAL);
|
||||
<SNL>"&=" RETURN(AND_EQUAL);
|
||||
<SNL>"|=" RETURN(OR_EQUAL);
|
||||
<SNL>"!=" RETURN(NE);
|
||||
<SNL>"<<" RETURN(L_SHIFT);
|
||||
<SNL>"<=" RETURN(LE);
|
||||
<SNL>"%=" RETURN(MODULO_EQUAL);
|
||||
<SNL>"^=" RETURN(CMPL_EQUAL);
|
||||
<SNL>"->" RETURN(POINTER);
|
||||
<SNL>"+" RETURN(PLUS);
|
||||
<SNL>"-" RETURN(MINUS);
|
||||
<SNL>"!" RETURN(NOT);
|
||||
<SNL>"/" RETURN(SLASH);
|
||||
<SNL>"<" RETURN(LT);
|
||||
<SNL>">" RETURN(GT);
|
||||
<SNL>"|" RETURN(BIT_OR);
|
||||
<SNL>"&" RETURN(BIT_AND);
|
||||
<SNL>"^" RETURN(COMPLEMENT);
|
||||
<SNL>"%" RETURN(MODULO);
|
||||
<SNL>"=" RETURN(EQUAL);
|
||||
<SNL>"&" RETURN(AMPERSAND);
|
||||
<SNL>"*" RETURN(ASTERISK);
|
||||
<SNL>"{" RETURN(L_BRACKET);
|
||||
<SNL>"}" RETURN(R_BRACKET);
|
||||
<SNL>"[" RETURN(L_SQ_BRACKET);
|
||||
<SNL>"]" RETURN(R_SQ_BRACKET);
|
||||
<SNL>":" RETURN(COLON);
|
||||
<SNL>";" RETURN(SEMI_COLON);
|
||||
<SNL>"." RETURN(PERIOD);
|
||||
<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} {
|
||||
yylval.pchar = strdup(yytext);
|
||||
RETURN(NUMBER);
|
||||
}
|
||||
<SNL>{CCONST} {
|
||||
yylval.pchar = strdup(yytext);
|
||||
RETURN(CHAR_CONST);
|
||||
}
|
||||
<SNL>[\t\ ]* /* no action */ ;
|
||||
<SNL>. RETURN(BAD_CHAR);
|
||||
# { /* somehow "^#" doesn't work if it's first char */
|
||||
BEGIN PP;
|
||||
RETURN(PP_SYMBOL)
|
||||
}
|
||||
.|\n { line_num = 1; BEGIN SNL; yyless(0); }
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
/**************************************************************************
|
||||
GTA PROJECT AT division
|
||||
Copyright, 1990, The Regents of the University of California.
|
||||
Los Alamos National Laboratory
|
||||
|
||||
snc_main.c,v 1.2 1995/06/27 15:26:11 wright Exp
|
||||
|
||||
|
||||
DESCRIPTION: Main program and miscellaneous routines for
|
||||
State Notation Compiler.
|
||||
|
||||
ENVIRONMENT: UNIX
|
||||
HISTORY:
|
||||
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>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* SNC Globals: */
|
||||
char in_file[200]; /* input file name */
|
||||
char out_file[200]; /* output file name */
|
||||
char *src_file; /* ptr to (effective) source file name */
|
||||
int line_num; /* current src file line number */
|
||||
int c_line_num; /* line number for beginning of C code */
|
||||
/* Compile & run-time options: */
|
||||
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; /* 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
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* -------------------------------------------------------------
|
||||
* int argc I arg count
|
||||
* char *argv[] I array of ptrs to args
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Program entry.
|
||||
*
|
||||
* NOTES: The streams stdin and stdout are redirected to files named in the
|
||||
* command parameters. This accomodates the use by lex of stdin for input
|
||||
* and permits printf() to be used for output. Stderr is not redirected.
|
||||
*
|
||||
* This routine calls yyparse(), which never returns.
|
||||
*-*************************************************************************/
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
FILE *infp, *outfp, *freopen();
|
||||
|
||||
/* Get command arguments */
|
||||
get_args(argc, argv);
|
||||
|
||||
/* Redirect input stream from specified file */
|
||||
infp = freopen(in_file, "r", stdin);
|
||||
if (infp == NULL)
|
||||
{
|
||||
perror(in_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Redirect output stream to specified file */
|
||||
outfp = freopen(out_file, "w", stdout);
|
||||
if (outfp == NULL)
|
||||
{
|
||||
perror(out_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* src_file is used to mark the output file for snc & cc errors */
|
||||
src_file = in_file;
|
||||
|
||||
/* Use line buffered output */
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||
|
||||
printf("/* %s: %s */\n\n", sncVersion, in_file);
|
||||
|
||||
/* Call the SNC parser */
|
||||
Global_yyparse();
|
||||
}
|
||||
/*+************************************************************************
|
||||
* NAME: get_args
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* -----------------------------------------------------------
|
||||
* int argc I number of arguments
|
||||
* char *argv[] I shell command arguments
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Get the shell command arguments.
|
||||
*
|
||||
* NOTES: If "*.s" is input file then "*.c" is the output file. Otherwise,
|
||||
* ".c" is appended to the input file to form the output file name.
|
||||
* Sets the gloabals in_file[] and out_file[].
|
||||
*-*************************************************************************/
|
||||
get_args(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "%s\n", sncVersion);
|
||||
fprintf(stderr, "usage: snc <options> <infile>\n");
|
||||
fprintf(stderr, "options:\n");
|
||||
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, " -v - don't include VxWorks definitions\n");
|
||||
fprintf(stderr, "example:\n snc +a -c vacuum.st\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (argc--, argv++; argc > 0; argc--, argv++)
|
||||
{
|
||||
s = *argv;
|
||||
if (*s == '+' || *s == '-')
|
||||
get_options(s);
|
||||
else
|
||||
get_in_file(s);
|
||||
}
|
||||
}
|
||||
|
||||
get_options(s)
|
||||
char *s;
|
||||
{
|
||||
int opt_val;
|
||||
|
||||
if (*s == '+')
|
||||
opt_val = TRUE;
|
||||
else
|
||||
opt_val = FALSE;
|
||||
|
||||
switch (s[1])
|
||||
{
|
||||
case 'a':
|
||||
async_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
conn_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
debug_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
newef_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
line_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reent_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
warn_opt = opt_val;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
vx_opt = opt_val;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown option: \"%s\"\n", s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
get_in_file (s)
|
||||
char *s;
|
||||
{
|
||||
int ls;
|
||||
|
||||
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;
|
||||
}
|
||||
else if (in_file[ls-2] == '.')
|
||||
{ /* change suffix to 'c' */
|
||||
out_file[ls -1] = 'c';
|
||||
}
|
||||
else
|
||||
{ /* append ".c" */
|
||||
out_file[ls] = '.';
|
||||
out_file[ls+1] = 'c';
|
||||
out_file[ls+2] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*+************************************************************************
|
||||
* NAME: snc_err
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* -------------------------------------------------------------------
|
||||
* char *err_txt I Text of error msg.
|
||||
* int line I Line no. where error ocurred
|
||||
* int code I Error code (see snc.y)
|
||||
*
|
||||
* RETURNS: no return
|
||||
*
|
||||
* FUNCTION: Print the SNC error message and then exit.
|
||||
*
|
||||
* NOTES:
|
||||
*-*************************************************************************/
|
||||
snc_err(err_txt)
|
||||
char *err_txt;
|
||||
{
|
||||
fprintf(stderr, " %s\n", err_txt);
|
||||
exit(1);
|
||||
}
|
||||
/*+************************************************************************
|
||||
* NAME: yyerror
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* ---------------------------------------------------
|
||||
* char *err I yacc error
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Print yacc error msg
|
||||
*
|
||||
* NOTES:
|
||||
*-*************************************************************************/
|
||||
yyerror(err)
|
||||
char *err;
|
||||
{
|
||||
fprintf(stderr, "%s: line no. %d (%s)\n", err, line_num, src_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/*+************************************************************************
|
||||
* NAME: print_line_num
|
||||
*
|
||||
* CALLING SEQUENCE
|
||||
* type argument I/O description
|
||||
* ---------------------------------------------------
|
||||
* int line_num I current line number
|
||||
* char src_file I effective source file
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*
|
||||
* FUNCTION: Prints the line number and input file name for use by the
|
||||
* C preprocessor. e.g.: # line 24 "something.st"
|
||||
*
|
||||
* NOTES:
|
||||
*-*************************************************************************/
|
||||
print_line_num(line_num, src_file)
|
||||
int line_num;
|
||||
char *src_file;
|
||||
{
|
||||
if (line_opt)
|
||||
printf("# line %d \"%s\"\n", line_num, src_file);
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user