Hi, all,
The attached file is the "svn diff" output.
Regrads,
Gongfa
Andrew Johnson wrote:
Hi Gongfa,
On Tuesday 11 November 2008 10:43:21 Liu, Gongfa wrote:
I have checked out sncseq from the address you provided and finished
the mergence of our changes:
(1) support accessing the local variable. The implementation is done by
Michael Laznovsky originally.
(2) support debugging
(3) support redundancy
Now we need an account to commit our changes. Would you like to create
an account for us?
I would like to see your changes reviewed before they are committed by mailing
the 'svn diff' output to core-talk, with a CC to Michael since I don't know
if he has subscribed to that list yet from his new address.
I will also let Michael as the SNCSEQ maintainer decide whether to make all
commits himself or to let others have accounts to do so, although I don't he
has an SVN account himself yet.
I think with this change the version number should become 2.1 rather than
2.0.13 since I imagine it involves some significant modification or additions
to the internals of the sequencer.
- Andrew
--
----------------------------------------------------------
Gongfa Liu MKS-2, DESY
phone: +49-40-8998-1642 Notkestr. 85
fax: +49-40-8998-4388 22607 Hamburg
e-mail: [email protected] Germany
----------------------------------------------------------
Index: src/snc/phase2.c
===================================================================
--- src/snc/phase2.c (revision 194)
+++ src/snc/phase2.c (working copy)
@@ -30,6 +30,7 @@
06mar00,wfl Added threadInit() to main program; removed ASYNC/SYNC #defines.
17mar00,wfl Added necessary includes for C main program.
31mar00,wfl Supported entry handler.
+13dec07,liu Add num_locvars to support accessing local variables.
***************************************************************************/
/*#define DEBUG 1*/
@@ -51,6 +52,7 @@
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 */
+int num_locvars = 0; /* number of local variables (includes assigned to PVs?) */
void gen_preamble();
void gen_opt_defn();
@@ -145,10 +147,12 @@
printf("#define NUM_CHANNELS %d\n", num_channels);
printf("#define NUM_EVENTS %d\n", num_events);
printf("#define NUM_QUEUES %d\n", num_queues);
+ printf("#define NUM_LOCVARS %d\n", num_locvars);
/* The following definition should be consistant with db_access.h */
+#define MAX_STRING_SIZE 40
printf("\n");
- printf("#define MAX_STRING_SIZE 40\n");
+ printf("#define MAX_STRING_SIZE %d\n",MAX_STRING_SIZE);
/* #define's for compiler options */
printf("\n");
@@ -180,7 +184,6 @@
printf(" macro_def = (argc>1)?argv[1]:NULL;\n");
printf(" threadId = seq((void *)&%s, macro_def, 0);\n", prog_name);
printf(" if(callIocsh) {\n");
- printf(" seqRegisterSequencerCommands();\n");
printf(" iocsh(0);\n");
printf(" } else {\n");
printf(" epicsThreadExitMain();\n");
@@ -213,6 +216,11 @@
extern Expr *ss_list, *entry_code_list, *exit_code_list;
Expr *ssp, *ep;
+ extern Var *var_list;
+ Var *vp;
+
+ char *db_type_str();
+
for (ssp = ss_list; ssp != 0; ssp = ssp->next)
{
#ifdef DEBUG
@@ -233,6 +241,13 @@
traverseExprTree(ep, E_VAR, 0, connect_variable, 0);
}
+ /* count all local variables we know about (ie. not declared in escaped code) */
+ for (vp = var_list;
+ vp != NULL;
+ vp = vp->next)
+ {
+ if (strlen(db_type_str(vp->type)) > 0) num_locvars++;
+ }
}
/* Connect a variable in an expression to the the Var structure */
Index: src/snc/gen_tables.c
===================================================================
--- src/snc/gen_tables.c (revision 194)
+++ src/snc/gen_tables.c (working copy)
@@ -26,6 +26,7 @@
avoided warnings when no variables are mapped to channels.
18feb00,wfl Partial support for local declarations (not yet complete).
31mar00,wfl Supported entry handler.
+18jan08,liu add gen_var_blocks() to support accessing local variables.
***************************************************************************/
/*#define DEBUG 1*/
@@ -39,6 +40,7 @@
void encode_state_options(Expr *sp);
void gen_db_blocks();
+void gen_var_blocks();
void fill_db_block();
void gen_state_blocks();
void fill_state_block();
@@ -52,6 +54,8 @@
int find_error_state();
+#define max(a,b) (((a) > (b)) ? (a) : (b)) /* generic max() */
+
/*+************************************************************************
* NAME: gen_tables
*
@@ -73,6 +77,9 @@
/* Generate DB blocks */
gen_db_blocks();
+ /* Generate Local Variable Blocks */
+ gen_var_blocks();
+
/* Generate State Blocks */
gen_state_blocks();
@@ -130,7 +137,7 @@
}
return;
}
-
+
/* Fill in a db block with data (all elements for "seqChan" struct) */
void fill_db_block(cp, elem_num)
Chan *cp;
@@ -153,6 +160,7 @@
else
elem_str[0] = '\0';
+
if (vp->type == V_STRING)
suffix = "[0]";
else
@@ -237,6 +245,78 @@
}
}
+/* Generate blocks with data for each defined (or referenced) local variable
+ * ... lazmo@lsac 22-Mar-2006
+ */
+void gen_var_blocks()
+{
+ extern Var *var_list;
+ Var *vp;
+ char *vstr;
+ int nv;
+
+ char *suf1, *suf2;
+
+ extern int reent_opt;
+ extern int num_locvars;
+
+ char *db_type_str();
+
+ printf("\n");
+ printf("/* Local Variables (some may also be connected to PVs above)\n");
+ printf(" * ... does not include escaped declarations\n");
+ printf(" */\n");
+
+
+ if (var_list) {
+
+ printf("static struct seqVar seqVar[NUM_LOCVARS] = {\n");
+
+ printf(" /* name type_i type_s class dim1 dim2 initial address */\n");
+
+ for (nv=0, vp = var_list;
+ vp != NULL;
+ nv++, vp = vp->next)
+ {
+ if(strlen(db_type_str(vp->type)) > 0) /*don't include escaped vars */
+ {
+ if (nv > 0) printf(",\n");
+ printf(" {");
+
+ printf(" \"%s\",\t", vp->name); /* name (string) */
+ printf(" %2d,", vp->type); /* type (enum) */
+ printf(" \"%s\",\t", db_type_str(vp->type)); /* type (string) */
+ printf(" %d,", vp->class); /* class (enum) */
+ printf(" %3d, %3d,", vp->length1, vp->length2); /* array dimensions; [1][1] if none */
+
+ /* run-time address pointer suffix */
+ suf1 = (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP) ? "[0]" /* 1-dim */
+ : (vp->class == VC_ARRAY2) ? "[0][0]" /* 2-dim */
+ : ""; /* no dim */
+
+ suf2 = (vp->type == V_STRING) ? "[0]" : ""; /* string also needs "[0]" */
+
+ printf(vp->value ? " \"%s\",\t" : " NULL,", vp->value); /* initial value (string); NULL if none */
+
+ /* ptr (or offset) to variable
+ * ... reentrant entries are resolved in at runtime
+ */
+ printf(reent_opt
+ ? " (void *)OFFSET(struct UserVar, %s%s%s)"
+ : " (void *)&%s%s%s",
+ vp->name, suf1, suf2);
+
+ printf(" }");
+ }
+ }
+ printf("\n};\n");
+ }
+ else {
+ printf("\n/* No Variables; create 1 for ptr init. */\n");
+ printf("static struct seqVar seqVar[1];\n");
+ }
+}
+
/* Generate structure and data for state blocks */
void gen_state_blocks()
{
@@ -292,6 +372,8 @@
Expr *ep;
int isEntry = FALSE, isExit = FALSE;
+ extern int debug_opt;
+
/* Check if there are any entry or exit "transitions" in this
state so that if so the state block will be initialized to include a
reference to the function which implements them, but otherwise just
@@ -462,9 +544,11 @@
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/* *pVars */ seqVar,\n"); /* table of local variables */
+ printf("\t/* numVars */ NUM_LOCVARS,\n"); /* number of local variables */
+
printf("\t/* *pSS */ seqSS,\n"); /* array of SS blocks */
printf("\t/* numSS */ NUM_SS,\n"); /* number of state sets */
Index: src/snc/gen_ss_code.c
===================================================================
--- src/snc/gen_ss_code.c (revision 194)
+++ src/snc/gen_ss_code.c (working copy)
@@ -25,6 +25,7 @@
18feb00,wfl More partial support for local declarations (still not done)
31mar00,wfl Put 'when' code in a block (allows local declarations);
supported entry handler
+14dec07,liu add gen_event_string_func();
***************************************************************************/
#include <stdio.h>
#include <string.h>
@@ -60,6 +61,7 @@
void eval_delay(Expr *ep, Expr *sp);
void gen_action_func(Expr *sp, Expr *ssp);
void gen_event_func(Expr *sp, Expr *ssp);
+void gen_event_string_func(Expr *sp, Expr *ssp);
void eval_expr(int stmt_type, Expr *ep, Expr *sp, int level);
void indent(int level);
void gen_ef_func(int stmt_type,Expr *ep,Expr *sp,char *fname,
@@ -75,6 +77,9 @@
int state_block_index_from_name(Expr *ssp,char *state_name);
int special_func(int stmt_type,Expr *ep,Expr *sp);
+extern int debug_opt;
+
+
/*+************************************************************************
* NAME: gen_ss_code
*
@@ -123,6 +128,9 @@
/* Generate event processing function */
gen_event_func(sp, ssp);
+ /* Generate when()-string access function */
+ gen_event_string_func(sp, ssp);
+
/* Generate action processing function */
gen_action_func(sp, ssp);
}
@@ -162,6 +170,7 @@
/* Entry function declaration */
printf("\n/* Entry function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
+
printf("static void I_%s_%s(SS_ID ssId, struct UserVar *pVar)\n{\n",
ssp->value, sp->value);
@@ -253,25 +262,24 @@
*/
void eval_delay(Expr *ep, Expr *sp)
{
- int delay_id;
+ int delay_id;
-#ifdef DEBUG
- fprintf(stderr, "eval_delay: type=%s\n", stype[ep->type]);
-#endif /*DEBUG*/
+#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);
+ /* 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);
+ /* Evaluate & generate the 3-rd parameter (an expression) */
+ eval_expr(EVENT_STMT, ep->left, sp, 0);
- /* Complete the function call */
- printf("));\n");
+ /* 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.
@@ -281,18 +289,22 @@
Expr *tp;
Expr *ap;
int trans_num;
- extern int line_num;
+ extern int 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(SS_ID ssId, struct UserVar *pVar, short transNum)\n{\n",
ssp->value, sp->value);
/* "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)
{
@@ -330,8 +342,10 @@
trans_num++;
}
}
+
/* end of switch stmt */
printf("\t}\n");
+
/* end of function */
printf("}\n");
return;
@@ -345,21 +359,27 @@
printf("\n/* Event function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
+
printf("static long E_%s_%s(SS_ID ssId, struct UserVar *pVar, short *pTransNum, short *pNextState)\n{\n",
ssp->value, sp->value);
+
trans_num = 0;
+
/* For each transition generate an "if" statement ... */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
if (tp->type == E_WHEN)
{
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)
@@ -381,6 +401,56 @@
printf("}\n");
}
+/* Generate a C function that returns the when() condition as a string, for a particular state */
+void gen_event_string_func(Expr *sp, Expr *ssp)
+{
+ Expr *tp;
+ int index, trans_num;
+ int n;
+
+ if (!debug_opt) return;
+
+ printf("\n/* Event-string function for state \"%s\" in state set \"%s\" */\n",
+ sp->value, ssp->value);
+
+ printf("static void ES_%s_%s(SS_ID ssId, short transNum, char **ppString)\n",ssp->value,sp->value);
+ printf("{\n");
+
+ printf("static char *when_string[] = {");
+
+ trans_num = 0;
+ n = 0;
+ for (tp = sp->left;
+ tp != NULL;
+ tp = tp->next) { /* for each transition... */
+
+ if (tp->type == E_WHEN) {
+
+ printf("%s\n\t/* %d */ \"", (n>0) ? "," : "", trans_num);
+ if (tp->left) eval_expr(EVENT_STMT, tp->left, sp, 0);
+ printf("\"");
+
+ /* index is the transition number (0, 1, ...) */
+ index = state_block_index_from_name(ssp, tp->value);
+ if (index < 0) {
+ index = 0; /* default to 1st state */
+ printf("\t/* state %s does not exist */\n",tp->value);
+ }
+
+ trans_num++;
+ n++;
+ }
+ }
+ printf("\n};\n\n");
+
+ printf("\tif ((transNum < 0) || (transNum >= sizeof(when_string)/sizeof(char*))) {\n");
+ printf("\t *ppString = \"???\";\n");
+ printf("\t} else {\n");
+ printf("\t *ppString = when_string[transNum];\n");
+ printf("\t}\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) */
int state_block_index_from_name(Expr *ssp,char *state_name)
Index: src/snc/parse.c
===================================================================
--- src/snc/parse.c (revision 194)
+++ src/snc/parse.c (working copy)
@@ -809,6 +809,10 @@
Expr *ep1; /* beginning of 1-st structure or list */
Expr *ep2; /* beginning 2-nd (append it to 1-st) */
{
+#ifdef DEBUG
+ Expr *ep;
+#endif /*DEBUG*/
+
if (ep1 == 0 && ep2 == 0)
return NULL;
else if (ep1 == 0)
Index: src/seq/seq_prog.c
===================================================================
--- src/seq/seq_prog.c (revision 194)
+++ src/seq/seq_prog.c (working copy)
@@ -18,6 +18,7 @@
18feb00,wfl Avoided memory leak.
29feb00,wfl Supported new OSI.
31mar00,wfl Added seqFindProgByName().
+14dec07,liu Support accessing local variabls.
***************************************************************************/
/*#define DEBUG*/
@@ -40,13 +41,14 @@
#define seqListNext(pNode) (PROG_NODE *)ellNext((ELLNODE *)pNode)
-/*
- * seqFindProg() - find a program in the state program list from thread id.
+/*----------------------------------------------------------------
+ * seqFindProg() - find a program from thread id
+ *----------------------------------------------------------------
*/
SPROG *seqFindProg(epicsThreadId threadId)
{
PROG_NODE *pNode;
- SPROG *pSP;
+ SPROG *pSP, *pFound = NULL;
SSCB *pSS;
int n;
@@ -55,32 +57,46 @@
epicsMutexMustLock(seqProgListSemId);
- for (pNode = seqListFirst(&seqProgList); pNode != NULL;
- pNode = seqListNext(pNode) )
+ for (pNode = seqListFirst(&seqProgList);
+ pNode != NULL;
+ pNode = seqListNext(pNode))
{
- pSP = pNode->pSP;
- if (pSP->threadId == threadId)
- {
- epicsMutexUnlock(seqProgListSemId);
- return pSP;
- }
- pSS = pSP->pSS;
- for (n = 0; n < pSP->numSS; n++, pSS++)
- {
- if (pSS->threadId == threadId)
- {
- epicsMutexUnlock(seqProgListSemId);
- return pSP;
- }
- }
+ pSP = pNode->pSP;
+
+#if 1 /* ...also in pSS? */
+ if (pSP->threadId == threadId) {
+ pFound = pSP;
+ break;
+ }
+#endif
+
+ pSS = pSP->pSS;
+
+#if 0
+printf("pSP->numSS: %d\n",pSP->numSS);
+#endif
+
+ for (n = 0; n < pSP->numSS; n++, pSS++) {
+
+#if 0
+printf("pSS->threadId: 0x%x\n",pSS->threadId);
+#endif
+
+ if (pSS->threadId == threadId) {
+ pFound = pSP;
+ break;
+ }
+ }
+ if (pFound) break;
}
+
epicsMutexUnlock(seqProgListSemId);
-
- return NULL; /* not in list */
+ return pFound;
}
-/*
- * seqFindProgByName() - find a program in the state program list by name.
+/*----------------------------------------------------------------
+ * seqFindProgByName() - find a program in the state program list by name
+ *----------------------------------------------------------------
*/
epicsShareFunc SPROG *epicsShareAPI seqFindProgByName(char *pProgName)
{
@@ -92,8 +108,9 @@
epicsMutexMustLock(seqProgListSemId);
- for (pNode = seqListFirst(&seqProgList); pNode != NULL;
- pNode = seqListNext(pNode) )
+ for (pNode = seqListFirst(&seqProgList);
+ pNode != NULL;
+ pNode = seqListNext(pNode) )
{
pSP = pNode->pSP;
if (strcmp(pSP->pProgName, pProgName) == 0)
@@ -107,10 +124,11 @@
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.
+/*----------------------------------------------------------------
+ * seqTraverseProg() - traverse the program list and call a specified
+ * function for each one
+ * ... passes one parameter of pointer size
+ *----------------------------------------------------------------
*/
epicsShareFunc epicsStatus seqTraverseProg(pFunc, param)
void (*pFunc)(); /* function to call */
@@ -123,8 +141,10 @@
return ERROR;
epicsMutexMustLock(seqProgListSemId);
- for (pNode = seqListFirst(&seqProgList); pNode != NULL;
- pNode = seqListNext(pNode) )
+
+ for (pNode = seqListFirst(&seqProgList);
+ pNode != NULL;
+ pNode = seqListNext(pNode) )
{
pSP = pNode->pSP;
pFunc(pSP, param);
@@ -134,9 +154,10 @@
return OK;
}
-/*
+/*----------------------------------------------------------------
* seqAddProg() - add a program to the state program list.
* Returns ERROR if program is already in list, else TRUE.
+ *----------------------------------------------------------------
*/
epicsShareFunc epicsStatus seqAddProg(pSP)
SPROG *pSP;
@@ -147,8 +168,10 @@
seqProgListInit(); /* Initialize list */
epicsMutexMustLock(seqProgListSemId);
- for (pNode = seqListFirst(&seqProgList); pNode != NULL;
- pNode = seqListNext(pNode) )
+
+ for (pNode = seqListFirst(&seqProgList);
+ pNode != NULL;
+ pNode = seqListNext(pNode) )
{
if (pSP == pNode->pSP)
@@ -180,9 +203,10 @@
return OK;
}
-/*
- *seqDelProg() - delete a program from the program list.
+/*----------------------------------------------------------------
+ * seqDelProg() - delete a program from the program list.
* Returns TRUE if deleted, else FALSE.
+ *----------------------------------------------------------------
*/
epicsShareFunc epicsStatus seqDelProg(pSP)
SPROG *pSP;
@@ -193,8 +217,10 @@
return ERROR;
epicsMutexMustLock(seqProgListSemId);
- for (pNode = seqListFirst(&seqProgList); pNode != NULL;
- pNode = seqListNext(pNode) )
+
+ for (pNode = seqListFirst(&seqProgList);
+ pNode != NULL;
+ pNode = seqListNext(pNode) )
{
if (pNode->pSP == pSP)
{
@@ -214,8 +240,9 @@
return ERROR; /* not in list */
}
-/*
+/*----------------------------------------------------------------
* seqProgListInit() - initialize the state program list.
+ *----------------------------------------------------------------
*/
LOCAL void seqProgListInit()
{
@@ -227,3 +254,4 @@
seqProgListInited = TRUE;
}
+/* end */
Index: src/seq/seq_qry.c
===================================================================
--- src/seq/seq_qry.c (revision 194)
+++ src/seq/seq_qry.c (working copy)
@@ -31,6 +31,7 @@
stamp unconditionally.
29feb00,wfl Supported new OSI; removed remaining OS-dependencies.
31mar00,wfl Removed limitation on only printing 5 array elements.
+18jan08,liu Support accessing local variabls.
***************************************************************************/
/*#define DEBUG 1*/
@@ -40,6 +41,7 @@
#define epicsExportSharedSymbols
#include "seq.h"
+#include "../snc/parse.h" /* for V_* #defines */
/* User functions */
LOCAL int wait_rtn();
@@ -299,11 +301,12 @@
}
void epicsShareAPI seqcaStats(int *pchans, int *pdiscon) {
- struct seqStats stats = {0, 0, 0, 0};
- seqTraverseProg(seqcarCollect, (void *) &stats);
- if (pchans) *pchans = stats.nChans;
- if (pdiscon) *pdiscon = stats.nChans - stats.nConn;
+ struct seqStats stats = {0, 0, 0, 0};
+ seqTraverseProg(seqcarCollect, (void *) &stats);
+ if (pchans) *pchans = stats.nChans;
+ if (pdiscon) *pdiscon = stats.nChans - stats.nConn;
}
+
/*
* seqQueueShow() - Show syncQ queue information for a state program.
*/
@@ -521,3 +524,428 @@
printf("No active state programs\n");
return;
}
+
+/*
+ ************************************************************************
+ ************************************************************************
+ * PV dumper
+ * ... to file? ........................
+ ************************************************************************
+ ************************************************************************
+ */
+
+/*----------------------------------------------------------------
+ * internal func ... list PVs via pSP
+ *----------------------------------------------------------------
+ */
+static void SeqPvShowBySP (SPROG *pSP, void *dummy)
+{
+ CHAN *pDB;
+ int n;
+
+ printf("program %s %p\n",
+ pSP->pProgName,
+ pSP->threadId);
+
+ for (n = 0, pDB = pSP->pChan;
+ n < pSP->numChans;
+ n++)
+ {
+ if (pDB->dbName) printf("%s\n",pDB->dbName);
+ pDB++;
+ }
+}
+
+/*----------------------------------------------------------------
+ * list PVs for single task, or all progs if tid==0
+ * ... ACHTUNG! seqTraverseProg() waits on "seqProgListSemId" semaphore
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqPvShow (epicsThreadId tid)
+{
+ epicsShareFunc epicsStatus seqTraverseProg(void (*pFunc)(), void *param); /* seq_prog.c */
+
+ SPROG *pSP;
+
+ if (tid == 0) { /* all progs */
+ seqTraverseProg (SeqPvShowBySP,0);
+ return OK;
+ }
+
+ if (NULL == (pSP = seqFindProg(tid))) /* find state pgm */
+ return ERROR;
+
+ SeqPvShowBySP (pSP,0);
+
+ return OK;
+}
+
+/*
+ ************************************************************************
+ ************************************************************************
+ * Local-variable access functions
+ ************************************************************************
+ ************************************************************************
+ */
+
+/*----------------------------------------------------------------
+ * seqVarGetPtr -- return pointer to start of local-variable struct array, and var count
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqVarGetPtrAndCount (epicsThreadId tid, /* thread id */
+ SVAR **ppSV, /* [returned] ptr to ptr to struct array */
+ int *pNV) /* [returned] ptr to count */
+
+{
+ SPROG *pSP;
+ SVAR *pSV;
+
+ pSP = seqFindProg(tid);
+ if (pSP == NULL) return ERROR; /* state pgm not found */
+
+ pSV = pSP->pVarTbl;
+ if (pSV == NULL) return ERROR; /* local variables not found(?) */
+
+ if (ppSV) *ppSV = pSV;
+ else return ERROR; /* bad arg */
+
+ if (pNV ) *pNV = pSP->numVars;
+ else return ERROR; /* bad arg */
+
+ return OK;
+}
+
+/*----------------------------------------------------------------
+ * seqVarGetInit -- initialize "get" iterator
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqVarGetInit (epicsThreadId tid) /* thread id */
+{
+ SPROG *pSP;
+ SVAR *pSV;
+
+ pSP = seqFindProg(tid);
+ if (pSP == NULL) return ERROR; /* state pgm not found */
+
+ pSP->pVarGetPtr = NULL; /* init... */
+ pSP-> varGetCnt = 0;
+
+ pSV = pSP->pVarTbl;
+ if (pSV == NULL) return ERROR; /* local variables not found(?) */
+
+ pSP->pVarGetPtr = pSV;
+
+ return OK;
+}
+
+/*----------------------------------------------------------------
+ * seqVarGetNext -- get next var entry via iterator
+ * ... returns NULL SVAR ptr if no more entries
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqVarGetNext (epicsThreadId tid, /* thread id */
+ SVAR **ppSV) /* [returned] ptr to ptr to struct array */
+{
+ SPROG *pSP;
+ SVAR *pSV;
+
+ *ppSV = NULL; /* init to "done" */
+
+ pSP = seqFindProg(tid);
+ if (pSP == NULL) return ERROR; /* state pgm not found */
+
+ pSV = pSP->pVarTbl;
+ if (pSV == NULL) return ERROR; /* local variables not found(?) */
+
+ if (pSP->varGetCnt < pSP->numVars) {
+ *ppSV = pSP->pVarGetPtr;
+ pSP->pVarGetPtr++;
+ pSP->varGetCnt++;
+ }
+
+ return OK;
+}
+
+/*----------------------------------------------------------------
+ * seqVarFind -- return pointer to single local-variable struct, by thread id & var name
+ *----------------------------------------------------------------
+ */
+LOCAL long epicsShareAPI seqVarFind (epicsThreadId tid, /* thread id */
+ char *varName, /* var name */
+ SVAR **ppSV) /* [returned] ptr to ptr to struct */
+{
+ SPROG *pSP;
+ SVAR *pSV;
+ int n;
+
+ pSP = seqFindProg(tid);
+ if (pSP == NULL) return ERROR; /* state pgm not found */
+
+ pSV = pSP->pVarTbl;
+ if (pSV == NULL) return ERROR; /* local variables not found (?) */
+
+ for (n = 0; n < pSP->numVars; n++, pSV++) {
+ if (!strcmp(varName, pSV->name)) {
+ if (ppSV ) *ppSV = pSV; /* return seqVar ptr */
+ return OK;
+ }
+ }
+
+ return ERROR; /* var not found */
+}
+
+/*----------------------------------------------------------------
+ * seqVarGetValueString -- convert local-var value to string
+ * ... passed-in string buffer must be large enough to handle anticipated result
+ * ... array variables will return just the first element
+ * ... if 2nd arg is NULL, var value is printed out instead
+ * ... local buf is STATIC ... need to be thread-safe?
+ *----------------------------------------------------------------
+ */
+LOCAL long seqVarGetValueString(SVAR *pSV,
+ char *pStr) /* [returned] */
+{
+ void *pVar;
+ char *pBuf = pStr;
+
+ static char sbuf[MAX_STRING_SIZE]; /* local buf, for print case */
+
+ if (pSV == NULL) return ERROR;
+ if (pStr == NULL) pBuf = &sbuf[0];
+
+ pVar = (void*)pSV->addr;
+
+ if (pSV->class == VC_POINTER) { /* redirect, if pointer */
+ pVar = *(void**)pVar;
+ }
+
+ if (pVar == NULL) {
+ strcpy(pBuf,"(NULL)");
+ }
+ else {
+
+ switch (pSV->type) { /* convert by type ("V_" defs are in ../snc/parse.h) */
+
+ case V_CHAR:
+ case V_UCHAR:
+ if (VC_POINTER == pSV->class) { /* show first 3 bytes if it's a char pointer */
+ int i;
+ *pBuf = 0;
+ for (i=0; i<3; i++) {
+ sprintf (&pBuf[strlen(pBuf)], "%d ",
+ (pSV->type == V_CHAR) ? *((char*)pVar+i) : *((unsigned char*)pVar+i));
+ }
+ strcat(pBuf,"...");
+ }
+ else { /* just a single char */
+ sprintf (pBuf, "%d",
+ (pSV->type == V_CHAR) ? *(char*)pVar : *(unsigned char*)pVar);
+ }
+ break;
+
+ case V_SHORT: sprintf (pBuf, "%d", *( short*) pVar); break;
+ case V_USHORT: sprintf (pBuf, "%u", *(unsigned short*) pVar); break;
+ case V_INT: sprintf (pBuf, "%d", *( int*) pVar); break;
+ case V_UINT: sprintf (pBuf, "%u", *(unsigned int*) pVar); break;
+ case V_LONG: sprintf (pBuf, "%ld", *( long*) pVar); break;
+ case V_ULONG: sprintf (pBuf, "%lu", *(unsigned long*) pVar); break;
+ case V_FLOAT: sprintf (pBuf, "%.7g", *( float*) pVar); break;
+ case V_DOUBLE: sprintf (pBuf, "%.16g", *( double*) pVar); break;
+
+ case V_STRING:
+ strcpy (pBuf, pVar);
+ break;
+
+#if 0
+ case V_EVFLAG: ...?
+ case V_NONE: ...?
+#endif
+
+ default:
+ strcpy(pBuf,""); /* unknown? */
+ break;
+ }
+ }
+
+ /* print to console if arg was null
+ */
+ if (pStr == NULL) printf("\"%s\"\n",pBuf);
+
+ return OK;
+}
+
+/*----------------------------------------------------------------
+ * seqVarPutValueString -- set local-var value from string
+ * ... array variables will have just the first element set
+ *----------------------------------------------------------------
+ */
+LOCAL long seqVarPutValueString(SVAR *pSV,
+ char *pStr)
+{
+ void *pVar;
+
+ if (pSV == NULL) return ERROR;
+ if (pStr == NULL) return ERROR;
+
+ pVar = (void*)pSV->addr;
+
+ if (pSV->class == VC_POINTER) { /* redirect, if pointer */
+ pVar = *(void**)pVar;
+ }
+
+ if (pVar == NULL) {
+ return ERROR; /* null ptr... doh! */
+ }
+
+ switch (pSV->type) { /* convert by type ("V_" defs are in ../snc/parse.h) */
+
+ case V_CHAR: if (sscanf (pStr, "%c" , ( char*) pVar) != 1) return ERROR; break;
+ case V_UCHAR: if (sscanf (pStr, "%c", (unsigned char*) pVar) != 1) return ERROR; break;
+ case V_SHORT: if (sscanf (pStr, "%hd", ( short*) pVar) != 1) return ERROR; break;
+ case V_USHORT: if (sscanf (pStr, "%hu", (unsigned short*) pVar) != 1) return ERROR; break;
+ case V_INT: if (sscanf (pStr, "%d" , ( int*) pVar) != 1) return ERROR; break;
+ case V_UINT: if (sscanf (pStr, "%u" , (unsigned int*) pVar) != 1) return ERROR; break;
+ case V_LONG: if (sscanf (pStr, "%ld", ( long*) pVar) != 1) return ERROR; break;
+ case V_ULONG: if (sscanf (pStr, "%lu", (unsigned long*) pVar) != 1) return ERROR; break;
+ case V_FLOAT: if (sscanf (pStr, "%g" , ( float*) pVar) != 1) return ERROR; break;
+ case V_DOUBLE: if (sscanf (pStr, "%lg", ( double*) pVar) != 1) return ERROR; break;
+
+ case V_STRING:
+ strcpy (pStr, pVar);
+ break;
+
+#if 0
+ case V_EVFLAG: ...?
+ case V_NONE: ...?
+#endif
+
+ default:
+ strcpy(pStr,""); /* unknown? */
+ break;
+ }
+
+ return OK;
+}
+
+/*----------------------------------------------------------------
+ * seqVarGet -- get single local-var value, as string
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqVarGet (epicsThreadId tid, /* thread id */
+ char *varName, /* var name */
+ char *pStr) /* [returned] char buf for value */
+{
+ SVAR *pSV;
+ if (seqVarFind(tid, varName, &pSV) != OK) return ERROR;
+ return seqVarGetValueString(pSV,pStr);
+}
+
+/*----------------------------------------------------------------
+ * seqVarPut -- put single local-var value, as string
+ *----------------------------------------------------------------
+ */
+long epicsShareAPI seqVarPut (epicsThreadId tid, /* thread id */
+ char *varName, /* var name */
+ char *pStr) /* value */
+{
+ SVAR *pSV;
+ if (seqVarFind(tid, varName, &pSV) != OK) return ERROR;
+ return seqVarPutValueString(pSV,pStr);
+}
+
+/*----------------------------------------------------------------
+ * seqVarShow -- show (print) local var info
+ * ... ("threadId" == 0) -> show all local var info for all threads
+ * ... ("varName" == 0) -> show all local var info for single thread
+ * ... ("varName" != 0) -> show single var value
+ * ... local buf is STATIC ... need to be thread-safe?
+ *----------------------------------------------------------------
+ */
+
+/* local func */
+LOCAL void seqVarShowSP(SPROG *pSP, char *varName)
+{
+ static char sbuf[MAX_STRING_SIZE];
+
+ SVAR *pSV = pSP->pVarTbl;
+ int n;
+
+ if (varName == NULL) { /* title only for multi-line output */
+ printf("\n");
+ printf("Program: %s\n",pSP->pProgName);
+/*
+tabs: | | | | | | | | | | |
+ Name Type [n][n] Address Value
+ -----------------------------------------------------------
+ namenamenamenamenamen typetypet * [n][n] addrad val...
+*/
+ printf(" Name Type [n][n] Address Value\n");
+ printf(" -----------------------------------------------------------\n");
+ }
+
+ for (n = 0; n < pSP->numVars; n++, pSV++) {
+
+ if (varName && strcmp(varName,pSV->name)) continue;
+
+ seqVarGetValueString(pSV,sbuf);
+
+ if (varName == NULL) { /* full only for multi-line output */
+
+ printf(" %-21s",pSV->name);
+
+ printf("\t%s ",pSV->type_str);
+ if (pSV->class == VC_POINTER) printf("*");
+ printf(" \t");
+
+ if (pSV->length1 > 1) printf("[%d]", pSV->length1);
+ if (pSV->length2 > 1) printf("[%d]", pSV->length2);
+
+ printf("\t%-1p", pSV->addr);
+ printf("\t");
+ }
+
+ if (pSV->class == VC_POINTER) {
+ if (*(void**)(pSV->addr) == NULL) {
+ printf("(NULL)");
+ }
+ else {
+ printf("%p -> ",*(void**)(pSV->addr)); /* hope it's a good pointer! :O */
+ printf("\"%s\"",sbuf);
+ }
+ }
+ else {
+ printf("\"%s\"",sbuf);
+ }
+
+ printf("\n");
+ }
+}
+
+/* global func */
+long epicsShareAPI seqVarShow (epicsThreadId tid, /* thread id */
+ char *varName) /* var name */
+{
+ SPROG *pSP;
+
+ if (tid == NULL) { /* show all progs */
+ seqTraverseProg(seqVarShowSP,0);
+ printf("\n");
+ return OK;
+ }
+
+ pSP = seqFindProg(tid); /* show single prog & maybe var */
+ if (pSP == NULL) {
+ printf(" Prog not found!\n");
+ return ERROR;
+ }
+
+ seqVarShowSP(pSP,varName);
+ printf("\n");
+ return OK;
+}
+
+/****************************************************************/
+/****************************************************************/
+/****************************************************************/
+
+/* end */
Index: src/seq/seqPvt.h
===================================================================
--- src/seq/seqPvt.h (revision 194)
+++ src/seq/seqPvt.h (working copy)
@@ -53,6 +53,9 @@
* 06mar00,wfl Added function prototypes for global routines.
* 31mar00,wfl Made caSemId a mutex; added seqFindProgXxx() prototypes.
* 22mar01,mrk mover to seqPvt.h from seq.h for stupid windows problem
+ * 06Jun07,liu dbgStRunState, dbgStateJump and dbgStepTrig are added in SSCB,
+ they are used for SNL debugger.
+ * 21dec07,liu Support accessing local variables.
*/
#ifndef INCLseqPvth
#define INCLseqPvth
@@ -138,7 +141,9 @@
};
typedef struct state_info_block STATE;
-#define MAX_NDELAY 20 /* max # delays allowed in each SS */
+#define MAX_NDELAY 20 /* max # delays allowed in each SS */
+#define SEQ_DBG_RUNSTATE_RUNNING 0
+#define SEQ_DBG_RUNSTATE_STOPPED 1
/* Structure to hold information about a State Set */
struct state_set_control_block
{
@@ -167,7 +172,14 @@
epicsBoolean delayExpired[MAX_NDELAY]; /* TRUE if delay expired */
double timeEntered; /* time that a state was entered */
struct state_program *sprog; /* ptr back to state program block */
+
+ /* debugger stuff... */
+ int dbgRunState;
+ int dbgStateJump;
+ int dbgStepTrig;
+ int dbgStopBySeqStop;
};
+
typedef struct state_set_control_block SSCB;
/* Macro table */
@@ -187,6 +199,13 @@
unsigned int stackSize; /* stack size */
epicsMutexId caSemId; /* mutex for locking CA events */
CHAN *pChan; /* table of channels */
+
+ /* local variables */
+ SVAR *pVarTbl; /* table of local variables */
+ SVAR *pVarGetPtr; /* iterator "get" ptr */
+ int varGetCnt; /* iterator "get" count */
+ long numVars; /* number of local variables */
+
long numChans; /* number of db channels, incl. unass */
long assignCount; /* number of db channels assigned */
long connCount; /* number of channels connected */
Index: src/seq/seqCommands.c
===================================================================
--- src/seq/seqCommands.c (revision 194)
+++ src/seq/seqCommands.c (working copy)
@@ -26,7 +26,10 @@
#define epicsExportSharedSymbols
#include "seq.h"
+long epicsShareAPI seqVarShow (epicsThreadId tid,
+ char *varName);
+
struct sequencerProgram {
struct seqProgram *prog;
struct sequencerProgram *next;
@@ -50,9 +53,9 @@
/*
* Find a thread by name or ID number
+ * ... renamed to "seq_" and removed "static" [2006-04-28 lazmo@slac]
*/
-static epicsThreadId
-findThread (const char *name)
+epicsThreadId seq_findThread (const char *name)
{
epicsThreadId id;
char *term;
@@ -60,6 +63,7 @@
id = (epicsThreadId)strtoul (name, &term, 16);
if ((term != name) && (*term == '\0'))
return id;
+
id = epicsThreadGetId (name);
if (id)
return id;
@@ -106,7 +110,7 @@
if (name == NULL)
seqShow (NULL);
- else if ((id = findThread (name)) != NULL)
+ else if ((id = seq_findThread (name)) != NULL)
seqShow (id);
}
@@ -119,7 +123,7 @@
epicsThreadId id;
char *name = args[0].sval;
- if ((name != NULL) && ((id = findThread (name)) != NULL))
+ if ((name != NULL) && ((id = seq_findThread (name)) != NULL))
seqQueueShow (id);
}
@@ -132,7 +136,7 @@
epicsThreadId id;
char *name = args[0].sval;
- if ((name != NULL) && ((id = findThread (name)) != NULL))
+ if ((name != NULL) && ((id = seq_findThread (name)) != NULL))
seqStop (id);
}
@@ -147,7 +151,7 @@
char *name = args[0].sval;
char *chan = args[1].sval;
- if ((name != NULL) && ((id = findThread (name)) != NULL))
+ if ((name != NULL) && ((id = seq_findThread (name)) != NULL))
seqChanShow (id, chan);
}
@@ -160,6 +164,131 @@
seqcar (args[0].ival);
}
+/*----------------------------------------------------------------
+ * seqVarShow (threadid, varname)
+ * ... ("threadId" == 0) -> show all local var info for all threads (progs, actually)
+ * ... ("varName" == 0) -> show all local var info for single thread
+ * ... ("varName" != 0) -> show single var info
+ *----------------------------------------------------------------
+ */
+static const iocshArg seqVarShowArg0 = { "sequencer",iocshArgString };
+static const iocshArg seqVarShowArg1 = { "varName" ,iocshArgString };
+
+static const iocshArg * const seqVarShowArgs[2] = { &seqVarShowArg0,
+ &seqVarShowArg1 };
+
+static const iocshFuncDef seqVarShowFuncDef = { "seqVarShow",2,seqVarShowArgs };
+
+static void seqVarShowCallFunc(const iocshArgBuf *args)
+{
+ epicsThreadId id;
+ char *thdName = args[0].sval;
+ char *varName = args[1].sval;
+
+ if (thdName == NULL) {
+ seqVarShow (NULL,NULL);
+ }
+ else {
+ if ((id = seq_findThread (thdName)) != NULL) {
+ seqVarShow (id,varName);
+ }
+ }
+}
+
+/*----------------------------------------------------------------
+ * seqVarGet (thread, varname, NULL)
+ * ... last arg is forced to NULL for iocShell version (ie. no return via pointer)
+ *----------------------------------------------------------------
+ */
+static const iocshArg seqVarGetArg0 = { "sequencer",iocshArgString };
+static const iocshArg seqVarGetArg1 = { "varName" ,iocshArgString };
+
+static const iocshArg * const seqVarGetArgs[2] = { &seqVarGetArg0,
+ &seqVarGetArg1 };
+
+static const iocshFuncDef seqVarGetFuncDef = { "seqVarGet",2,seqVarGetArgs };
+
+static void seqVarGetCallFunc(const iocshArgBuf *args)
+{
+ epicsThreadId id;
+ char *thdName = args[0].sval;
+ char *varName = args[1].sval;
+
+ if (thdName != NULL) {
+ if ((id = seq_findThread (thdName)) != NULL) {
+ seqVarGet (id,varName,NULL);
+ }
+ }
+}
+
+/*----------------------------------------------------------------
+ * seqVarPut (thread, varname, newval)
+ *----------------------------------------------------------------
+ */
+static const iocshArg seqVarPutArg0 = { "sequencer",iocshArgString };
+static const iocshArg seqVarPutArg1 = { "varName" ,iocshArgString };
+static const iocshArg seqVarPutArg2 = { "newVal" ,iocshArgString };
+
+static const iocshArg * const seqVarPutArgs[3] = { &seqVarPutArg0,
+ &seqVarPutArg1,
+ &seqVarPutArg2 };
+
+static const iocshFuncDef seqVarPutFuncDef = { "seqVarPut",3,seqVarPutArgs };
+
+static void seqVarPutCallFunc(const iocshArgBuf *args)
+{
+ epicsThreadId id;
+ char *thdName = args[0].sval;
+ char *varName = args[1].sval;
+ char *newVal = args[2].sval;
+
+ if (thdName != NULL) {
+ if ((id = seq_findThread (thdName)) != NULL) {
+ seqVarPut (id,varName,newVal);
+ }
+ }
+}
+
+/*----------------------------------------------------------------
+ * seqPvShow (thread)
+ * ... accepts missing arg as "0"
+ *----------------------------------------------------------------
+ */
+static const iocshArg seqPvShowArg0 = { "sequencer",iocshArgString };
+
+static const iocshArg * const seqPvShowArgs[1] = { &seqPvShowArg0 };
+
+static const iocshFuncDef seqPvShowFuncDef = { "seqPvShow",1,seqPvShowArgs };
+
+static void seqPvShowCallFunc(const iocshArgBuf *args)
+{
+ epicsThreadId id = 0;
+ char *thdName = args[0].sval;
+
+ if (thdName != NULL) {
+ if ((id = seq_findThread (thdName)) == NULL) id = 0;
+ }
+
+ seqPvShow (id);
+}
+
+/* SEQ_Run */
+static const iocshFuncDef SEQ_RunFuncDef = {"SEQ_Run",0,NULL};
+static void SEQ_RunCallFunc(const iocshArgBuf *args)
+{
+ SEQ_Run();
+}
+
+/* SEQ_Pause */
+static const iocshFuncDef SEQ_PauseFuncDef = {"SEQ_Pause",0,NULL};
+static void SEQ_PauseCallFunc(const iocshArgBuf *args)
+{
+ SEQ_Pause();
+}
+
+/*----------------------------------------------------------------*/
+/*----------------------------------------------------------------*/
+
/*
* This routine is called before multitasking has started, so there's
* no race condition in the test/set of firstTime.
@@ -169,11 +298,23 @@
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
- iocshRegister(&seqFuncDef,seqCallFunc);
- iocshRegister(&seqShowFuncDef,seqShowCallFunc);
- iocshRegister(&seqQueueShowFuncDef,seqQueueShowCallFunc);
- iocshRegister(&seqStopFuncDef,seqStopCallFunc);
- iocshRegister(&seqChanShowFuncDef,seqChanShowCallFunc);
- iocshRegister(&seqcarFuncDef,seqcarCallFunc);
+ iocshRegister ( &seqFuncDef , seqCallFunc );
+ iocshRegister ( &seqShowFuncDef , seqShowCallFunc );
+ iocshRegister ( &seqQueueShowFuncDef , seqQueueShowCallFunc );
+ iocshRegister ( &seqStopFuncDef , seqStopCallFunc );
+ iocshRegister ( &seqChanShowFuncDef , seqChanShowCallFunc );
+ iocshRegister ( &seqcarFuncDef , seqcarCallFunc );
+ iocshRegister ( &seqVarShowFuncDef , seqVarShowCallFunc );
+ iocshRegister ( &seqVarGetFuncDef , seqVarGetCallFunc );
+ iocshRegister ( &seqVarPutFuncDef , seqVarPutCallFunc );
+ iocshRegister ( &seqPvShowFuncDef , seqPvShowCallFunc );
+ iocshRegister ( &SEQ_RunFuncDef , SEQ_RunCallFunc );
+ iocshRegister ( &SEQ_PauseFuncDef , SEQ_PauseCallFunc );
+
}
}
+
+/*----------------------------------------------------------------*/
+/*----------------------------------------------------------------*/
+
+/* end */
Index: src/seq/seq_task.c
===================================================================
--- src/seq/seq_task.c (revision 194)
+++ src/seq/seq_task.c (working copy)
@@ -43,6 +43,9 @@
29feb00,wfl Supported new OSI (and errlogPrintf); new use of DEBUG macro;
implemented new sequencer deletion method.
31mar00,wfl Changed caSemId to be a mutex.
+16jan08,liu Support accessing local variabls.
+22oct08,liu Add SEQ_Run() and SEQ_Pause() to restart or freeze sequencer for
+ supporting ioc redundancy.
***************************************************************************/
#define DEBUG nothing /* "nothing", "printf", "errlogPrintf" etc. */
@@ -54,6 +57,10 @@
#define epicsExportSharedSymbols
#include "seq.h"
+/* Task Control */
+enum ctl {ctlRun, ctlPause};
+volatile enum ctl SEQ_Ctl = ctlRun;
+
/* Used to disable debug output */
void nothing(const char *format,...) {}
@@ -152,6 +159,12 @@
pSS->nextState = -1;
pSS->prevState = -1;
+ /* debugger stuff */
+ pSS->dbgRunState = SEQ_DBG_RUNSTATE_RUNNING;
+ pSS->dbgStateJump = FALSE;
+ pSS->dbgStepTrig = FALSE;
+ pSS->dbgStopBySeqStop = FALSE;
+
/* Use the event mask for this state */
pSS->pMask = (pST->pEventMask);
nWords = (pSP->numEvents + NBITS - 1) / NBITS;
@@ -186,16 +199,37 @@
/* Loop until an event is triggered, i.e. when() returns TRUE
*/
do {
+
/* Wake up on PV event, event flag, or expired delay */
delay = seq_getTimeout(pSS); /* min. delay from list */
- if (delay > 0.0)
- (void) epicsEventWaitWithTimeout(pSS->syncSemId,
- delay);
+ if( delay > 0.0 )
+ (void) epicsEventWaitWithTimeout(pSS->syncSemId, delay);
/* Check whether we have been asked to exit */
if (epicsEventTryWait(pSS->death1SemId) ==
epicsEventWaitOK) goto exit;
+ /* sleep here when ss is suspended. */
+ /* single step runnig is supported only when ss is suspended. */
+ while(pSS->dbgRunState != SEQ_DBG_RUNSTATE_RUNNING)
+ {
+ epicsThreadSleep(0.1);
+
+ if(pSS->dbgStepTrig == TRUE)
+ {
+ pSS->dbgStepTrig = FALSE;
+ break;
+ }
+ }
+
+ /* update pST. It is used for state jumping */
+ while(pSS->dbgStateJump == TRUE)
+ {
+ epicsThreadSleep(0.1);
+ pSS->dbgStateJump = FALSE;
+ }
+ pST = pSS->pStates + pSS->currentState;
+
/* Call the event function to check for an event
* trigger. The statement inside the when() statement
* is executed. Note, we lock out PV events while doing
@@ -241,6 +275,25 @@
pSS->prevState = pSS->currentState;
pSS->currentState = pSS->nextState;
pST = pSS->pStates + pSS->currentState;
+
+
+ /* (1)when IOC is slave, sleep here and update pST. */
+ /* (2)support state program reloading. when seqStop(tid) is executed, */
+ /* it set pSS->dbgStopBySeqStop to TRUE which awakes ss_entry(pSS). */
+
+ while( SEQ_Ctl == ctlPause )
+ {
+ if( pSS->dbgStopBySeqStop == TRUE)
+ {
+ pSS->dbgStopBySeqStop = FALSE;
+ break;
+ }
+
+ epicsThreadSleep(0.1);
+ pSS->prevState = pSS->currentState;
+ pSS->currentState = pSS->nextState;
+ pST = pSS->pStates + pSS->currentState;
+ }
}
/* Thread exit has been requested */
@@ -450,6 +503,7 @@
/* Ask the thread to exit */
DEBUG(" tid=%p\n", pSS->threadId);
epicsEventSignal(pSS->death1SemId);
+ pSS->dbgStopBySeqStop = TRUE; /* awake the sleeping state set for SLAVE */
}
/* Wake up all state-sets */
@@ -590,6 +644,9 @@
/* Free SSCBs */
free(pSP->pSS);
+ /* Free local-variable table, if allocated */
+ if (pSP->options & OPT_REENT) free (pSP->pVarTbl);
+
/* Free SPROG */
free(pSP);
}
@@ -599,34 +656,49 @@
*/
void *seqAuxThread(void *tArgs)
{
- AUXARGS *pArgs = (AUXARGS *)tArgs;
- char *pPvSysName = pArgs->pPvSysName;
- long debug = pArgs->debug;
- int status;
- extern epicsThreadId seqAuxThreadId;
+ AUXARGS *pArgs = (AUXARGS *)tArgs;
+ char *pPvSysName = pArgs->pPvSysName;
+ long debug = pArgs->debug;
+ int status;
+ extern epicsThreadId seqAuxThreadId;
- /* Register this thread with the EPICS watchdog */
- taskwdInsert(epicsThreadGetIdSelf(),(SEQVOIDFUNCPTR)0, (void *)0);
+ /* Register this thread with the EPICS watchdog */
+ taskwdInsert(epicsThreadGetIdSelf(),(SEQVOIDFUNCPTR)0, (void *)0);
- /* All state program threads will use a common PV context (subtract
- 1 from debug level for PV debugging) */
- status = pvSysCreate(pPvSysName, debug>0?debug-1:0, &pvSys);
- if (status != pvStatOK)
- {
- errlogPrintf("seqAuxThread: pvSysCreate() %s failure: %s\n",
- pPvSysName, pvSysGetMess(pvSys));
- seqAuxThreadId = (epicsThreadId) -1;
- return NULL;
- }
- seqAuxThreadId = epicsThreadGetIdSelf(); /* AFTER pvSysCreate() */
+ /* All state program threads will use a common PV context (subtract
+ 1 from debug level for PV debugging) */
+ status = pvSysCreate(pPvSysName, debug>0?debug-1:0, &pvSys);
+ if (status != pvStatOK)
+ {
+ errlogPrintf("seqAuxThread: pvSysCreate() %s failure: %s\n",
+ pPvSysName, pvSysGetMess(pvSys));
+ seqAuxThreadId = (epicsThreadId) -1;
+ return NULL;
+ }
+ seqAuxThreadId = epicsThreadGetIdSelf(); /* AFTER pvSysCreate() */
- /* This loop allows for check for connect/disconnect on PVs */
- for (;;)
- {
- pvSysPend(pvSys, 10.0, TRUE); /* returns every 10 sec. */
- }
+ /* This loop allows for check for connect/disconnect on PVs */
+ for (;;)
+ {
+ pvSysPend(pvSys, 10.0, TRUE); /* returns every 10 sec. */
+ }
- /* Return no result (never exit in any case) */
- return NULL;
+ /* Return no result (never exit in any case) */
+ /*return NULL; */
}
+/* SEQ_Run()/SEQ_Pause() to restart/freeze sequencer for supporting ioc redundancy. */
+void SEQ_Run(void)
+{
+ SEQ_Ctl = ctlRun;
+ errlogPrintf("SEQ_Run: sequencer is running\n");
+ return;
+}
+
+void SEQ_Pause(void)
+{
+ SEQ_Ctl = ctlPause;
+ errlogPrintf("SEQ_Pause: sequencer is paused\n");
+ return;
+}
+
Index: src/seq/Makefile
===================================================================
--- src/seq/Makefile (revision 194)
+++ src/seq/Makefile (working copy)
@@ -5,7 +5,7 @@
# ADD MACRO DEFINITIONS AFTER THIS LINE
# Include files
-INC = seqCom.h
+INC = seq.h seqCom.h seqPvt.h
# Internal debug control
#USR_CPPFLAGS = -DDEBUG=TRUE
Index: src/seq/seqCom.h
===================================================================
--- src/seq/seqCom.h (revision 194)
+++ src/seq/seqCom.h (working copy)
@@ -34,7 +34,11 @@
* 22sep99,grw Supported entry and exit actions; supported state options.
* 29feb00,wfl Converted to new OSI; new magic number.
* 31mar00,wfl Included pvAlarm.h; added entry function; new magic number.
+ * 20dec07,liu Add struct seqVar to hold information about a local variable.
+ * 22oct08,liu Add functions SEQ_Run() and SEQ_Pause() to restart or freeze sequencer
+ * for supportng ioc redundancy.
*/
+
#ifndef INCLseqComh
#define INCLseqComh
@@ -100,7 +104,8 @@
* from the start of a structure */
#define OFFSET(structure, member) ((long) &(((structure *) 0) -> member))
-/* Structure to hold information about database channels */
+
+/* Structure to hold information about database channels */
struct seqChan
{
char *dbAsName; /* assigned channel name */
@@ -117,6 +122,20 @@
int queueIndex; /* syncQ queue index */
};
+/* Structure to hold information about one local variable */
+struct seqVar
+{
+ char *name; /* name (string) */
+ int type; /* type (enum) */
+ char *type_str; /* type (string) */
+ int class; /* class (enum) */
+ int length1; /* 1st array dimension (1 if none) */
+ int length2; /* 2nd array dimension (1 if none) */
+ char *init; /* initial value (string) */
+ char *addr; /* ptr to var (reentrant case is resolved at runtime) */
+};
+typedef struct seqVar SVAR;
+
/* Structure to hold information about a state */
struct seqState
{
@@ -146,6 +165,8 @@
char *pProgName; /* program name (for debugging) */
struct seqChan *pChan; /* table of channels */
long numChans; /* number of db channels */
+ SVAR *pVarTbl; /* table of local vars */
+ long numVars; /* number of local vars */
struct seqSS *pSS; /* array of state set info structs */
long numSS; /* number of state sets */
long varSize; /* # bytes in user variable area */
@@ -212,7 +233,15 @@
seq(struct seqProgram *, char *, unsigned int);
epicsShareFunc struct state_program *epicsShareAPI seqFindProgByName (char *);
+epicsShareFunc long epicsShareAPI seqVarGet (epicsThreadId, char *, char *);
+epicsShareFunc long epicsShareAPI seqVarPut (epicsThreadId, char *, char *);
+epicsShareFunc long epicsShareAPI seqPvShow (epicsThreadId);
+
+/* restart or freeze sequencer for supportng ioc redundancy */
+epicsShareFunc void SEQ_Run(void);
+epicsShareFunc void SEQ_Pause(void);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
Index: src/seq/seq_main.c
===================================================================
--- src/seq/seq_main.c (revision 194)
+++ src/seq/seq_main.c (working copy)
@@ -6,7 +6,7 @@
seq_main.c,v 1.2 1995/06/27 15:25:58 wright Exp
- DESCRIPTION: Seq() initiates a sequence as a group of cooperating
+ DESCRIPTION: Seq() initiates a sequencer as a group of cooperating
tasks. An optional string parameter specifies the values for
macros. The PV context and auxiliary thread are shared by all state
programs.
@@ -62,6 +62,7 @@
29feb00,wfl Supported new OSI (and errlogPrintf); got rid of remaining
OS-dependencies; improved command-line interpreter
31mar00,wfl Supported 'shell' macro to run shell; made caSemId a mutex
+20dec07,liu Support accessing local variabls.
***************************************************************************/
/*#define DEBUG 1*/
@@ -89,6 +90,7 @@
LOCAL void init_sprog(struct seqProgram *, SPROG *);
LOCAL void init_sscb(struct seqProgram *, SPROG *);
LOCAL void init_chan(struct seqProgram *, SPROG *);
+LOCAL void init_locvar(struct seqProgram *, SPROG *);
LOCAL void init_mac(SPROG *);
LOCAL void seq_logInit(SPROG *);
@@ -102,6 +104,8 @@
/* Auxiliary sequencer thread id; used to share PV context. */
epicsThreadId seqAuxThreadId = (epicsThreadId) 0;
+/********************************************************************/
+
/*
* seq: User-callable routine to initiate a state program.
* Usage: seq(<pSP>, <macros string>, <stack size>)
@@ -135,9 +139,9 @@
/* Check for correct state program format */
if (pSeqProg->magic != MAGIC)
{ /* Oops */
- errlogPrintf("Illegal magic number in state program.\n");
- errlogPrintf(" - Possible mismatch between SNC & SEQ "
- "versions\n");
+ errlogPrintf("Illegal magic number in state program!\n");
+ errlogPrintf(" - Possible mismatch between SNC & SEQ versions\n");
+ errlogPrintf(" - snc:%ld seq:%d\n",pSeqProg->magic,MAGIC);
errlogPrintf(" - Re-compile your program?\n");
epicsThreadSleep( 1.0 ); /* let error messages get printed */
return 0;
@@ -213,10 +217,11 @@
}
/* Spawn the initial sequencer thread */
+
#ifdef DEBUG
- printf("Spawning thread %s, stackSize=%d\n", pThreadName,
- pSP->stackSize);
+ printf("Spawning thread %s, stackSize=%d\n",pThreadName,pSP->stackSize);
#endif /*DEBUG*/
+
/* Specify thread priority */
pSP->threadPriority = THREAD_PRIORITY;
pValue = seqMacValGet(pSP->pMacros, "priority");
@@ -235,7 +240,10 @@
return tid;
}
-/* seqInitTables - initialize sequencer tables */
+
+/********************************************************************/
+
+/* seqInitTables - initialize sequencer tables */
LOCAL SPROG *seqInitTables(pSeqProg)
struct seqProgram *pSeqProg;
{
@@ -255,10 +263,15 @@
/* Initialize the macro table */
init_mac(pSP);
+ /* Initialize local variable table */
+ init_locvar(pSeqProg, pSP);
return pSP;
}
-/*
+
+/********************************************************************/
+
+/*
* Copy data from seqCom.h structures into this thread's dynamic structures
* as defined in seq.h.
*/
@@ -269,14 +282,16 @@
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->entryFunc = (ENTRY_FUNC)pSeqProg->entryFunc;
- pSP->exitFunc = (EXIT_FUNC)pSeqProg->exitFunc;
- pSP->varSize = pSeqProg->varSize;
+ pSP->numSS = pSeqProg->numSS;
+ pSP->numChans = pSeqProg->numChans;
+ pSP->numVars = pSeqProg->numVars;
+ pSP->numEvents = pSeqProg->numEvents;
+ pSP->options = pSeqProg->options;
+ pSP->pProgName = pSeqProg->pProgName;
+ pSP->entryFunc = (ENTRY_FUNC)pSeqProg->entryFunc;
+ 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);
@@ -315,6 +330,9 @@
return;
}
+
+/********************************************************************/
+
/*
* Initialize the state set control blocks
*/
@@ -355,8 +373,7 @@
/* Create a binary semaphore for synchronizing events in a SS */
pSS->syncSemId = epicsEventMustCreate(epicsEventEmpty);
- /* Create binary semaphores for synchronous pvGet() and
- pvPut() */
+ /* Create binary semaphores for synchronous pvGet() and pvPut() */
pSS->getSemId = epicsEventMustCreate(epicsEventFull);
pSS->putSemId = epicsEventMustCreate(epicsEventFull);
@@ -374,14 +391,15 @@
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->entryFunc = (ENTRY_FUNC)pSeqState->entryFunc;
- pState->exitFunc = (EXIT_FUNC)pSeqState->exitFunc;
- pState->pEventMask = pSeqState->pEventMask;
- pState->options = pSeqState->options;
+ pState->pStateName = pSeqState->pStateName;
+ pState->actionFunc = (ACTION_FUNC) pSeqState->actionFunc;
+ pState->eventFunc = (EVENT_FUNC) pSeqState->eventFunc;
+ pState->delayFunc = (DELAY_FUNC) pSeqState->delayFunc;
+ pState->entryFunc = (ENTRY_FUNC) pSeqState->entryFunc;
+ pState->exitFunc = (EXIT_FUNC) pSeqState->exitFunc;
+
+ pState->pEventMask = pSeqState->pEventMask;
+ pState->options = pSeqState->options;
#ifdef DEBUG
printf("init_sscb: State Name=%s, Event Mask=%p\n",
pState->pStateName, *pState->pEventMask);
@@ -394,7 +412,64 @@
#endif /*DEBUG*/
return;
}
-
+
+/********************************************************************/
+
+/* init_one_chan -- called by init_chan (below)
+ */
+LOCAL void init_one_chan(SPROG *pSP,
+ CHAN *pDB,
+ struct seqChan *pSeqChan)
+{
+#ifdef DEBUG
+ printf("init_chan: pDB=%p\n", pDB);
+#endif /*DEBUG*/
+
+ pDB->sprog = pSP;
+ pDB->sset = NULL; /* set temporarily during get/put */
+
+ pDB->dbAsName = pSeqChan->dbAsName;
+ pDB->pVarName = pSeqChan->pVarName;
+ pDB->pVarType = pSeqChan->pVarType;
+ pDB->pVar = pSeqChan->pVar; /* offset for +r option */
+ pDB->count = pSeqChan->count;
+ pDB->efId = pSeqChan->efId;
+ pDB->monFlag = pSeqChan->monFlag;
+ pDB->eventNum = pSeqChan->eventNum;
+ pDB->queued = pSeqChan->queued;
+
+ pDB->maxQueueSize = pSeqChan->maxQueueSize ?
+ pSeqChan->maxQueueSize : MAX_QUEUE_SIZE;
+
+ pDB->queueIndex = pSeqChan->queueIndex;
+
+ pDB->assigned = 0;
+
+ /* Latest error message (dynamically allocated) */
+ pDB->message = NULL;
+
+ /* Fill in get/put db types, element size, & access offset */
+ selectDBtype(pSeqChan->pVarType,
+ &pDB->getType,
+ &pDB->putType,
+ &pDB->size,
+ &pDB->dbOffset);
+
+ /* Reentrant option: Convert offset to addr of the user var. */
+ if ((pSP->options & OPT_REENT) != 0)
+ pDB->pVar += (ptrdiff_t)pSP->pVar;
+
+#ifdef DEBUG
+ printf(" Assigned Name=%s, VarName=%s, VarType=%s, count=%d\n",
+ pDB->dbAsName, pDB->pVarName, pDB->pVarType, pDB->count);
+ printf(" size=%d, dbOffset=%d\n", pDB->size, pDB->dbOffset);
+ printf(" efId=%d, monFlag=%d, eventNum=%d\n",
+ pDB->efId, pDB->monFlag, pDB->eventNum);
+#endif /*DEBUG*/
+}
+
+/*----------------------------------------------------------------*/
+
/*
* init_chan--Build the database channel structures.
* Note: Actual PV name is not filled in here. */
@@ -407,53 +482,53 @@
struct seqChan *pSeqChan;
/* Allocate space for the CHAN structures */
- pSP->pChan = (CHAN *)calloc(pSP->numChans, sizeof(CHAN));
- pDB = pSP->pChan;
+ pDB = pSP->pChan = (CHAN *)calloc(pSP->numChans, sizeof(CHAN));
pSeqChan = pSeqProg->pChan;
- for (nchan = 0; nchan < pSP->numChans; nchan++, pDB++, pSeqChan++)
+
+ for (nchan = 0;
+ nchan < pSP->numChans;
+ nchan++, pDB++, pSeqChan++)
{
-#ifdef DEBUG
- printf("init_chan: pDB=%p\n", pDB);
-#endif /*DEBUG*/
- pDB->sprog = pSP;
- pDB->sset = NULL; /* set temporarily during get/put */
- pDB->dbAsName = pSeqChan->dbAsName;
- pDB->pVarName = pSeqChan->pVarName;
- pDB->pVarType = pSeqChan->pVarType;
- pDB->pVar = pSeqChan->pVar; /* offset for +r option */
- pDB->count = pSeqChan->count;
- pDB->efId = pSeqChan->efId;
- pDB->monFlag = pSeqChan->monFlag;
- pDB->eventNum = pSeqChan->eventNum;
- pDB->queued = pSeqChan->queued;
- pDB->maxQueueSize = pSeqChan->maxQueueSize ?
- pSeqChan->maxQueueSize : MAX_QUEUE_SIZE;
- pDB->queueIndex = pSeqChan->queueIndex;
- pDB->assigned = 0;
+ init_one_chan(pSP,pDB,pSeqChan);
+ }
+}
- /* Latest error message (dynamically allocated) */
- pDB->message = NULL;
+/********************************************************************/
- /* Fill in get/put db types, element size, & access offset */
- selectDBtype(pSeqChan->pVarType, &pDB->getType,
- &pDB->putType, &pDB->size, &pDB->dbOffset);
+/* init_locvar -- init local-variable table
+ * ... if re-entrant, make a copy of the seqVars struct, otherwise just
+ * use the compiled one
+ */
+LOCAL void init_locvar(pSeqProg, pSP)
+struct seqProgram *pSeqProg; /* compiled struct */
+SPROG *pSP; /* dynamic struct */
+{
+ if (pSP->options & OPT_REENT) {
- /* Reentrant option: Convert offset to addr of the user var. */
- if ((pSP->options & OPT_REENT) != 0)
- pDB->pVar += (ptrdiff_t)pSP->pVar;
-#ifdef DEBUG
- printf(" Assigned Name=%s, VarName=%s, VarType=%s, "
- "count=%d\n", pDB->dbAsName, pDB->pVarName,
- pDB->pVarType, pDB->count);
- printf(" size=%d, dbOffset=%d\n", pDB->size,
- pDB->dbOffset);
- printf(" efId=%d, monFlag=%d, eventNum=%d\n",
- pDB->efId, pDB->monFlag, pDB->eventNum);
-#endif /*DEBUG*/
- }
+ SVAR *pVarTbl = (SVAR*)calloc(pSP->numVars, sizeof(SVAR));
+ int n;
+
+ pSP->pVarTbl = pVarTbl; /* ptr to thread-specific struct */
+
+ /* copy compiled struct to thread-local version */
+ memcpy(pSP->pVarTbl, pSeqProg->pVarTbl, pSP->numVars * sizeof(SVAR));
+
+ /* resolve address of each local var */
+ for (n = 0;
+ n < pSP->numVars;
+ n++, pVarTbl++)
+ {
+ pVarTbl->addr += (ptrdiff_t)pSP->pVar; /* add start of var block to offset */
+ }
+ }
+ else { /* not reentrant; use compiled struct w/static addresses */
+ pSP->pVarTbl = pSeqProg->pVarTbl;
+ }
}
+/********************************************************************/
+
/*
* init_mac - initialize the macro table.
*/
@@ -474,7 +549,10 @@
pMac->pValue = NULL;
}
}
-/*
+
+/********************************************************************/
+
+/*
* Evaluate channel names by macro substitution.
*/
#define MACRO_STR_LEN (MAX_STRING_SIZE+1)
@@ -495,7 +573,10 @@
#endif /*DEBUG*/
}
}
-/*
+
+/********************************************************************/
+
+/*
* selectDBtype -- returns types for DB put/get, element size, and db access
* offset based on user variable type.
* Mapping is determined by the following typeMap[] array.
@@ -568,6 +649,8 @@
}
};
+/********************************************************************/
+
LOCAL void selectDBtype(pUserType, pGetType, pPutType, pSize, pOffset)
char *pUserType;
short *pGetType, *pPutType, *pSize, *pOffset;
@@ -589,7 +672,10 @@
return;
}
-/*
+
+/********************************************************************/
+
+/*
* seq_logInit() - Initialize logging.
* If "logfile" is not specified, then we log to standard output.
*/
@@ -622,7 +708,10 @@
}
}
}
-/*
+
+/********************************************************************/
+
+/*
* seq_logv
* Log a message to the console or a file with thread name, date, & time of day.
* The format looks like "mythread 12/13/93 10:07:43: Hello world!".
@@ -678,7 +767,10 @@
}
return OK;
}
-/*
+
+/********************************************************************/
+
+/*
* seq_seqLog() - State program interface to seq_log().
* Does not require ptr to state program block.
*/
@@ -694,3 +786,6 @@
va_end (args);
return(rtn);
}
+
+/********************************************************************/
+/********************************************************************/
- Navigate by Date:
- Prev:
Re: errlogVprintf does not print messages to console Andrew Johnson
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: errlogVprintf does not print messages to console Andrew Johnson
- Index:
2002
2003
2004
2005
2006
2007
<2008>
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|