try to make things work on 64 bit systems
Annotate for file src/seq/seq_ca.c
2000-04-04 William 1 /*
03:23:15 ' 2 seq_ca.c,v 1.2 1995/06/27 15:25:54 wright Exp
' 3
' 4 * DESCRIPTION: Process Variable (was CA) interface for sequencer.
' 5 *
' 6 * Author: Andy Kozubal
' 7 * Date: July, 1991
' 8 *
' 9 * Experimental Physics and Industrial Control System (EPICS)
' 10 *
' 11 * Copyright 1991-1994, the Regents of the University of California,
' 12 * and the University of Chicago Board of Governors.
' 13 *
' 14 * This software was produced under U.S. Government contracts:
' 15 * (W-7405-ENG-36) at the Los Alamos National Laboratory,
' 16 * and (W-31-109-ENG-38) at Argonne National Laboratory.
' 17 *
' 18 * Initial development by:
' 19 * The Controls and Automation Group (AT-8)
' 20 * Ground Test Accelerator
' 21 * Accelerator Technology Division
' 22 * Los Alamos National Laboratory
' 23 *
' 24 * Co-developed with
' 25 * The Controls and Computing Group
' 26 * Accelerator Systems Division
' 27 * Advanced Photon Source
' 28 * Argonne National Laboratory
' 29 *
' 30 * Modification Log:
' 31 * -----------------
' 32 * 03jul91,ajk .
' 33 * 11dec91,ajk Cosmetic changes (comments & names)
' 34 * 13feb92,ajk All seqLog() calls compile only if DEBUG is defined.
' 35 * 28apr92,ajk Implemented new event flag mode.
' 36 * 21may92,ajk Will periodically announce number of connected channels
' 37 * if waiting form some to connect.
' 38 * 17feb93,ajk Implemented code to allow sharing of a single CA task by
' 39 * all state programs. Added seq_disconnect() and ca_import_
' 40 * cancel(). DB name resolution was moved to seq_main.c.
' 41 * 19feb93,ajk Added patched version of VxWorks 5.02b taskVarDelete().
' 42 * 01mar94,ajk Moved "seq_pv*()" functions to seq_if.c.
' 43 * 28mar94,ajk Restructured event& callback handlers to call proc_db_events().
' 44 * 29mar94,ajk Removed getPtrToValue(). Offset is now in db_channel structure.
' 45 * 08apr94,ajk Added support for time stamp.
' 46 * 17jan96,ajk Removed ca_import_cancel(), which is now in channel access lib.
' 47 * 17jan96,ajk Many routines changed to use ANSI-style function headers.
' 48 * 09aug96,wfl Added support for syncQ queued values.
' 49 * 30apr99,wfl Replaced VxWorks task dependencies with OSI.
' 50 * 17may99,wfl Fixed errors in debug output; checked for NULL mask pointer
' 51 * (NULL mask pointer bug had always been present).
' 52 * 07sep99,wfl Supported put completion (c.f. existing get completion);
' 53 * Copied message text (returned via seq_pvMessage());
' 54 * On completion, unconditionally give semaphore.
' 55 * 18feb00,wfl Supported simple types for putCallback (fixed bug...).
' 56 * 29feb00,wfl Converted to new OSI (and errlogPrintf).
' 57 * 31mar00,wfl Checked for NULL value returned on put completion.
' 58 */
' 59
' 60 #include <string.h>
' 61
2000-04-14 Janet 62 #define epicsExportSharedSymbols
2000-04-04 William 63 #include "seq.h"
03:23:15 ' 64
' 65 LOCAL void proc_db_events(pvValue *, pvType, CHAN *, long);
' 66 LOCAL void proc_db_events_queued(pvValue *, CHAN *);
' 67
' 68 /*#define DEBUG*/
' 69
' 70 #ifdef DEBUG
' 71 #undef LOCAL
' 72 #define LOCAL
' 73 #endif /*DEBUG*/
' 74 /*
' 75 * seq_connect() - Connect to all database channels.
' 76 */
2000-04-14 Janet 77 epicsShareFunc long seq_connect(SPROG *pSP)
2000-04-04 William 78 {
03:23:15 ' 79 CHAN *pDB;
' 80 int status, i;
' 81 extern void seq_conn_handler();
' 82
2004-04-30 Marty 83 for (i = 0, pDB = pSP->pChan; i < pSP->numChans; i++, pDB++)
19:41:03 ' 84 {
' 85 if (pDB->dbName == NULL || pDB->dbName[0] == 0)
' 86 continue; /* skip records without pv names */
' 87 pSP->assignCount += 1; /* keep track of number of *assigned* channels */
' 88 if (pDB->monFlag) pSP->numMonitoredChans++;/*do it before pvVarCreate*/
' 89 }
2000-04-04 William 90 /*
03:23:15 ' 91 * For each channel: connect to db & issue monitor (if monFlag is TRUE).
' 92 */
' 93 for (i = 0, pDB = pSP->pChan; i < pSP->numChans; i++, pDB++)
' 94 {
' 95 if (pDB->dbName == NULL || pDB->dbName[0] == 0)
' 96 continue; /* skip records without pv names */
' 97 #ifdef DEBUG
' 98 errlogPrintf("seq_connect: connect %s to %s\n", pDB->pVarName,
' 99 pDB->dbName);
' 100 #endif /*DEBUG*/
' 101 /* Connect to it */
' 102 status = pvVarCreate(
' 103 pvSys, /* PV system context */
' 104 pDB->dbName, /* PV name */
' 105 seq_conn_handler, /* connection handler routine */
' 106 pDB, /* private data is CHAN struc */
' 107 0, /* debug level (inherited) */
' 108 &pDB->pvid ); /* ptr to PV id */
' 109 if (status != pvStatOK)
' 110 {
' 111 errlogPrintf("seq_connect: pvVarCreate() %s failure: "
' 112 "%s\n", pDB->dbName, pvVarGetMess(pDB->pvid));
' 113 return status;
' 114 }
2004-04-30 Marty 115 pDB->assigned = TRUE;
2000-04-04 William 116 /* Clear monitor indicator */
03:23:15 ' 117 pDB->monitored = FALSE;
' 118
' 119 /*
' 120 * Issue monitor request
' 121 */
' 122 if (pDB->monFlag)
' 123 {
' 124 seq_pvMonitor((SS_ID)pSP->pSS, i);
' 125 }
' 126 }
' 127 pvSysFlush(pvSys);
' 128 return 0;
' 129 }
' 130
' 131 /*
' 132 * Event completion type (extra argument passed to proc_db_events().
' 133 */
' 134 #define GET_COMPLETE 0
' 135 #define PUT_COMPLETE 1
' 136 #define MON_COMPLETE 2
' 137
' 138 /*
' 139 * seq_get_handler() - Sequencer callback handler.
' 140 * Called when a "get" completes.
' 141 */
2000-04-14 Janet 142 epicsShareFunc void seq_get_handler(void *var, pvType type, int count, pvValue *pValue,
2000-04-04 William 143 void *arg)
03:23:15 ' 144 {
' 145 /* Process event handling in each state set */
' 146 proc_db_events(pValue, type, (CHAN *)arg, GET_COMPLETE);
' 147 }
' 148
' 149 /*
' 150 * seq_put_handler() - Sequencer callback handler.
' 151 * Called when a "put" completes.
' 152 */
2000-04-14 Janet 153 epicsShareFunc void seq_put_handler(void *var, pvType type, int count, pvValue *pValue,
2000-04-04 William 154 void *arg)
03:23:15 ' 155 {
' 156 /* Process event handling in each state set */
' 157 proc_db_events(pValue, type, (CHAN *)arg, PUT_COMPLETE);
' 158 }
' 159
' 160 /*
' 161 * seq_mon_handler() - PV events (monitors) come here.
' 162 */
2000-04-14 Janet 163 epicsShareFunc void seq_mon_handler(void *var, pvType type, int count, pvValue *pValue,
2000-04-04 William 164 void *arg)
03:23:15 ' 165 {
2003-09-24 Marty 166 CHAN *pCHAN = (CHAN *)arg;
18:31:43 ' 167 SPROG *pSP = pCHAN->sprog;
' 168
2003-10-06 Marty 169 /* Process event handling in each state set */
15:53:11 ' 170 proc_db_events(pValue, type, pCHAN, MON_COMPLETE);
2003-09-24 Marty 171 if(!pCHAN->gotFirstMonitor) {
18:31:43 ' 172 pCHAN->gotFirstMonitor = 1;
' 173 pSP->firstMonitorCount++;
2003-10-06 Marty 174 if((pSP->firstMonitorCount==pSP->numMonitoredChans)
15:53:11 ' 175 && (pSP->firstConnectCount==pSP->assignCount)) {
' 176 SSCB *pSS;
' 177 int i;
' 178 for(i=0, pSS=pSP->pSS; i<pSP->numSS; i++,pSS++) {
' 179 epicsEventSignal(pSS->allFirstConnectAndMonitorSemId);
' 180 }
' 181 }
2003-09-24 Marty 182 }
2000-04-04 William 183 }
03:23:15 ' 184
' 185 /* Common code for completion and monitor handling */
' 186 LOCAL void proc_db_events(pvValue *pValue, pvType type, CHAN *pDB,
' 187 long complete_type)
' 188 {
' 189 SPROG *pSP;
' 190 void *pVal;
' 191
' 192 #ifdef DEBUG
' 193 errlogPrintf("proc_db_events: var=%s, pv=%s, type=%s\n", pDB->pVarName,
' 194 pDB->dbName, complete_type==0?"get":complete_type==1?"put":"mon");
' 195 #endif /*DEBUG*/
' 196
' 197 /* If monitor on var queued via syncQ, branch to alternative routine */
' 198 if (pDB->queued && complete_type == MON_COMPLETE)
' 199 {
' 200 proc_db_events_queued(pValue, pDB);
' 201 return;
' 202 }
' 203
' 204 /* Copy value returned into user variable (can get NULL value pointer
' 205 for put completion only) */
' 206 if (pValue == NULL)
' 207 ;
' 208 else if (PV_SIMPLE(type))
' 209 {
' 210 pVal = (void *)pValue; /* ptr to data */
' 211 memcpy(pDB->pVar, pVal, pDB->size * pDB->dbCount);
' 212 }
' 213 else
' 214 {
2011-04-06 ben.franksen 215 pVal = (void *)((char *)pValue + pDB->dbOffset); /* ptr to data */
2000-04-04 William 216 memcpy(pDB->pVar, pVal, pDB->size * pDB->dbCount);
03:23:15 ' 217 }
' 218
' 219 /* Copy status, severity and time stamp (leave unchanged if absent) */
' 220 if (pValue != NULL && !PV_SIMPLE(type))
' 221 {
' 222 pDB->status = (short) pValue->timeStringVal.status;
' 223 pDB->severity = (short) pValue->timeStringVal.severity;
' 224 pDB->timeStamp = pValue->timeStringVal.stamp;
' 225 }
' 226
' 227 /* Copy error message (only when severity indicates error) */
' 228 if (pDB->severity != pvSevrNONE)
' 229 {
2005-07-25 Andrew 230 char *pmsg = pvVarGetMess(pDB->pvid);
23:28:49 ' 231 if (!pmsg) pmsg = "unknown";
' 232 pDB->message = Strdcpy(pDB->message, pmsg);
2000-04-04 William 233 }
03:23:15 ' 234
' 235 /* Get ptr to the state program that owns this db entry */
' 236 pSP = pDB->sprog;
' 237
' 238 /* Indicate completed pvGet() or pvPut() */
' 239 switch (complete_type)
' 240 {
' 241 case GET_COMPLETE:
' 242 pDB->getComplete = TRUE;
' 243 break;
' 244 case PUT_COMPLETE:
' 245 pDB->putComplete = TRUE;
' 246 break;
' 247 default:
' 248 break;
' 249 }
' 250
' 251 /* Wake up each state set that uses this channel in an event */
' 252 seqWakeup(pSP, pDB->eventNum);
' 253
' 254 /* If there's an event flag associated with this channel, set it */
' 255 if (pDB->efId > 0)
' 256 seq_efSet((SS_ID)pSP->pSS, pDB->efId);
' 257
' 258 /* Give semaphore for completed synchronous pvGet() and pvPut() */
' 259 switch (complete_type)
' 260 {
' 261 case GET_COMPLETE:
' 262 if (pDB->sset != NULL)
2001-02-16 Marty 263 epicsEventSignal(pDB->sset->getSemId);
2000-04-04 William 264 break;
03:23:15 ' 265 case PUT_COMPLETE:
' 266 if (pDB->sset != NULL)
2001-02-16 Marty 267 epicsEventSignal(pDB->sset->putSemId);
2000-04-04 William 268 break;
03:23:15 ' 269 default:
' 270 break;
' 271 }
' 272
' 273 return;
' 274 }
' 275 /* Common code for event and callback handling (queuing version) */
' 276 LOCAL void proc_db_events_queued(pvValue *pValue, CHAN *pDB)
' 277 {
' 278 QENTRY *pEntry;
' 279 SPROG *pSP;
' 280 int count;
' 281
' 282 /* Get ptr to the state program that owns this db entry */
' 283 pSP = pDB->sprog;
' 284
' 285 /* Determine number of items currently on the queue */
' 286 count = ellCount(&pSP->pQueues[pDB->queueIndex]);
' 287
' 288 #ifdef DEBUG
' 289 errlogPrintf("proc_db_events_queued: var=%s, pv=%s, count(max)=%d(%d), "
' 290 "index=%d\n", pDB->pVarName, pDB->dbName, count,
' 291 pDB->maxQueueSize, pDB->queueIndex);
' 292 #endif /*DEBUG*/
' 293
' 294 /* Allocate queue entry (re-use last one if queue has reached its
' 295 maximum size) */
' 296 if ( count < pDB->maxQueueSize )
' 297 {
' 298 pEntry = (QENTRY *) calloc(sizeof(QENTRY), 1);
' 299 if (pEntry == NULL)
' 300 {
' 301 errlogPrintf("proc_db_events_queued: %s queue memory "
2004-03-03 W. 302 "allocation failure\n", pDB->pVarName);
2000-04-04 William 303 return;
03:23:15 ' 304 }
' 305 ellAdd(&pSP->pQueues[pDB->queueIndex], (ELLNODE *) pEntry);
' 306 }
' 307 else
' 308 {
' 309 pEntry = (QENTRY *) ellLast(&pSP->pQueues[pDB->queueIndex]);
' 310 if (pEntry == NULL)
' 311 {
' 312 errlogPrintf("proc_db_events_queued: %s queue "
' 313 "inconsistent failure\n", pDB->pVarName);
' 314 return;
' 315 }
' 316 }
' 317
' 318 /* Copy channel id, value and associated information into queue
' 319 entry (NB, currently only copy _first_ value for arrays) */
' 320 pEntry->pDB = pDB;
' 321 memcpy((char *)&pEntry->value, (char *)pValue, sizeof(pEntry->value));
' 322
' 323 /* Set the event flag associated with this channel */
' 324 #ifdef DEBUG
' 325 errlogPrintf("setting event flag %d\n", pDB->efId);
' 326 #endif /*DEBUG*/
' 327 seq_efSet((SS_ID)pSP->pSS, pDB->efId);
' 328
' 329 return;
' 330 }
' 331
' 332 /* Disconnect all database channels */
' 333 /*#define DEBUG_DISCONNECT*/
' 334
2000-04-14 Janet 335 epicsShareFunc long seq_disconnect(SPROG *pSP)
2000-04-04 William 336 {
03:23:15 ' 337 CHAN *pDB;
' 338 int i;
' 339 SPROG *pMySP; /* will be NULL if this is not a sequencer thread */
' 340
' 341 /* Did we already disconnect? */
' 342 if (pSP->connCount < 0)
' 343 return 0;
' 344
' 345 /* Attach to PV context of pvSys creator (auxiliary thread) */
2001-02-16 Marty 346 pMySP = seqFindProg(epicsThreadGetIdSelf());
2000-04-04 William 347 if (pMySP == NULL)
03:23:15 ' 348 {
' 349 #ifdef DEBUG_DISCONNECT
' 350 errlogPrintf("seq_disconnect: pvSysAttach(pvSys)\n");
' 351 #endif /*DEBUG_DISCONNECT*/
' 352 /* not a sequencer thread */
' 353 pvSysAttach(pvSys);
' 354 }
' 355
' 356 pDB = pSP->pChan;
' 357 #ifdef DEBUG_DISCONNECT
2001-03-19 Marty 358 errlogPrintf("seq_disconnect: pSP = %p, pDB = %p\n", pSP, pDB);
2000-04-04 William 359 #endif /*DEBUG_DISCONNECT*/
03:23:15 ' 360
' 361 for (i = 0; i < pSP->numChans; i++, pDB++)
' 362 {
' 363 pvStat status;
' 364
' 365 if (!pDB->assigned)
' 366 continue;
' 367 #ifdef DEBUG_DISCONNECT
' 368 errlogPrintf("seq_disconnect: disconnect %s from %s\n",
' 369 pDB->pVarName, pDB->dbName);
' 370 #endif /*DEBUG_DISCONNECT*/
' 371 /* Disconnect this PV */
' 372 status = pvVarDestroy(pDB->pvid);
' 373 if (status != pvStatOK)
' 374 errlogPrintf("seq_disconnect: pvVarDestroy() %s failure: "
' 375 "%s\n", pDB->dbName, pvVarGetMess(pDB->pvid));
' 376
' 377 /* Clear monitor & connect indicators */
' 378 pDB->monitored = FALSE;
' 379 pDB->connected = FALSE;
' 380 }
' 381
' 382 pSP->connCount = -1; /* flag to indicate all disconnected */
' 383
' 384 pvSysFlush(pvSys);
' 385
' 386 return 0;
' 387 }
' 388
' 389 /*
' 390 * seq_conn_handler() - Sequencer connection handler.
' 391 * Called each time a connection is established or broken.
' 392 */
' 393 void seq_conn_handler(void *var,int connected)
' 394 {
' 395 CHAN *pDB;
' 396 SPROG *pSP;
' 397
' 398 /* Private data is db ptr (specified at pvVarCreate()) */
' 399 pDB = (CHAN *)pvVarGetPrivate(var);
' 400
' 401 /* State program that owns this db entry */
' 402 pSP = pDB->sprog;
' 403
' 404 /* If PV not connected */
' 405 if (!connected)
' 406 {
' 407 #ifdef DEBUG
' 408 errlogPrintf("%s disconnected from %s\n", pDB->pVarName,
' 409 pDB->dbName);
' 410 #endif /*DEBUG*/
2003-09-09 Marty 411 if(pDB->connected) {
13:27:23 ' 412 pDB->connected = FALSE;
' 413 pSP->connCount--;
' 414 pDB->monitored = FALSE;
' 415 } else {
' 416 printf("%s disconnected but already disconnected %s\n",
' 417 pDB->pVarName,pDB->dbName);
' 418 }
2000-04-04 William 419 }
03:23:15 ' 420 else /* PV connected */
' 421 {
' 422 #ifdef DEBUG
' 423 errlogPrintf("%s connected to %s\n", pDB->pVarName,pDB->dbName);
' 424 #endif /*DEBUG*/
2003-09-09 Marty 425 if(!pDB->connected) {
13:27:23 ' 426 pDB->connected = TRUE;
' 427 pSP->connCount++;
' 428 if (pDB->monFlag)
' 429 pDB->monitored = TRUE;
' 430 pDB->dbCount = pvVarGetCount(var);
' 431 if (pDB->dbCount > pDB->count)
' 432 pDB->dbCount = pDB->count;
' 433 } else {
' 434 printf("%s connected but already connected %s\n",
' 435 pDB->pVarName,pDB->dbName);
' 436 }
2003-10-06 Marty 437 if(!pDB->gotFirstConnect) {
15:53:11 ' 438 pDB->gotFirstConnect = 1;
' 439 pSP->firstConnectCount++;
' 440 if((pSP->firstMonitorCount==pSP->numMonitoredChans)
' 441 && (pSP->firstConnectCount==pSP->assignCount)) {
' 442 SSCB *pSS;
' 443 int i;
' 444 for(i=0, pSS=pSP->pSS; i<pSP->numSS; i++,pSS++) {
' 445 epicsEventSignal(pSS->allFirstConnectAndMonitorSemId);
' 446 }
' 447 }
' 448 }
2000-04-04 William 449 }
03:23:15 ' 450
' 451 /* Wake up each state set that is waiting for event processing */
' 452 seqWakeup(pSP, 0);
' 453
' 454 return;
' 455 }
' 456
' 457 /*
' 458 * seqWakeup() -- wake up each state set that is waiting on this event
' 459 * based on the current event mask. EventNum = 0 means wake all state sets.
' 460 */
' 461 void seqWakeup(SPROG *pSP, long eventNum)
' 462 {
' 463 int nss;
' 464 SSCB *pSS;
' 465
' 466 /* Check event number against mask for all state sets: */
' 467 for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
' 468 {
' 469 /* If event bit in mask is set, wake that state set */
' 470 if ( (eventNum == 0) ||
' 471 ( pSS->pMask != NULL && bitTest(pSS->pMask, eventNum) ) )
' 472 {
2001-02-16 Marty 473 epicsEventSignal(pSS->syncSemId); /* wake up ss thread */
2000-04-04 William 474 }
03:23:15 ' 475
' 476 }
' 477 return;
' 478 }