static void interruptCallbackEnumBo(void *drvPvt, asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements) { devPvt *pPvt = (devPvt *)drvPvt; boRecord *pr = (boRecord *)pPvt->pr; if (!interruptAccept) return; dbScanLock((dbCommon*)pr); setEnums((char*)&pr->znam, NULL, &pr->zsv, strings, NULL, severities, nElements, 2); db_post_events(pr, &pr->val, DBE_PROPERTY); dbScanUnlock((dbCommon*)pr); }
static void interruptCallbackEnumMbbo(void *drvPvt, asynUser *pasynUser, char *strings[], int values[], int severities[], size_t nElements) { devInt32Pvt *pPvt = (devInt32Pvt *)drvPvt; mbboRecord *pr = (mbboRecord *)pPvt->pr; if (!interruptAccept) return; dbScanLock((dbCommon*)pr); setEnums((char*)&pr->zrst, (int*)&pr->zrvl, &pr->zrsv, strings, values, severities, nElements, MAX_ENUM_STATES); db_post_events(pr, &pr->val, DBE_PROPERTY); dbScanUnlock((dbCommon*)pr); }
/* Callback for bo, see ao_callback comments */ static void check_bo_callback(void *arg) { boRecord *rec = (boRecord *) arg; struct rset *rset= (struct rset *)(rec->rset); DevicePrivate *pvt = (DevicePrivate *)rec->dpvt; unsigned long rval; eip_bool process = false; /* We are about the check and even set val, & rval -> lock */ dbScanLock((dbCommon *)rec); if (rec->pact) { (*rset->process) ((dbCommon *)rec); dbScanUnlock((dbCommon *)rec); return; } /* Check if record's (R)VAL is current */ if (!check_data((dbCommon *) rec)) { (*rset->process) ((dbCommon *)rec); dbScanUnlock((dbCommon *)rec); return; } if (get_bits((dbCommon *)rec, 1, &rval) && (rec->udf || rec->sevr == INVALID_ALARM || rec->rval != rval)) { if (rec->tpro) printf("'%s': got %lu from driver\n", rec->name, rval); if (!rec->udf && pvt->special & SPCO_FORCE) { if (rec->tpro) printf("'%s': will re-write record's value %u\n", rec->name, (unsigned int)rec->val); } else { /* back-convert rval into val */ rec->rval = rval; rec->val = (rec->rval==0) ? 0 : 1; rec->udf = false; if (rec->tpro) printf("'%s': updated record to tag, val = %u\n", rec->name, (unsigned int)rec->val); } process = true; } dbScanUnlock((dbCommon *)rec); /* Does record need processing and is not periodic? */ if (process && rec->scan < SCAN_1ST_PERIODIC) scanOnce(rec); }
/* ---------------------------------------------------------------------- */ void myCallback_devAiAsyncGpib(CALLBACK *p_callback) { struct dbCommon *p_record; struct rset *p_rset; dsetLog(3, __FILE__ "[%d] -> %s \n", __LINE__, __func__ ); callbackGetUser(p_record,p_callback); p_rset=(struct rset *)(p_record->rset); dbScanLock(p_record); (*p_rset->process)(p_record); dbScanUnlock(p_record); dsetLog(3, __FILE__ "[%d] <- %s \n", __LINE__, __func__ ); }
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { epicsTimeStamp now; epicsTimeGetCurrent(&now); /* If string or array, must make a copy (to ensure coherence between time and data) */ if (pfl->type == dbfl_type_rec) { dbScanLock(dbChannelRecord(chan)); dbChannelMakeArrayCopy(pvt, pfl, chan); dbScanUnlock(dbChannelRecord(chan)); } pfl->time = now; return pfl; }
static void checkLinksCallback(CALLBACK *arg) { calcoutRecord *prec; rpvtStruct *prpvt; callbackGetUser(prec, arg); prpvt = prec->rpvt; dbScanLock((dbCommon *)prec); prpvt->cbScheduled = 0; checkLinks(prec); dbScanUnlock((dbCommon *)prec); }
static void myCallback_devAiAsyncGpib(CALLBACK *pcallback) { struct dbCommon *precord; struct rset *prset; dsetLog(3,__FILE__ "[%d] -> %s \n", __LINE__, __func__ ); callbackGetUser(precord,pcallback);/* Get record attached to callback */ prset=(struct rset *)(precord->rset);/* get deviceRecord->rset */ dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); dsetLog(3,__FILE__ "[%d] <- %s \n", __LINE__, __func__ ); return; }
static void myCallback_devMbboAsyncSerial(CALLBACK *p_callback) { struct dbCommon *p_record; struct rset *p_rset; callbackGetUser(p_record,p_callback); dsetLog(3,__FILE__ "[%d] -> %s(%s)\n", __LINE__, __func__, p_record->name ); p_rset=(struct rset *)(p_record->rset); dbScanLock(p_record); (*p_rset->process)(p_record); dbScanUnlock(p_record); dsetLog(3, __FILE__ "[%d] <- %s\n", __LINE__, __func__); return; }
LOCAL void myCallback(CALLBACK *pCallback) { ab1771IXRecord *precord; recordPvt *precordPvt; int callLock; callbackGetUser(precord,pCallback); callLock = interruptAccept; if(callLock)dbScanLock((void *)precord); precordPvt = precord->dpvt; precordPvt->status = (*pabDrv->getStatus)(precordPvt->drvPvt); if(precordPvt->status!=abSuccess) { switch(precordPvt->msgState) { case msgStateWaitInit: case msgStateWaitGet: precordPvt->msgState = msgStateInit; break; default: errlogPrintf("ILLEGAL myCallback state: record %s\n",precord->name); break; } issueError(precord,errAb,0); } else { precordPvt->err = errOK; switch(precordPvt->msgState) { case msgStateWaitInit: precordPvt->msgState = msgStateGet; break;; case msgStateWaitGet: setValMsg(precord,0); msgCompleteGet(precord); issueAsynCallback(precord); break;; default: errlogPrintf("ILLEGAL myCallback state: record %s\n",precord->name); break; } if(precordPvt->err == errOK) switch(precordPvt->msgState) { case msgStateInit: msgInit(precord); break; case msgStateGet: msgGet(precord); break; default: break; } } if(precordPvt->err != errOK) issueAsynCallback(precord); if(callLock)dbScanUnlock((void *)precord); }
static void myCallback(CALLBACK *pcallback) { ASDBCALLBACK *pasdbcallback = (ASDBCALLBACK *)pcallback; subRecord *precord; struct rset *prset; callbackGetUser(precord,pcallback); prset=(struct rset *)(precord->rset); precord->val = 0.0; if(pasdbcallback->status) { recGblSetSevr(precord,READ_ALARM,precord->brsv); recGblRecordError(pasdbcallback->status,precord,"asInit Failed"); } dbScanLock((dbCommon *)precord); (*prset->process)((dbCommon *)precord); dbScanUnlock((dbCommon *)precord); }
static void myCallback(struct callback *pcallback) { struct dbCommon *precord = pcallback->precord; struct rset *prset = (struct rset *)(precord->rset); #ifdef DEBUG1 printf( __FILE__ "[%d] -> %s\n", __LINE__, __func__ ); #endif dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); #ifdef DEBUG1 printf( __FILE__ "[%d] <- %s\n", __LINE__, __func__ ); #endif }
static void controlThreadFunc(void *param) { drvM6802_taskConfig *ptaskConfig = (drvM6802_taskConfig*) param; drvM6802_controlThreadConfig *pcontrolThreadConfig; controlThreadQueueData queueData; while( !ptaskConfig->pcontrolThreadConfig ) epicsThreadSleep(.1); pcontrolThreadConfig = (drvM6802_controlThreadConfig*) ptaskConfig->pcontrolThreadConfig; epicsPrintf("task launching: %s thread for %s task\n",pcontrolThreadConfig->threadName, ptaskConfig->taskName); while(TRUE) { EXECFUNCQUEUE pFunc; execParam *pexecParam; struct dbCommon *precord; struct rset *prset; drvM6802_taskConfig *ptaskConfig; epicsMessageQueueReceive(pcontrolThreadConfig->threadQueueId, (void*) &queueData, sizeof(controlThreadQueueData)); pFunc = queueData.pFunc; pexecParam = &queueData.param; precord = (struct dbCommon*) pexecParam->precord; prset = (struct rset*) precord->rset; ptaskConfig = (drvM6802_taskConfig *) pexecParam->ptaskConfig; if(!pFunc) continue; else pFunc(pexecParam); if(!precord) continue; dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); } return; }
void prng_cb(CALLBACK* cb) { aiRecord* prec; struct prngState* priv; struct rset* prset; epicsInt32 raw; callbackGetUser(prec,cb); prset=(struct rset*)prec->rset; priv=prec->dpvt; raw=rand_r(&priv->seed); dbScanLock((dbCommon*)prec); prec->rval=raw; (*prset->process)(prec); dbScanUnlock((dbCommon*)prec); }
/***************************************************************************** * * Link-group processing function. * * if the input link is not a constant * call dbGetLink() to get the link value * else * get the value from the DOV field * call dbPutLink() to forward the value to destination location * call processNextLink() to schedule the processing of the next link-group * * NOTE: * dbScanLock is NOT held for prec when this function is called!! * ******************************************************************************/ static void processCallback(CALLBACK *arg) { callbackSeq *pcb; seqRecord *prec; double myDouble; callbackGetUser(pcb,arg); prec = pcb->pseqRecord; dbScanLock((struct dbCommon *)prec); if (seqRecDebug > 5) printf("processCallback(%s) processing field index %d\n", prec->name, pcb->index+1); /* Save the old value */ myDouble = pcb->plinks[pcb->index]->dov; dbGetLink(&(pcb->plinks[pcb->index]->dol), DBR_DOUBLE, &(pcb->plinks[pcb->index]->dov),0,0); recGblGetTimeStamp(prec); /* Dump the value to the destination field */ dbPutLink(&(pcb->plinks[pcb->index]->lnk), DBR_DOUBLE, &(pcb->plinks[pcb->index]->dov),1); if (myDouble != pcb->plinks[pcb->index]->dov) { if (seqRecDebug > 0) printf("link %d changed from %f to %f\n", pcb->index, myDouble, pcb->plinks[pcb->index]->dov); db_post_events(prec, &pcb->plinks[pcb->index]->dov, DBE_VALUE|DBE_LOG); } else { if (seqRecDebug > 0) printf("link %d not changed... %f\n", pcb->index, pcb->plinks[pcb->index]->dov); } /* Find the 'next' link-seq that is ready for processing. */ pcb->index++; processNextLink(prec); dbScanUnlock((struct dbCommon *)prec); return; }
static void checkLinksCallback(CALLBACK *pcallback) { acalcoutRecord *pcalc; rpvtStruct *prpvt; callbackGetUser(pcalc, pcallback); prpvt = (rpvtStruct *)pcalc->rpvt; if (!interruptAccept) { /* Can't call dbScanLock yet. Schedule another CALLBACK */ prpvt->wd_id_1_LOCK = 1; /* make sure */ callbackRequestDelayed(&prpvt->checkLinkCb,.5); } else { dbScanLock((struct dbCommon *)pcalc); prpvt->wd_id_1_LOCK = 0; checkLinks(pcalc); dbScanUnlock((struct dbCommon *)pcalc); } }
long epicsShareAPI dbPutField(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest) { long status = 0; long special = paddr->special; dbFldDes *pfldDes = paddr->pfldDes; dbCommon *precord = paddr->precord; short dbfType = paddr->field_type; if (special == SPC_ATTRIBUTE) return S_db_noMod; /*check for putField disabled*/ if (precord->disp && (void *)(&precord->disp) != paddr->pfield) return S_db_putDisabled; if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) return dbPutFieldLink(paddr, dbrType, pbuffer, nRequest); dbScanLock(precord); status = dbPut(paddr, dbrType, pbuffer, nRequest); if (status == 0) { if (paddr->pfield == (void *)&precord->proc || (pfldDes->process_passive && precord->scan == 0 && dbrType < DBR_PUT_ACKT)) { if (precord->pact) { if (precord->tpro) printf("%s: Active %s\n", epicsThreadGetNameSelf(), precord->name); precord->rpro = TRUE; } else { /* indicate that dbPutField called dbProcess */ precord->putf = TRUE; status = dbProcess(precord); } } } dbScanUnlock(precord); return status; }
static void devRoboStrParmCallback(asynUser *pasynUser) { dbCommon *pr = (dbCommon *)pasynUser->userPvt; devStrParmPvt *pPvt = (devStrParmPvt *)pr->dpvt; struct rset *prset = (struct rset *)(pr->rset); pPvt->pasynUser->timeout = pPvt->timeout; switch(pPvt->opType) { case opTypeOutput: pPvt->status = pPvt->pasynOctet->write(pPvt->octetPvt, pasynUser, pPvt->buffer, strlen(pPvt->buffer), &pPvt->nwrite); break; } /* Process the record. This will result in the readXi or writeXi routine being called again, but with pact=1 */ dbScanLock(pr); (*prset->process)(pr); dbScanUnlock(pr); }
static void myCallbackFunc(CALLBACK *arg) { myCallback *pcallback; boRecord *prec; callbackGetUser(pcallback,arg); prec=(boRecord *)pcallback->precord; dbScanLock((struct dbCommon *)prec); if(prec->pact) { if((prec->val==1) && (prec->high>0)){ myCallback *pcallback; pcallback = (myCallback *)(prec->rpvt); callbackSetPriority(prec->prio, &pcallback->callback); callbackRequestDelayed(&pcallback->callback,(double)prec->high); } } else { prec->val = 0; dbProcess((struct dbCommon *)prec); } dbScanUnlock((struct dbCommon *)prec); }
static void onceTask(void *arg) { taskwdInsert(0, NULL, NULL); epicsEventSignal(startStopEvent); while (TRUE) { void *precord; epicsEventMustWait(onceSem); while ((precord = epicsRingPointerPop(onceQ))) { if (precord == &exitOnce) goto shutdown; dbScanLock(precord); dbProcess(precord); dbScanUnlock(precord); } } shutdown: taskwdRemove(0); epicsEventSignal(startStopEvent); }
/*----------------------------------------------------------------------*/ static void myCallback_devAoAsyncGpib( CALLBACK *pcallback) { struct dbCommon *precord; struct rset *prset; callbackGetUser(precord,pcallback); #ifdef DEBUG1 printf( __FILE__ "[%d] -> %s(%s)\n", __LINE__ , __func__, precord->name); #endif prset = (struct rset *)(precord->rset); dbScanLock(precord); (*prset->process)(precord); dbScanUnlock(precord); #ifdef DEBUG1 printf( __FILE__ "[%d] <- %s\n", __LINE__, __func__); #endif }
static void myCallback_devAiAsyncSerial(CALLBACK *p_callback) { struct dbCommon *p_record; struct rset *p_rset; #ifdef DEBUG1 printf(__FILE__ "[%d] -> %s\n", __LINE__, __func__ ); #endif callbackGetUser(p_record,p_callback); p_rset=(struct rset *)(p_record->rset); dbScanLock(p_record); (*p_rset->process)(p_record); dbScanUnlock(p_record); #ifdef DEBUG1 printf( __FILE__ "[%d] <- %s\n", __LINE__, __func__); #endif return; } /* end_of_myCallback */
static void devAiHeidND261Callback(asynUser *pasynUser) { dbCommon *pr = (dbCommon *)pasynUser->userPvt; aiRecord* pai = (aiRecord*) pr; devAiHeidND261Pvt *pPvt = (devAiHeidND261Pvt *)pr->dpvt; struct rset *prset = (struct rset *)(pr->rset); int eomReason; pPvt->pasynUser->timeout = pPvt->timeout; pPvt->status = pPvt->pasynOctet->write(pPvt->octetPvt, pasynUser, pPvt->outbuf, 2, &pPvt->nwrite); pPvt->pasynOctet->setInputEos(pPvt->octetPvt, pasynUser, pPvt->term, pPvt->termlen); pPvt->status = pPvt->pasynOctet->read(pPvt->octetPvt, pasynUser, pPvt->inbuf, pPvt->nchar, &pPvt->nread, &eomReason); pai->udf = 0; dbScanLock(pr); (*prset->process)(pr); dbScanUnlock(pr); }
/* * Process a record without printing it. */ long epicsShareAPI dbprc(char *record_name) { struct dbAddr addr; struct dbCommon *precord; long status; /* * Convert name to address */ status = dbNameToAddr(record_name, &addr); if (status == S_db_notFound) printf(" BKPT> Record %s not found\n", record_name); if (status != 0) return(status); precord = addr.precord; /* lock lockset, process record, unlock lockset */ dbScanLock(precord); status = dbProcess(precord); dbScanUnlock(precord); return(status); }
static void outputCallbackCallback(CALLBACK *pcb) { devPvt *pPvt; static const char *functionName="outputCallbackCallback"; callbackGetUser(pPvt, pcb); { dbCommon *pr = pPvt->pr; dbScanLock(pr); pPvt->newOutputCallbackValue = 1; dbProcess(pr); if (pPvt->newOutputCallbackValue != 0) { /* We called dbProcess but the record did not process, perhaps because PACT was 1 * Need to remove ring buffer element */ asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s %s::%s warning dbProcess did not process record, PACT=%d\n", pr->name, driverName, functionName,pr->pact); getCallbackValue(pPvt); pPvt->newOutputCallbackValue = 0; } dbScanUnlock(pr); } }
static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser, epicsUInt32 value) { devPvt *pPvt = (devPvt *)drvPvt; dbCommon *pr = pPvt->pr; ringBufferElement *rp; static const char *functionName="interruptCallbackOutput"; asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE, "%s %s::%s new value=%u\n", pr->name, driverName, functionName, value); if (!interruptAccept) return; dbScanLock(pr); epicsMutexLock(pPvt->ringBufferLock); rp = &pPvt->ringBuffer[pPvt->ringHead]; rp->value = value; rp->time = pasynUser->timestamp; rp->status = pasynUser->auxStatus; rp->alarmStatus = pasynUser->alarmStatus; rp->alarmSeverity = pasynUser->alarmSeverity; pPvt->ringHead = (pPvt->ringHead==pPvt->ringSize) ? 0 : pPvt->ringHead+1; if (pPvt->ringHead == pPvt->ringTail) { pPvt->ringTail = (pPvt->ringTail==pPvt->ringSize) ? 0 : pPvt->ringTail+1; pPvt->ringBufferOverflows++; } else { /* If PACT is true then this callback was received during asynchronous record processing * Must defer calling callbackRequest until end of record processing */ if (pr->pact) { pPvt->numDeferredOutputCallbacks++; } else { callbackRequest(&pPvt->outputCallback); } } epicsMutexUnlock(pPvt->ringBufferLock); dbScanUnlock(pr); }
static void initConversionTask(void* parm) { int qstatus; void *sub; struct reinitMsg msg; struct cvtRecord *pcvt; long status; while (TRUE) { qstatus = epicsMessageQueueReceive( initConversionQ, (void*)&msg, REINIT_MSG_SIZE); if (qstatus == -1) { nerrmsg("", "msgQReceive failed"); continue; } pcvt = msg.record; status = initConversion(pcvt->name, msg.bdir, msg.tdir, msg.meth, msg.spec, &sub); dbScanLock((struct dbCommon *)pcvt); if (status && pcvt->ista != menuCvtInitStateAgain) { if (pcvt->ista != menuCvtInitStateError) { pcvt->ista = menuCvtInitStateError; pcvt->drty |= DRTY_ISTA; } } else { switch (pcvt->ista) { case menuCvtInitStateInProgress: case menuCvtInitStateError: pcvt->ista = menuCvtInitStateDone; pcvt->drty |= DRTY_ISTA; /* free old csub if it was a csm_function... */ if (pcvt->meth == menuCvtMethod1DTable || pcvt->meth == menuCvtMethod1DTableInverted || pcvt->meth == menuCvtMethod2DTable) { csm_function *csub = (csm_function *)pcvt->csub; if (csub) { /* check because it might have never been created */ csm_free(csub); } } /* ...and write the new values back into the record */ pcvt->meth = msg.meth; pcvt->drty |= DRTY_METH; strncpy(pcvt->spec, msg.spec, SPEC_SIZE); pcvt->drty |= DRTY_SPEC; strncpy(pcvt->bdir, msg.bdir, BDIR_SIZE); pcvt->drty |= DRTY_BDIR; strncpy(pcvt->tdir, msg.tdir, TDIR_SIZE); pcvt->drty |= DRTY_TDIR; pcvt->csub = sub; break; case menuCvtInitStateAgain: if (!status && sub && ( pcvt->meth == menuCvtMethod1DTable || pcvt->meth == menuCvtMethod1DTableInverted || pcvt->meth == menuCvtMethod2DTable)) { csm_free((csm_function *)sub); } /* even if initConversion(...) above failed, we go here */ if (reinitConversion(pcvt)) { /* this is fatal */ pcvt->ista = menuCvtInitStateError; pcvt->drty |= DRTY_ISTA; pcvt->pact = TRUE; break; } pcvt->ista = menuCvtInitStateInProgress; pcvt->drty |= DRTY_ISTA; break; case menuCvtInitStateDone: errmsg("internal error: unexpected " "value <menuCvtInitStateDone> in field ISTA"); pcvt->pact = TRUE; break; default: errmsg("internal error: ISTA is not a member of menuCvtMethod"); pcvt->pact = TRUE; } } checkAlarms(pcvt); monitor(pcvt); dbScanUnlock((struct dbCommon *)pcvt); } }
/* * Remove breakpoint from a record * 1. Convert name to address and check breakpoint mask. * 2. Lock database and take stack semaphore. * 3. Find structure for record's lockset (in stack). * 4. Find and delete record from breakpoint list. * 5. Turn off break point field. * 6. Give up semaphore to "signal" bkptCont task to quit. */ long epicsShareAPI dbd(const char *record_name) { struct dbAddr addr; struct LS_LIST *pnode; struct BP_LIST *pbl; struct dbCommon *precord; long status; /* * Convert name to address */ status = dbNameToAddr(record_name, &addr); if (status == S_db_notFound) printf(" BKPT> Record %s not found\n", record_name); if (status != 0) return(status); precord = addr.precord; if (! precord->bkpt & BKPT_ON_MASK) { printf(" BKPT> No breakpoint set in this record\n"); return(S_db_bkptNotSet); } dbScanLock(precord); epicsMutexMustLock(bkpt_stack_sem); FIND_LOCKSET(precord, pnode); if (pnode == NULL) { /* not found, error ! */ printf(" BKPT> Logic Error in dbd()\n"); precord->bkpt &= BKPT_OFF_MASK; epicsMutexUnlock(bkpt_stack_sem); dbScanUnlock(precord); return(S_db_bkptLogic); } /* * Remove record from breakpoint list */ /* find record in list */ pbl = (struct BP_LIST *) ellFirst(&pnode->bp_list); while (pbl != NULL) { if (pbl->precord == precord) { ellDelete(&pnode->bp_list, (ELLNODE *)pbl); free(pbl); break; } pbl = (struct BP_LIST *) ellNext((ELLNODE *)pbl); } if (pbl == NULL) { printf(" BKPT> Logic Error in dbd()\n"); precord->bkpt &= BKPT_OFF_MASK; epicsMutexUnlock(bkpt_stack_sem); dbScanUnlock(precord); return(S_db_bkptLogic); } /* * Turn off breakpoint field in record */ precord->bkpt &= BKPT_OFF_MASK; /* * If there are no more breakpoints, give up semaphore * to cause the bkptCont task to quit. */ if (ellCount(&pnode->bp_list) == 0) epicsEventSignal(pnode->ex_sem); epicsMutexUnlock(bkpt_stack_sem); dbScanUnlock(precord); return(0); }
/* * Task for continuing record processing * 1. Find lockset in stack for precord. * DO 2-3 while breakpoints exist in the lockset. * 2. Wait on execution semaphore ... * 3. Run through every entrypoint in queue, processing * those that are scheduled. * 4. Free resources for lockset, and exit task. */ static void dbBkptCont(dbCommon *precord) { struct LS_LIST *pnode; struct EP_LIST *pqe = NULL; /* * Reset breakpoint, process record, and * reset bkpt field in record */ epicsMutexMustLock(bkpt_stack_sem); FIND_LOCKSET(precord, pnode); if (pnode == NULL) { printf(" BKPT> Logic error in dbBkptCont()\n"); return; } /* * For every entrypoint scheduled, process. Run process * until there are no more breakpoints remaining in a * lock set. */ do { /* Give up semaphore before waiting to run ... */ epicsMutexUnlock(bkpt_stack_sem); /* Wait to run */ epicsEventMustWait(pnode->ex_sem); /* Bkpt stack must still be stable ! */ epicsMutexMustLock(bkpt_stack_sem); pqe = (struct EP_LIST *) ellFirst(&pnode->ep_queue); /* Run through entrypoint queue */ while (pqe != NULL) { /* check if entrypoint is currently scheduled */ if (pqe->sched) { /* save current entrypoint */ pnode->current_ep = pqe->entrypoint; /* lock the lockset, process record, unlock */ dbScanLock(precord); dbProcess(pqe->entrypoint); dbScanUnlock(precord); /* reset schedule and stepping flag - Do this AFTER processing */ pqe->sched = 0; pnode->step = 0; } pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe); } /* Reset precord. (Since no records are at a breakpoint) */ pnode->precord = NULL; } while (ellCount(&pnode->bp_list) != 0); /* remove node from lockset stack */ ellDelete(&lset_stack, (ELLNODE *)pnode); --lset_stack_count; /* free entrypoint queue */ ellFree(&pnode->ep_queue); /* remove execution semaphore */ epicsEventDestroy(pnode->ex_sem); printf("\n BKPT> End debug of lockset %lu\n-> ", pnode->l_num); /* free list node */ free(pnode); epicsMutexUnlock(bkpt_stack_sem); }
/* * Process breakpoint * Returns a zero if dbProcess() is to execute * record support, a one if dbProcess() is to * skip over record support. See dbProcess(). * * 1. See if there is at least a breakpoint set somewhere * in precord's lockset. If not, return immediately. * 2. Check the disable flag. * 3. Add entry points to the queue for future stepping and * schedule new entrypoints for the continuation task. * 4. Check the pact flag. * 5. Check to see if there is a breakpoint set in a record, and * if so, turn on stepping mode. * 6. If stepping mode is set, stop and report the breakpoint. */ int epicsShareAPI dbBkpt(dbCommon *precord) { struct LS_LIST *pnode; struct EP_LIST *pqe; /* * It is crucial that operations in dbBkpt() execute * in the correct order or certain features in the * breakpoint handler will not work as expected. */ /* * Take and give a semaphore to check for breakpoints * every time a record is processed. Slow. Thank * goodness breakpoint checking is turned off during * normal operation. */ epicsMutexMustLock(bkpt_stack_sem); FIND_LOCKSET(precord, pnode); epicsMutexUnlock(bkpt_stack_sem); if (pnode == NULL) { /* no breakpoints in precord's lockset */ return(0); } /* Check disable flag */ dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0); if (precord->disa == precord->disv) { /* * Do not process breakpoints if the record is disabled, * but allow disable alarms. Alarms will be raised * in dbProcess() because returning 0 allows dbProcess() * to continue. However processing will be prevented * because disa and disv will be examined again in * dbProcess(). Note that checking for pact will occur * before checking for disa and disv in dbProcess(). */ return(0); } /* * Queue entry points for future stepping. The taskid comparison * is used to determine if the source of processing is the * continuation task or an external source. If it is an external * source, queue its execution, but dump out of dbProcess without * calling record support. */ if (pnode->taskid && (epicsThreadGetIdSelf() != pnode->taskid)) { /* CONTINUE TASK CANNOT ENTER HERE */ /* * Add an entry point to queue, if it does * not already exist. */ FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord); if (pqe == NULL) { pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST)); if (pqe == NULL) return(1); pqe->entrypoint = precord; pqe->count = 1; epicsTimeGetCurrent(&pqe->time); pqe->sched = 0; #ifdef BKPT_DIAG printf(" BKPT> Adding entrypoint %s to queue\n", precord->name); #endif /* * Take semaphore, wait on continuation task */ epicsMutexMustLock(bkpt_stack_sem); /* Add entry to queue */ ellAdd(&pnode->ep_queue, (ELLNODE *)pqe); epicsMutexUnlock(bkpt_stack_sem); } else { if (pqe->count < MAX_EP_COUNT) pqe->count++; } /* check pact */ if (! precord->pact) { /* schedule if pact not set */ pqe->sched = 1; /* * Release the semaphore, letting the continuation * task begin execution of the new entrypoint. */ epicsEventSignal(pnode->ex_sem); } return(1); } /* * Don't mess with breakpoints if pact set! Skip * over rest of dbProcess() since we don't want * alarms going off. The pact flag is checked * AFTER entry point queuing so that the record * timing feature will work properly. */ if (precord->pact) return(1); /* Turn on stepping mode if a breakpoint is found */ if (precord->bkpt & BKPT_ON_MASK) { pnode->step = 1; #ifdef BKPT_DIAG printf(" BKPT> Bkpt detected: %s\n", precord->name); #endif } /* * If we are currently stepping through the lockset, * suspend task. */ if (pnode->step) { printf("\n BKPT> Stopped at: %s within Entrypoint: %s\n-> ", precord->name, pnode->current_ep->name); pnode->precord = precord; /* Move current lockset to top of stack */ ellDelete(&lset_stack, (ELLNODE *)pnode); ellInsert(&lset_stack, NULL, (ELLNODE *)pnode); /* * Unlock database while the task suspends itself. This * is done so that dbb() dbd() dbc() dbs() may be used * when the task is suspended. Scan tasks that also * use the scan lock feature will not be hung during * a breakpoint, so that records in other locksets will * continue to be processed. Cross your fingers, this * might actually work ! */ epicsMutexUnlock(bkpt_stack_sem); dbScanUnlock(precord); epicsThreadSuspendSelf(); dbScanLock(precord); epicsMutexMustLock(bkpt_stack_sem); } return(0); }
static void devVacSenCallback(asynUser *pasynUser) { dbCommon *pr = (dbCommon *)pasynUser->userPvt; devVacSenPvt *pPvt = (devVacSenPvt *)pr->dpvt; char readBuffer[vacSen_SIZE]; char responseBuffer[vacSen_BUFFER_SIZE]; struct rset *prset = (struct rset *)(pr->rset); int i, nread; char *pstartdata=0; char addcmd[3]; pPvt->pasynUser->timeout = vacSen_TIMEOUT; /* * VacSen on normal cycle should get status from all the values. * For commands issued the sendBuf will have a finite value. */ if (pPvt->command) { devVacSenWriteRead(pasynUser, pPvt->sendBuf,readBuffer,&nread); if (nread < 1 ) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Cmd reply too small=%d\n", pr->name, nread); goto finish; } /* for GP307 */ if (pPvt->devType == 0) { if (strcmp(readBuffer,"OK") != 0 ) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Cmd reply has error=[%s]\n", pr->name, readBuffer); recGblSetSevr(pr, READ_ALARM, INVALID_ALARM); goto finish; } /* for GP350 */ } else if (pPvt->devType == 1) { if (readBuffer[0] =='?') { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Cmd reply has error=[%s]\n", pr->name, readBuffer); recGblSetSevr(pr, READ_ALARM, INVALID_ALARM); goto finish; } } } /* Now start the various reads ...... * make sure to check the devType and send the correct set of commands * devType -> 0 = GP307, 1=GP350, 2=MM200 * GP307 and GP350 have only 6 commands while MM200 has 8 commands * The data will be packed into responseBuf separated by ",". * The locations are as follows for GP307 and GP350 * the one character doesnt work. so we use "PCS" for GP307 and "PC S" for GP350 * 307 = x,x,x,x,x,x<cr><lf> 350=# xxxx <cr> where x=1 or 0 * responseBuffer[0-14] = SetPoint Status * responseBuffer[15] = Degas Status 0 or 1 * responseBuffer[20-29] = IG1 pressure x.xxE-xx * responseBuffer[30-39] = IG2 pressure x.xxE-xx * responseBuffer[40-49] = CG1 pressure x.xxE-xx * responseBuffer[50-59] = CG2 pressure x.xxE-xx * The locations are as follows for MM200 * responseBuffer[0-9] = SetPoint Status in 2 char with 2nd char for low 4 * responseBuffer[10-19] = CC pressure n=x.xx-(+)eT * responseBuffer[20-29 = CG1 pressure n=x.xx-(+)eT * responseBuffer[30-39] = CG2 pressure n=x.xx-(+)eT ( if pressent) * responseBuffer[40-49] = SP1/2 pressure x.x-(+)e or x.xx-(+)e * responseBuffer[50-59] = SP3/4 pressure x.x-(+)e or x.xx-(+)e * responseBuffer[60-69] = SP5/6 pressure x.x-(+)e or x.xx-(+)e * responseBuffer[70-79] = SP7/8 pressure x.x-(+)e or x.xx-(+)e */ memset(responseBuffer, 0, vacSen_BUFFER_SIZE); for (i=0;i<8;i++) { /* check for GP307 and GP350 and exit when commands are done */ if (i > 5 && pPvt->devType < 2) continue; /* check for CV2 nonexistance and skip*/ if (pPvt->devType ==2 && i==3 && pPvt->cv2==0) continue; /* for MM200 if no of setpoints is only 2 then skip */ if (pPvt->devType ==2 && pPvt->noSPT==2 && i>5) continue; strcpy( pPvt->sendBuf,pPvt->cmdPrefix); strcat( pPvt->sendBuf,readCmdString[i+(pPvt->devType *10)]); /* for MM200 we have to add the station number to command */ if (pPvt->devType == 2) { switch (i) { case 1: sprintf(addcmd,"%d",pPvt->cc); break; case 2: sprintf(addcmd,"%d",pPvt->cv1); break; case 3: sprintf(addcmd,"%d",pPvt->cv2); break; case 4: sprintf(addcmd,"%dN",pPvt->cv1); break; case 5: sprintf(addcmd,"%dN",(2 + pPvt->cv1)); break; case 6: sprintf(addcmd,"%dN",(4 + pPvt->cv1)); break; case 7: sprintf(addcmd,"%dN",(6 + pPvt->cv1)); break; default: strcpy(addcmd,""); break; } strcat(pPvt->sendBuf,addcmd); } devVacSenWriteRead(pasynUser, pPvt->sendBuf,readBuffer,&nread); if (nread < 1) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Read reply too small=%d\n", pr->name, nread); pPvt->errCount++; goto finish; } /* * For Problems: * For GP307 series sends out message with the words ERROR at the end * For GP350 series all error messages start with ? instead of * * Lets look for these and set the alarm on the record if problems. * For GP350 lets strip the leading character and the space [*] * For MM200 the reply is "x?" where x=ACDLNORS */ /* for GP307 */ if (pPvt->devType ==0) { pstartdata = &readBuffer[nread-5]; if (strcmp(pstartdata,"ERROR") == 0 ) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Read reply has error=[%s]\n", pr->name, readBuffer); pPvt->errCount++; goto finish; } pstartdata = &readBuffer[0]; /* for GP350 */ } else if (pPvt->devType == 1) { if (readBuffer[0] =='?') { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Read reply has error=[%s]\n", pr->name, readBuffer); pPvt->errCount++; goto finish; } /* strip off the headers */ pstartdata = &readBuffer[2]; /* for MM200 */ } else if (pPvt->devType == 2) { if (readBuffer[1] =='?') { asynPrint(pasynUser, ASYN_TRACE_ERROR, "devVacSen::devVacSenCallback %s Read reply has error=[%s]\n", pr->name, readBuffer); pPvt->errCount++; goto finish; } /* Figure out how many relays are there based on reply */ if(i==0) { if(readBuffer[0] == 'n') pPvt->noSPT = 2; else pPvt->noSPT = 4; } pstartdata = &readBuffer[0]; } /* for Degas alone move the data by 5 to accomadate GP307 PCS */ if (pPvt->devType < 2 && i==1) strcpy(&responseBuffer[15],pstartdata); else strcpy(&responseBuffer[10*i],pstartdata); } /* for successful read set errCount=0 */ pPvt->errCount=0; /* Process the record. This will result in the readWrite_vs routine * being called again, but with pact=1 */ finish: memset(pPvt->recBuf, 0, vacSen_BUFFER_SIZE); memcpy(pPvt->recBuf, responseBuffer, vacSen_BUFFER_SIZE); dbScanLock(pr); (*prset->process)(pr); dbScanUnlock(pr); }