try to make things work on 64 bit systems
Annotate for file src/seq/seq_main.c
2000-04-04 William 1 /**************************************************************************
03:23:15 ' 2 GTA PROJECT AT division
' 3 Copyright, 1990-1994, The Regents of the University of California
' 4 and the University of Chicago.
' 5 Los Alamos National Laboratory
' 6
' 7 seq_main.c,v 1.2 1995/06/27 15:25:58 wright Exp
' 8
' 9 DESCRIPTION: Seq() initiates a sequence as a group of cooperating
' 10 tasks. An optional string parameter specifies the values for
' 11 macros. The PV context and auxiliary thread are shared by all state
' 12 programs.
' 13
' 14 ENVIRONMENT: VxWorks
' 15
' 16 HISTORY:
' 17 23apr91,ajk Fixed problem with state program invoking the sequencer.
' 18 01jul91,ajk Added ANSI functional prototypes.
' 19 05jul91,ajk Changed semCreate() in three places to semBCreate.
' 20 Modified semTake() second param. to WAIT_FOREVER.
' 21 These provide VX5.0 compatability.
' 22 16aug91,ajk Improved "magic number" error message.
' 23 25oct91,ajk Code to create semaphores "pSS->getSemId" was left out.
' 24 Added this code to init_sscb().
' 25 25nov91,ajk Removed obsolete seqLog() code dealing with global locking.
' 26 04dec91,ajk Implemented state program linked list, eliminating need for
' 27 task variables.
' 28 11dec91,ajk Cleaned up comments.
' 29 05feb92,ajk Decreased minimum allowable stack size to SPAWN_STACK_SIZE/2.
' 30 24feb92,ajk Print error code for log file failure.
' 31 28apr92,ajk Implemented new event flag mode.
' 32 29apr92,ajk Now alocates private program structures, even when reentry option
' 33 is not specified. This avoids problems with seqAddTask().
' 34 29apr92,ajk Implemented mutual exclusion lock in seq_log().
' 35 16feb93,ajk Converted to single channel access task for all state programs.
' 36 16feb93,ajk Removed VxWorks pre-v5 stuff.
' 37 17feb93,ajk Evaluation of channel names moved here from seq_ca.c.
' 38 19feb93,ajk Fixed time stamp format for seq_log().
' 39 16jun93,ajk Fixed taskSpawn() to have 15 args per vx5.1.
' 40 20jul93,ajk Replaced obsolete delete() with remove() per vx5.1 release notes.
' 41 20jul93,ajk Removed #define ANSI
' 42 15mar94,ajk Implemented i/f to snc through structures in seqCom.h.
' 43 15mar94,ajk Allowed assignment of array elements to db.
' 44 15mar94,ajk Rearranged code that builds program structures.
' 45 02may94,ajk Performed initialization when sequencer is evoked, even w/o
' 46 parameters.
' 47 19jul95,ajk Added unsigned types (unsigned char, short, int, long).
' 48 20jul95,ajk Added priority specification at run time.
' 49 03aug95,ajk Fixed problem with +r option: user variable space (pSP->pVar)
' 50 was not being allocated.
' 51 03jun96,ajk Now compiles with -wall and -pedantic switches.
' 52 09aug96,wfl Added initialization of syncQ queues.
' 53 30apr99,wfl Replaced VxWorks dependencies with OSI.
' 54 17may99,wfl Under UNIX, call OSIthreadJoinAll() rather than exiting.
' 55 17may99,wfl Moved misplaced event array initialization.
' 56 06jul99,wfl Slightly improved Unix command-line interpreter.
' 57 07sep99,wfl Added "-" Unix command (==seqChanShow("-"));
' 58 Unconditionally create get/put completion semaphores.
' 59 22sep99,grw Supported entry and exit actions; supported state options.
' 60 18feb00,wfl Re-worked args (inc. run-time debug level) for seqAuxThread;
' 61 Called sprog_delete() on Unix thread exit
' 62 29feb00,wfl Supported new OSI (and errlogPrintf); got rid of remaining
' 63 OS-dependencies; improved command-line interpreter
' 64 31mar00,wfl Supported 'shell' macro to run shell; made caSemId a mutex
' 65 ***************************************************************************/
' 66 /*#define DEBUG 1*/
' 67
' 68 #include <sys/types.h>
' 69 #include <sys/stat.h>
' 70
' 71 #include <errno.h>
' 72 #include <fcntl.h>
' 73 #include <string.h>
2004-01-15 Marty 74 #include <stddef.h>
2000-04-18 W. 75 #include <stdarg.h>
2000-04-04 William 76
2000-04-14 Janet 77 /* #include <unistd.h>*/
21:55:19 ' 78
' 79 #define epicsExportSharedSymbols
2000-04-04 William 80 #include "seq.h"
03:23:15 ' 81
' 82 #ifdef DEBUG
' 83 #undef LOCAL
' 84 #define LOCAL
' 85 #endif /*DEBUG*/
' 86
' 87 /* function prototypes for local routines */
' 88 LOCAL SPROG *seqInitTables(struct seqProgram *);
' 89 LOCAL void init_sprog(struct seqProgram *, SPROG *);
' 90 LOCAL void init_sscb(struct seqProgram *, SPROG *);
' 91 LOCAL void init_chan(struct seqProgram *, SPROG *);
' 92 LOCAL void init_mac(SPROG *);
' 93
' 94 LOCAL void seq_logInit(SPROG *);
' 95 LOCAL void seqChanNameEval(SPROG *);
' 96 LOCAL void selectDBtype(char *, short *, short *, short *, short *);
' 97
' 98 #define SCRATCH_SIZE (MAX_MACROS*(MAX_STRING_SIZE+1)*12)
' 99
' 100 /* Globals */
' 101
' 102 /* Auxiliary sequencer thread id; used to share PV context. */
2001-02-16 Marty 103 epicsThreadId seqAuxThreadId = (epicsThreadId) 0;
2000-04-04 William 104
03:23:15 ' 105 /*
' 106 * seq: User-callable routine to initiate a state program.
' 107 * Usage: seq(<pSP>, <macros string>, <stack size>)
' 108 * pSP is the ptr to the state program structure.
' 109 * Example: seq(&myprog, "logfile=mylog", 0)
' 110 * When called from the shell, the 2nd & 3rd parameters are optional.
' 111 *
' 112 * Creates the initial state program thread and returns its thread id.
' 113 * Most initialization is performed here.
' 114 */
2001-03-19 Marty 115 epicsShareFunc epicsThreadId epicsShareAPI seq (
2001-02-23 Marty 116 struct seqProgram *pSeqProg, char *macroDef, unsigned int stackSize)
2000-04-04 William 117 {
2001-02-16 Marty 118 epicsThreadId tid;
2000-04-04 William 119 extern char *seqVersion;
03:23:15 ' 120 SPROG *pSP;
' 121 char *pValue, *pThreadName;
' 122 unsigned int smallStack;
' 123 AUXARGS auxArgs;
' 124 extern void *seqAuxThread(void *);
' 125
' 126 /* Print version & date of sequencer */
2001-03-19 Marty 127 printf("%s\n", seqVersion);
2000-04-04 William 128
03:23:15 ' 129 /* Exit if no parameters specified */
' 130 if (pSeqProg == 0)
' 131 {
' 132 return 0;
' 133 }
' 134
' 135 /* Check for correct state program format */
' 136 if (pSeqProg->magic != MAGIC)
' 137 { /* Oops */
' 138 errlogPrintf("Illegal magic number in state program.\n");
' 139 errlogPrintf(" - Possible mismatch between SNC & SEQ "
' 140 "versions\n");
' 141 errlogPrintf(" - Re-compile your program?\n");
2001-02-16 Marty 142 epicsThreadSleep( 1.0 ); /* let error messages get printed */
2001-03-19 Marty 143 return 0;
2000-04-04 William 144 }
03:23:15 ' 145
' 146 /* Initialize the sequencer tables */
' 147 pSP = seqInitTables(pSeqProg);
' 148
' 149 /* Parse the macro definitions from the "program" statement */
' 150 seqMacParse(pSeqProg->pParams, pSP);
' 151
' 152 /* Parse the macro definitions from the command line */
' 153 seqMacParse(macroDef, pSP);
' 154
' 155 /* Do macro substitution on channel names */
' 156 seqChanNameEval(pSP);
' 157
' 158 /* Initialize sequencer logging */
' 159 seq_logInit(pSP);
' 160
' 161 /* Specify stack size */
' 162 if (stackSize == 0)
2001-02-16 Marty 163 stackSize = epicsThreadGetStackSize(THREAD_STACK_SIZE);
2000-04-04 William 164 pValue = seqMacValGet(pSP->pMacros, "stack");
03:23:15 ' 165 if (pValue != NULL && strlen(pValue) > 0)
' 166 {
' 167 sscanf(pValue, "%ud", &stackSize);
' 168 }
2001-02-16 Marty 169 smallStack = epicsThreadGetStackSize(epicsThreadStackSmall);
2000-04-04 William 170 if (stackSize < smallStack)
03:23:15 ' 171 stackSize = smallStack;
' 172 pSP->stackSize = stackSize;
' 173
' 174 /* Specify thread name */
' 175 pValue = seqMacValGet(pSP->pMacros, "name");
' 176 if (pValue != NULL && strlen(pValue) > 0)
' 177 pThreadName = pValue;
' 178 else
' 179 pThreadName = pSP->pProgName;
' 180
' 181 /* Specify PV system name (defaults to CA) */
' 182 pValue = seqMacValGet(pSP->pMacros, "pvsys");
' 183 if (pValue != NULL && strlen(pValue) > 0)
' 184 auxArgs.pPvSysName = pValue;
' 185 else
' 186 auxArgs.pPvSysName = "ca";
' 187
' 188 /* Determine debug level (currently only used for PV-level debugging) */
' 189 pValue = seqMacValGet(pSP->pMacros, "debug");
' 190 if (pValue != NULL && strlen(pValue) > 0)
' 191 auxArgs.debug = atol(pValue);
' 192 else
' 193 auxArgs.debug = 0;
' 194
' 195 /* Spawn the sequencer auxiliary thread */
2001-02-16 Marty 196 if (seqAuxThreadId == (epicsThreadId) 0)
2000-04-04 William 197 {
2001-10-03 Marty 198 unsigned int auxStack = epicsThreadGetStackSize(epicsThreadStackMedium);
2001-02-16 Marty 199 epicsThreadCreate("seqAux", THREAD_PRIORITY+1, auxStack,
18:45:42 ' 200 (EPICSTHREADFUNC)seqAuxThread, &auxArgs);
' 201 while (seqAuxThreadId == (epicsThreadId) 0)
2000-04-04 William 202 /* wait for thread to init. message system */
2001-02-16 Marty 203 epicsThreadSleep(0.1);
2000-04-04 William 204
2001-02-16 Marty 205 if (seqAuxThreadId == (epicsThreadId) -1)
2000-04-04 William 206 {
2001-02-16 Marty 207 epicsThreadSleep( 1.0 ); /* let error messages get printed */
2001-03-19 Marty 208 return 0;
2000-04-04 William 209 }
03:23:15 ' 210 #ifdef DEBUG
2001-03-19 Marty 211 printf("thread seqAux spawned, tid=%p\n", (int) seqAuxThreadId);
2000-04-04 William 212 #endif /*DEBUG*/
03:23:15 ' 213 }
' 214
' 215 /* Spawn the initial sequencer thread */
' 216 #ifdef DEBUG
2001-03-19 Marty 217 printf("Spawning thread %s, stackSize=%d\n", pThreadName,
2000-04-04 William 218 pSP->stackSize);
03:23:15 ' 219 #endif /*DEBUG*/
' 220 /* Specify thread priority */
' 221 pSP->threadPriority = THREAD_PRIORITY;
' 222 pValue = seqMacValGet(pSP->pMacros, "priority");
' 223 if (pValue != NULL && strlen(pValue) > 0)
' 224 {
' 225 sscanf(pValue, "%ud", &(pSP->threadPriority));
' 226 }
' 227 if (pSP->threadPriority > THREAD_PRIORITY)
' 228 pSP->threadPriority = THREAD_PRIORITY;
' 229
2001-02-16 Marty 230 tid = epicsThreadCreate(pThreadName, pSP->threadPriority, pSP->stackSize,
18:45:42 ' 231 (EPICSTHREADFUNC)sequencer, pSP);
2000-04-04 William 232
2001-03-19 Marty 233 printf("Spawning state program \"%s\", thread %p: \"%s\"\n",
2000-04-04 William 234 pSP->pProgName, tid, pThreadName);
03:23:15 ' 235
2001-03-19 Marty 236 return tid;
2000-04-04 William 237 }
03:23:15 ' 238 /* seqInitTables - initialize sequencer tables */
' 239 LOCAL SPROG *seqInitTables(pSeqProg)
' 240 struct seqProgram *pSeqProg;
' 241 {
' 242 SPROG *pSP;
' 243
' 244 pSP = (SPROG *)calloc(1, sizeof (SPROG));
' 245
' 246 /* Initialize state program block */
' 247 init_sprog(pSeqProg, pSP);
' 248
' 249 /* Initialize state set control blocks */
' 250 init_sscb(pSeqProg, pSP);
' 251
' 252 /* Initialize database channel blocks */
' 253 init_chan(pSeqProg, pSP);
' 254
' 255 /* Initialize the macro table */
' 256 init_mac(pSP);
' 257
' 258
' 259 return pSP;
' 260 }
' 261 /*
' 262 * Copy data from seqCom.h structures into this thread's dynamic structures
' 263 * as defined in seq.h.
' 264 */
' 265 LOCAL void init_sprog(pSeqProg, pSP)
' 266 struct seqProgram *pSeqProg;
' 267 SPROG *pSP;
' 268 {
' 269 int i, nWords;
' 270
' 271 /* Copy information for state program */
' 272 pSP->numSS = pSeqProg->numSS;
' 273 pSP->numChans = pSeqProg->numChans;
' 274 pSP->numEvents = pSeqProg->numEvents;
' 275 pSP->options = pSeqProg->options;
' 276 pSP->pProgName = pSeqProg->pProgName;
' 277 pSP->entryFunc = (ENTRY_FUNC)pSeqProg->entryFunc;
' 278 pSP->exitFunc = (EXIT_FUNC)pSeqProg->exitFunc;
' 279 pSP->varSize = pSeqProg->varSize;
' 280 /* Allocate user variable area if reentrant option (+r) is set */
' 281 if ((pSP->options & OPT_REENT) != 0)
' 282 pSP->pVar = (char *)calloc(pSP->varSize, 1);
' 283
' 284 #ifdef DEBUG
2001-03-19 Marty 285 printf("init_sprog: num SS=%d, num Chans=%d, num Events=%d, "
2000-04-04 William 286 "Prog Name=%s, var Size=%d\n", pSP->numSS, pSP->numChans,
03:23:15 ' 287 pSP->numEvents, pSP->pProgName, pSP->varSize);
' 288 #endif /*DEBUG*/
' 289
' 290 /* Create a semaphore for resource locking on PV events */
2001-02-16 Marty 291 pSP->caSemId = epicsMutexMustCreate();
2000-04-04 William 292 pSP->connCount = 0;
03:23:15 ' 293 pSP->assignCount = 0;
' 294 pSP->logFd = NULL;
' 295
' 296 /* Allocate an array for event flag bits */
' 297 nWords = (pSP->numEvents + NBITS - 1) / NBITS;
' 298 if (nWords == 0)
' 299 nWords = 1;
' 300 pSP->pEvents = (bitMask *)calloc(nWords, sizeof(bitMask));
' 301 for (i = 0; i < nWords; i++)
' 302 pSP->pEvents[i] = 0;
' 303
' 304 /* Allocate and initialize syncQ queues */
' 305 pSP->numQueues = pSeqProg->numQueues;
' 306 pSP->pQueues = NULL;
' 307
' 308 if (pSP->numQueues > 0 )
' 309 {
' 310 pSP->pQueues = (ELLLIST *)calloc(pSP->numQueues,
' 311 sizeof(ELLLIST));
' 312 for (i = 0; i < pSP->numQueues; i++)
' 313 ellInit(&pSP->pQueues[i]);
' 314 }
' 315
' 316 return;
' 317 }
' 318 /*
' 319 * Initialize the state set control blocks
' 320 */
' 321 LOCAL void init_sscb(pSeqProg, pSP)
' 322 struct seqProgram *pSeqProg;
' 323 SPROG *pSP;
' 324 {
' 325 SSCB *pSS;
' 326 STATE *pState;
' 327 int nss, nstates;
' 328 struct seqSS *pSeqSS;
' 329 struct seqState *pSeqState;
' 330
' 331
' 332 /* Allocate space for the SSCB structures */
' 333 pSP->pSS = pSS = (SSCB *)calloc(pSeqProg->numSS, sizeof(SSCB));
' 334
' 335 /* Copy information for each state set and state */
' 336 pSeqSS = pSeqProg->pSS;
' 337 for (nss = 0; nss < pSeqProg->numSS; nss++, pSS++, pSeqSS++)
' 338 {
' 339 /* Fill in SSCB */
' 340 pSS->pSSName = pSeqSS->pSSName;
' 341 pSS->numStates = pSeqSS->numStates;
' 342 pSS->errorState = pSeqSS->errorState;
' 343 pSS->currentState = 0; /* initial state */
' 344 pSS->nextState = 0;
' 345 pSS->prevState = 0;
' 346 pSS->threadId = 0;
' 347 /* Initialize to start time rather than zero time! */
' 348 pvTimeGetCurrentDouble(&pSS->timeEntered);
' 349 pSS->sprog = pSP;
' 350 #ifdef DEBUG
2001-03-19 Marty 351 printf("init_sscb: SS Name=%s, num States=%d, pSS=%p\n",
2000-04-04 William 352 pSS->pSSName, pSS->numStates, pSS);
03:23:15 ' 353 #endif /*DEBUG*/
2003-10-06 Marty 354 pSS->allFirstConnectAndMonitorSemId = epicsEventMustCreate(epicsEventEmpty);
2000-04-04 William 355 /* Create a binary semaphore for synchronizing events in a SS */
2003-10-06 Marty 356 pSS->syncSemId = epicsEventMustCreate(epicsEventEmpty);
2000-04-04 William 357
03:23:15 ' 358 /* Create binary semaphores for synchronous pvGet() and
' 359 pvPut() */
2001-02-16 Marty 360 pSS->getSemId = epicsEventMustCreate(epicsEventFull);
18:45:42 ' 361 pSS->putSemId = epicsEventMustCreate(epicsEventFull);
2000-04-04 William 362
03:23:15 ' 363 /* Create binary semaphores for thread death */
2001-02-16 Marty 364 pSS->death1SemId = epicsEventMustCreate(epicsEventEmpty);
18:45:42 ' 365 pSS->death2SemId = epicsEventMustCreate(epicsEventEmpty);
' 366 pSS->death3SemId = epicsEventMustCreate(epicsEventEmpty);
' 367 pSS->death4SemId = epicsEventMustCreate(epicsEventEmpty);
2000-04-04 William 368
03:23:15 ' 369 /* Allocate & fill in state blocks */
' 370 pSS->pStates = pState = (STATE *)calloc(pSS->numStates,
' 371 sizeof(STATE));
' 372
' 373 pSeqState = pSeqSS->pStates;
' 374 for (nstates = 0; nstates < pSeqSS->numStates;
' 375 nstates++, pState++, pSeqState++)
' 376 {
' 377 pState->pStateName = pSeqState->pStateName;
' 378 pState->actionFunc = (ACTION_FUNC)pSeqState->actionFunc;
' 379 pState->eventFunc = (EVENT_FUNC)pSeqState->eventFunc;
' 380 pState->delayFunc = (DELAY_FUNC)pSeqState->delayFunc;
' 381 pState->entryFunc = (ENTRY_FUNC)pSeqState->entryFunc;
' 382 pState->exitFunc = (EXIT_FUNC)pSeqState->exitFunc;
' 383 pState->pEventMask = pSeqState->pEventMask;
' 384 pState->options = pSeqState->options;
' 385 #ifdef DEBUG
2001-03-19 Marty 386 printf("init_sscb: State Name=%s, Event Mask=%p\n",
2000-04-04 William 387 pState->pStateName, *pState->pEventMask);
03:23:15 ' 388 #endif /*DEBUG*/
' 389 }
' 390 }
' 391
' 392 #ifdef DEBUG
2001-03-19 Marty 393 printf("init_sscb: numSS=%d\n", pSP->numSS);
2000-04-04 William 394 #endif /*DEBUG*/
03:23:15 ' 395 return;
' 396 }
' 397
' 398 /*
' 399 * init_chan--Build the database channel structures.
' 400 * Note: Actual PV name is not filled in here. */
' 401 LOCAL void init_chan(pSeqProg, pSP)
' 402 struct seqProgram *pSeqProg;
' 403 SPROG *pSP;
' 404 {
' 405 int nchan;
' 406 CHAN *pDB;
' 407 struct seqChan *pSeqChan;
' 408
' 409 /* Allocate space for the CHAN structures */
' 410 pSP->pChan = (CHAN *)calloc(pSP->numChans, sizeof(CHAN));
' 411 pDB = pSP->pChan;
' 412
' 413 pSeqChan = pSeqProg->pChan;
' 414 for (nchan = 0; nchan < pSP->numChans; nchan++, pDB++, pSeqChan++)
' 415 {
' 416 #ifdef DEBUG
2001-03-19 Marty 417 printf("init_chan: pDB=%p\n", pDB);
2000-04-04 William 418 #endif /*DEBUG*/
03:23:15 ' 419 pDB->sprog = pSP;
' 420 pDB->sset = NULL; /* set temporarily during get/put */
' 421 pDB->dbAsName = pSeqChan->dbAsName;
' 422 pDB->pVarName = pSeqChan->pVarName;
' 423 pDB->pVarType = pSeqChan->pVarType;
' 424 pDB->pVar = pSeqChan->pVar; /* offset for +r option */
' 425 pDB->count = pSeqChan->count;
' 426 pDB->efId = pSeqChan->efId;
' 427 pDB->monFlag = pSeqChan->monFlag;
' 428 pDB->eventNum = pSeqChan->eventNum;
' 429 pDB->queued = pSeqChan->queued;
' 430 pDB->maxQueueSize = pSeqChan->maxQueueSize ?
' 431 pSeqChan->maxQueueSize : MAX_QUEUE_SIZE;
' 432 pDB->queueIndex = pSeqChan->queueIndex;
' 433 pDB->assigned = 0;
' 434
' 435 /* Latest error message (dynamically allocated) */
' 436 pDB->message = NULL;
' 437
' 438 /* Fill in get/put db types, element size, & access offset */
' 439 selectDBtype(pSeqChan->pVarType, &pDB->getType,
' 440 &pDB->putType, &pDB->size, &pDB->dbOffset);
' 441
' 442 /* Reentrant option: Convert offset to addr of the user var. */
' 443 if ((pSP->options & OPT_REENT) != 0)
2004-01-15 Marty 444 pDB->pVar += (ptrdiff_t)pSP->pVar;
2000-04-04 William 445 #ifdef DEBUG
2001-03-19 Marty 446 printf(" Assigned Name=%s, VarName=%s, VarType=%s, "
2000-04-04 William 447 "count=%d\n", pDB->dbAsName, pDB->pVarName,
03:23:15 ' 448 pDB->pVarType, pDB->count);
2001-03-19 Marty 449 printf(" size=%d, dbOffset=%d\n", pDB->size,
2000-04-04 William 450 pDB->dbOffset);
2001-03-19 Marty 451 printf(" efId=%d, monFlag=%d, eventNum=%d\n",
2000-04-04 William 452 pDB->efId, pDB->monFlag, pDB->eventNum);
03:23:15 ' 453 #endif /*DEBUG*/
' 454 }
' 455 }
' 456
' 457 /*
' 458 * init_mac - initialize the macro table.
' 459 */
' 460 LOCAL void init_mac(pSP)
' 461 SPROG *pSP;
' 462 {
' 463 int i;
' 464 MACRO *pMac;
' 465
' 466 pSP->pMacros = pMac = (MACRO *)calloc(MAX_MACROS, sizeof (MACRO));
' 467 #ifdef DEBUG
2001-03-19 Marty 468 printf("init_mac: pMac=%p\n", pMac);
2000-04-04 William 469 #endif /*DEBUG*/
03:23:15 ' 470
' 471 for (i = 0 ; i < MAX_MACROS; i++, pMac++)
' 472 {
' 473 pMac->pName = NULL;
' 474 pMac->pValue = NULL;
' 475 }
' 476 }
' 477 /*
' 478 * Evaluate channel names by macro substitution.
' 479 */
' 480 #define MACRO_STR_LEN (MAX_STRING_SIZE+1)
' 481 LOCAL void seqChanNameEval(pSP)
' 482 SPROG *pSP;
' 483 {
' 484 CHAN *pDB;
' 485 int i;
' 486
' 487 pDB = pSP->pChan;
' 488 for (i = 0; i < pSP->numChans; i++, pDB++)
' 489 {
' 490 pDB->dbName = calloc(1, MACRO_STR_LEN);
' 491 seqMacEval(pDB->dbAsName, pDB->dbName, MACRO_STR_LEN, pSP->pMacros);
' 492 #ifdef DEBUG
2001-03-19 Marty 493 printf("seqChanNameEval: \"%s\" evaluated to \"%s\"\n",
2000-04-04 William 494 pDB->dbAsName, pDB->dbName);
03:23:15 ' 495 #endif /*DEBUG*/
' 496 }
' 497 }
' 498 /*
' 499 * selectDBtype -- returns types for DB put/get, element size, and db access
' 500 * offset based on user variable type.
' 501 * Mapping is determined by the following typeMap[] array.
' 502 * pvTypeTIME_* types for gets/monitors return status and time stamp.
' 503 */
' 504 LOCAL struct typeMap {
' 505 char *pTypeStr;
' 506 short putType;
' 507 short getType;
' 508 short size;
' 509 short offset;
' 510 } typeMap[] = {
' 511 {
' 512 "char", pvTypeCHAR, pvTypeTIME_CHAR,
2011-04-06 ben.franksen 513 sizeof (pvChar), OFFSET(pvTimeChar, value[0])
2000-04-04 William 514 },
03:23:15 ' 515
' 516 {
' 517 "short", pvTypeSHORT, pvTypeTIME_SHORT,
2011-04-06 ben.franksen 518 sizeof (pvShort), OFFSET(pvTimeShort, value[0])
2000-04-04 William 519 },
03:23:15 ' 520
' 521 {
' 522 "int", pvTypeLONG, pvTypeTIME_LONG,
2011-04-06 ben.franksen 523 sizeof (pvLong), OFFSET(pvTimeLong, value[0])
2000-04-04 William 524 },
03:23:15 ' 525
' 526 {
' 527 "long", pvTypeLONG, pvTypeTIME_LONG,
2011-04-06 ben.franksen 528 sizeof (pvLong), OFFSET(pvTimeLong, value[0])
2000-04-04 William 529 },
03:23:15 ' 530
' 531 {
' 532 "unsigned char", pvTypeCHAR, pvTypeTIME_CHAR,
2011-04-06 ben.franksen 533 sizeof (pvChar), OFFSET(pvTimeChar, value[0])
2000-04-04 William 534 },
03:23:15 ' 535
' 536 {
' 537 "unsigned short",pvTypeSHORT, pvTypeTIME_SHORT,
2011-04-06 ben.franksen 538 sizeof (pvShort), OFFSET(pvTimeShort, value[0])
2000-04-04 William 539 },
03:23:15 ' 540
' 541 {
' 542 "unsigned int", pvTypeLONG, pvTypeTIME_LONG,
2011-04-06 ben.franksen 543 sizeof (pvLong), OFFSET(pvTimeLong, value[0])
2000-04-04 William 544 },
03:23:15 ' 545
' 546 {
' 547 "unsigned long", pvTypeLONG, pvTypeTIME_LONG,
2011-04-06 ben.franksen 548 sizeof (pvLong), OFFSET(pvTimeLong, value[0])
2000-04-04 William 549 },
03:23:15 ' 550
' 551 {
' 552 "float", pvTypeFLOAT, pvTypeTIME_FLOAT,
2011-04-06 ben.franksen 553 sizeof (pvFloat), OFFSET(pvTimeFloat, value[0])
2000-04-04 William 554 },
03:23:15 ' 555
' 556 {
' 557 "double", pvTypeDOUBLE, pvTypeTIME_DOUBLE,
2011-04-06 ben.franksen 558 sizeof (pvDouble), OFFSET(pvTimeDouble, value[0])
2000-04-04 William 559 },
03:23:15 ' 560
' 561 {
' 562 "string", pvTypeSTRING, pvTypeTIME_STRING,
' 563 MAX_STRING_SIZE, OFFSET(pvTimeString, value[0])
' 564 },
' 565
' 566 {
' 567 0, 0, 0, 0, 0
' 568 }
' 569 };
' 570
' 571 LOCAL void selectDBtype(pUserType, pGetType, pPutType, pSize, pOffset)
' 572 char *pUserType;
' 573 short *pGetType, *pPutType, *pSize, *pOffset;
' 574 {
' 575 struct typeMap *pMap;
' 576
' 577 for (pMap = &typeMap[0]; *pMap->pTypeStr != 0; pMap++)
' 578 {
' 579 if (strcmp(pUserType, pMap->pTypeStr) == 0)
' 580 {
' 581 *pGetType = pMap->getType;
' 582 *pPutType = pMap->putType;
' 583 *pSize = pMap->size;
' 584 *pOffset = pMap->offset;
' 585 return;
' 586 }
' 587 }
' 588 *pGetType = *pPutType = *pSize = *pOffset = 0; /* this shouldn't happen */
' 589
' 590 return;
' 591 }
' 592 /*
' 593 * seq_logInit() - Initialize logging.
' 594 * If "logfile" is not specified, then we log to standard output.
' 595 */
' 596 LOCAL void seq_logInit(pSP)
' 597 SPROG *pSP;
' 598 {
' 599 char *pValue;
' 600 FILE *fd;
' 601
' 602 /* Create a logging resource locking semaphore */
2001-02-16 Marty 603 pSP->logSemId = epicsMutexMustCreate();
2000-04-04 William 604 pSP->pLogFile = "";
03:23:15 ' 605
' 606 /* Check for logfile spec. */
' 607 pValue = seqMacValGet(pSP->pMacros, "logfile");
' 608 if (pValue != NULL && strlen(pValue) > 0)
' 609 { /* Create & open a new log file for write only */
' 610 fd = fopen(pValue, "w");
' 611 if (fd == NULL)
' 612 {
' 613 errlogPrintf("Log file open error, file=%s, error=%s\n",
' 614 pSP->pLogFile, strerror(errno));
' 615 }
' 616 else
' 617 {
' 618 errlogPrintf("Log file opened, fd=%d, file=%s\n",
' 619 fileno(fd), pValue);
' 620 pSP->logFd = fd;
' 621 pSP->pLogFile = pValue;
' 622 }
' 623 }
' 624 }
' 625 /*
2000-04-18 W. 626 * seq_logv
2000-04-04 William 627 * Log a message to the console or a file with thread name, date, & time of day.
03:23:15 ' 628 * The format looks like "mythread 12/13/93 10:07:43: Hello world!".
' 629 */
' 630 #define LOG_BFR_SIZE 200
' 631
2000-04-18 W. 632 epicsStatus seq_logv(SPROG *pSP, const char *fmt, va_list args)
2000-04-04 William 633 {
03:23:15 ' 634 int count, status;
2001-02-16 Marty 635 epicsTimeStamp timeStamp;
2000-04-04 William 636 char logBfr[LOG_BFR_SIZE], *eBfr=logBfr+LOG_BFR_SIZE, *pBfr;
2000-04-07 W. 637 FILE *fd = pSP->logFd ? pSP->logFd : stdout;
2000-04-04 William 638 pBfr = logBfr;
03:23:15 ' 639
' 640 /* Enter thread name */
2001-02-16 Marty 641 sprintf(pBfr, "%s ", epicsThreadGetNameSelf() );
2000-04-04 William 642 pBfr += strlen(pBfr);
03:23:15 ' 643
' 644 /* Get time of day */
2001-02-16 Marty 645 epicsTimeGetCurrent(&timeStamp); /* time stamp format */
2000-04-04 William 646
03:23:15 ' 647 /* Convert to text format: "yyyy/mm/dd hh:mm:ss" */
2001-02-16 Marty 648 epicsTimeToStrftime(pBfr, eBfr-pBfr, "%Y/%m/%d %H:%M:%S", &timeStamp);
2000-04-04 William 649 pBfr += strlen(pBfr);
03:23:15 ' 650
' 651 /* Insert ": " */
' 652 *pBfr++ = ':';
' 653 *pBfr++ = ' ';
' 654
' 655 /* Append the user's msg to the buffer */
2000-04-18 W. 656 vsprintf(pBfr, fmt, args);
2000-04-04 William 657 pBfr += strlen(pBfr);
03:23:15 ' 658
' 659 /* Write the msg */
2001-02-16 Marty 660 epicsMutexMustLock(pSP->logSemId);
2000-04-04 William 661 count = pBfr - logBfr + 1;
2000-04-07 W. 662 status = fwrite(logBfr, 1, count, fd);
2001-02-16 Marty 663 epicsMutexUnlock(pSP->logSemId);
2000-04-04 William 664
03:23:15 ' 665 if (status != count)
' 666 {
' 667 errlogPrintf("Log file write error, fd=%d, file=%s, error=%s\n",
' 668 fileno(pSP->logFd), pSP->pLogFile, strerror(errno));
' 669 return ERROR;
' 670 }
' 671
' 672 /* If this is not stdout, flush the buffer */
2000-04-07 W. 673 if (fd != stdout)
2000-04-04 William 674 {
2001-02-16 Marty 675 epicsMutexMustLock(pSP->logSemId);
2000-04-04 William 676 fflush(pSP->logFd);
2001-02-16 Marty 677 epicsMutexUnlock(pSP->logSemId);
2000-04-04 William 678 }
03:23:15 ' 679 return OK;
' 680 }
' 681 /*
' 682 * seq_seqLog() - State program interface to seq_log().
' 683 * Does not require ptr to state program block.
' 684 */
2000-04-18 W. 685 epicsShareFunc long epicsShareAPI seq_seqLog(SS_ID ssId, const char *fmt, ...)
2000-04-04 William 686 {
2001-03-19 Marty 687 SPROG *pSP;
2000-04-18 W. 688 va_list args;
2001-03-19 Marty 689 long rtn;
2000-04-04 William 690
2000-04-18 W. 691 va_start (args, fmt);
2001-03-19 Marty 692 pSP = ((SSCB *)ssId)->sprog;
21:07:52 ' 693 rtn = seq_logv(pSP, fmt, args);
2000-04-18 W. 694 va_end (args);
2001-03-19 Marty 695 return(rtn);
2000-04-04 William 696 }