long epicsShareAPI dbPutLinkValue(struct link *plink, short dbrType, const void *pbuffer, long nRequest) { long status = 0; if (plink->type == DB_LINK) { struct dbCommon *psource = plink->value.pv_link.precord; struct pv_link *ppv_link = &plink->value.pv_link; DBADDR *paddr = (DBADDR *)ppv_link->pvt; dbCommon *pdest = paddr->precord; status = dbPut(paddr, dbrType, pbuffer, nRequest); inherit_severity(ppv_link,pdest,psource->nsta,psource->nsev); if (status) return status; if (paddr->pfield == (void *)&pdest->proc || (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { /*if dbPutField caused asyn record to process */ /* ask for reprocessing*/ if (pdest->putf) { pdest->rpro = TRUE; } else { /* otherwise ask for the record to be processed*/ status = dbScanLink(psource, pdest); } } if (status) recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM); } else if (plink->type == CA_LINK) { struct dbCommon *psource = plink->value.pv_link.precord; status = dbCaPutLink(plink, dbrType, pbuffer, nRequest); if (status < 0) recGblSetSevr(psource, LINK_ALARM, INVALID_ALARM); } else { cantProceed("dbPutLinkValue: Illegal link type"); } return status; }
/** Constructor for NDPluginROIStat; most parameters are simply passed to NDPluginDriver::NDPluginDriver. * After calling the base class constructor this method sets reasonable default values for all of the * ROI parameters. * \param[in] portName The name of the asyn port driver to be created. * \param[in] queueSize The number of NDArrays that the input queue for this plugin can hold when * NDPluginDriverBlockingCallbacks=0. Larger queues can decrease the number of dropped arrays, * at the expense of more NDArray buffers being allocated from the underlying driver's NDArrayPool. * \param[in] blockingCallbacks Initial setting for the NDPluginDriverBlockingCallbacks flag. * 0=callbacks are queued and executed by the callback thread; 1 callbacks execute in the thread * of the driver doing the callbacks. * \param[in] NDArrayPort Name of asyn port driver for initial source of NDArray callbacks. * \param[in] NDArrayAddr asyn port driver address for initial source of NDArray callbacks. * \param[in] maxROIs The maximum number of ROIs this plugin supports. 1 is minimum. * \param[in] maxBuffers The maximum number of NDArray buffers that the NDArrayPool for this driver is * allowed to allocate. Set this to -1 to allow an unlimited number of buffers. * \param[in] maxMemory The maximum amount of memory that the NDArrayPool for this driver is * allowed to allocate. Set this to -1 to allow an unlimited amount of memory. * \param[in] priority The thread priority for the asyn port driver thread if ASYN_CANBLOCK is set in asynFlags. * \param[in] stackSize The stack size for the asyn port driver thread if ASYN_CANBLOCK is set in asynFlags. */ NDPluginROIStat::NDPluginROIStat(const char *portName, int queueSize, int blockingCallbacks, const char *NDArrayPort, int NDArrayAddr, int maxROIs, int maxBuffers, size_t maxMemory, int priority, int stackSize) /* Invoke the base class constructor */ : NDPluginDriver(portName, queueSize, blockingCallbacks, NDArrayPort, NDArrayAddr, maxROIs, NUM_NDPLUGIN_ROISTAT_PARAMS, maxBuffers, maxMemory, asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask, asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask, ASYN_MULTIDEVICE, 1, priority, stackSize) { const char *functionName = "NDPluginROIStat::NDPluginROIStat"; if (maxROIs < 1) { maxROIs = 1; } maxROIs_ = maxROIs; pROIs_ = new NDROI[maxROIs]; if(!pROIs_) {cantProceed(functionName);} /* ROI general parameters */ createParam(NDPluginROIStatFirstString, asynParamInt32, &NDPluginROIStatFirst); createParam(NDPluginROIStatNameString, asynParamOctet, &NDPluginROIStatName); createParam(NDPluginROIStatUseString, asynParamInt32, &NDPluginROIStatUse); createParam(NDPluginROIStatResetString, asynParamInt32, &NDPluginROIStatReset); createParam(NDPluginROIStatResetAllString, asynParamInt32, &NDPluginROIStatResetAll); createParam(NDPluginROIStatBgdWidthString, asynParamInt32, &NDPluginROIStatBgdWidth); /* ROI definition */ createParam(NDPluginROIStatDim0MinString, asynParamInt32, &NDPluginROIStatDim0Min); createParam(NDPluginROIStatDim0SizeString, asynParamInt32, &NDPluginROIStatDim0Size); createParam(NDPluginROIStatDim0MaxSizeString, asynParamInt32, &NDPluginROIStatDim0MaxSize); createParam(NDPluginROIStatDim1MinString, asynParamInt32, &NDPluginROIStatDim1Min); createParam(NDPluginROIStatDim1SizeString, asynParamInt32, &NDPluginROIStatDim1Size); createParam(NDPluginROIStatDim1MaxSizeString, asynParamInt32, &NDPluginROIStatDim1MaxSize); createParam(NDPluginROIStatDim2MinString, asynParamInt32, &NDPluginROIStatDim2Min); createParam(NDPluginROIStatDim2SizeString, asynParamInt32, &NDPluginROIStatDim2Size); createParam(NDPluginROIStatDim2MaxSizeString, asynParamInt32, &NDPluginROIStatDim2MaxSize); /* ROI statistics */ createParam(NDPluginROIStatMinValueString, asynParamFloat64, &NDPluginROIStatMinValue); createParam(NDPluginROIStatMaxValueString, asynParamFloat64, &NDPluginROIStatMaxValue); createParam(NDPluginROIStatMeanValueString, asynParamFloat64, &NDPluginROIStatMeanValue); createParam(NDPluginROIStatTotalString, asynParamFloat64, &NDPluginROIStatTotal); createParam(NDPluginROIStatNetString, asynParamFloat64, &NDPluginROIStatNet); /* Time series arrays */ createParam(NDPluginROIStatTSControlString, asynParamInt32, &NDPluginROIStatTSControl); createParam(NDPluginROIStatTSNumPointsString, asynParamInt32, &NDPluginROIStatTSNumPoints); createParam(NDPluginROIStatTSCurrentPointString, asynParamInt32, &NDPluginROIStatTSCurrentPoint); createParam(NDPluginROIStatTSAcquiringString, asynParamInt32, &NDPluginROIStatTSAcquiring); createParam(NDPluginROIStatTSMinValueString, asynParamFloat64Array, &NDPluginROIStatTSMinValue); createParam(NDPluginROIStatTSMaxValueString, asynParamFloat64Array, &NDPluginROIStatTSMaxValue); createParam(NDPluginROIStatTSMeanValueString, asynParamFloat64Array, &NDPluginROIStatTSMeanValue); createParam(NDPluginROIStatTSTotalString, asynParamFloat64Array, &NDPluginROIStatTSTotal); createParam(NDPluginROIStatTSNetString, asynParamFloat64Array, &NDPluginROIStatTSNet); createParam(NDPluginROIStatTSTimestampString, asynParamFloat64Array, &NDPluginROIStatTSTimestamp); createParam(NDPluginROIStatLastString, asynParamInt32, &NDPluginROIStatLast); //Note: params set to a default value here will overwrite a default database value /* Set the plugin type string */ setStringParam(NDPluginDriverPluginType, "NDPluginROIStat"); for (int roi=0; roi<maxROIs_; ++roi) { setIntegerParam(roi , NDPluginROIStatFirst, 0); setIntegerParam(roi , NDPluginROIStatLast, 0); setStringParam (roi, NDPluginROIStatName, ""); setIntegerParam(roi , NDPluginROIStatUse, 0); setIntegerParam(roi , NDPluginROIStatDim0Min, 0); setIntegerParam(roi , NDPluginROIStatDim0Size, 0); setIntegerParam(roi , NDPluginROIStatDim0MaxSize, 0); setIntegerParam(roi , NDPluginROIStatDim1Min, 0); setIntegerParam(roi , NDPluginROIStatDim1Size, 0); setIntegerParam(roi , NDPluginROIStatDim1MaxSize, 0); setIntegerParam(roi , NDPluginROIStatDim2Min, 0); setIntegerParam(roi , NDPluginROIStatDim2Size, 0); setIntegerParam(roi , NDPluginROIStatDim2MaxSize, 0); setDoubleParam (roi , NDPluginROIStatMinValue, 0.0); setDoubleParam (roi , NDPluginROIStatMaxValue, 0.0); setDoubleParam (roi , NDPluginROIStatMeanValue, 0.0); setDoubleParam (roi , NDPluginROIStatTotal, 0.0); setDoubleParam (roi , NDPluginROIStatNet, 0.0); callParamCallbacks(roi); } numTSPoints_ = DEFAULT_NUM_TSPOINTS; setIntegerParam(NDPluginROIStatTSNumPoints, numTSPoints_); timeSeries_ = (double *)calloc(MAX_TIME_SERIES_TYPES*maxROIs_*numTSPoints_, sizeof(double)); /* Try to connect to the array port */ connectToArrayPort(); callParamCallbacks(); }
/** * Callback function that is called by the NDArray driver with new NDArray data. * Computes statistics on the ROIs if NDPluginROIStatUse is 1. * If NDPluginROIStatNDArrayCallbacks is 1 then it also does NDArray callbacks. * \param[in] pArray The NDArray from the callback. */ void NDPluginROIStat::processCallbacks(NDArray *pArray) { //This function is called with the mutex already locked. //It unlocks it during long calculations when private structures don't need to be protected. int itemp = 0; int dim = 0; asynStatus status = asynSuccess; NDROI *pROI; int TSAcquiring; const char* functionName = "NDPluginROIStat::processCallbacks"; NDROI_t *pROIs = new NDROI[maxROIs_]; if(!pROIs) {cantProceed("%s",functionName);} /* Call the base class method */ NDPluginDriver::beginProcessCallbacks(pArray); // This plugin only works with 1-D or 2-D arrays if ((pArray->ndims < 1) || (pArray->ndims > 2)) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s: error, number of array dimensions must be 1 or 2\n", functionName); } //Set NDArraySize params to the input pArray, because this plugin doesn't change them if (pArray->ndims > 0) setIntegerParam(NDArraySizeX, (int)pArray->dims[0].size); if (pArray->ndims > 1) setIntegerParam(NDArraySizeY, (int)pArray->dims[1].size); /* Loop over the ROIs in this driver */ for (int roi=0; roi<maxROIs_; ++roi) { pROI = &pROIs[roi]; getIntegerParam(roi, NDPluginROIStatUse, &pROI->use); if (!pROI->use) { continue; } /* Need to fetch all of these parameters while we still have the mutex */ getIntegerParam(roi, NDPluginROIStatDim0Min, &itemp); pROI->offset[0] = itemp; getIntegerParam(roi, NDPluginROIStatDim1Min, &itemp); pROI->offset[1] = itemp; getIntegerParam(roi, NDPluginROIStatDim0Size, &itemp); pROI->size[0] = itemp; getIntegerParam(roi, NDPluginROIStatDim1Size, &itemp); pROI->size[1] = itemp; getIntegerParam(roi, NDPluginROIStatBgdWidth, &itemp); pROI->bgdWidth = itemp; for (dim=0; dim<pArray->ndims; dim++) { pROI->offset[dim] = MAX(pROI->offset[dim], 0); pROI->offset[dim] = MIN(pROI->offset[dim], pArray->dims[dim].size-1); pROI->size[dim] = MAX(pROI->size[dim], 1); pROI->size[dim] = MIN(pROI->size[dim], pArray->dims[dim].size - pROI->offset[dim]); pROI->arraySize[dim] = (int)pArray->dims[dim].size; } /* Update the parameters that may have changed */ setIntegerParam(roi, NDPluginROIStatDim0MaxSize, 0); setIntegerParam(roi, NDPluginROIStatDim1MaxSize, 0); if (pArray->ndims > 0) { setIntegerParam(roi, NDPluginROIStatDim0MaxSize, (int)pArray->dims[0].size); setIntegerParam(roi, NDPluginROIStatDim0Min, (int)pROI->offset[0]); setIntegerParam(roi, NDPluginROIStatDim0Size, (int)pROI->size[0]); } if (pArray->ndims > 1) { setIntegerParam(roi, NDPluginROIStatDim1MaxSize, (int)pArray->dims[1].size); setIntegerParam(roi, NDPluginROIStatDim1Min, (int)pROI->offset[1]); setIntegerParam(roi, NDPluginROIStatDim1Size, (int)pROI->size[1]); } } /* This function is called with the lock taken, and it must be set when we exit. * The following code can be exected without the mutex because we are not accessing elements of * pPvt that other threads can access. */ this->unlock(); for (int roi=0; roi<maxROIs_; ++roi) { pROI = &pROIs[roi]; if (!pROI->use) { continue; } status = doComputeStatistics(pArray, pROI); if (status != asynSuccess) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s: doComputeStatistics failed. status=%d\n", functionName, status); } } /* We must enter the loop and exit with the mutex locked */ this->lock(); getIntegerParam(NDPluginROIStatTSAcquiring, &TSAcquiring); for (int roi=0; roi<maxROIs_; ++roi) { pROI = &pROIs[roi]; if (!pROI->use) { continue; } if (TSAcquiring) { double *pData = timeSeries_ + (roi * MAX_TIME_SERIES_TYPES * numTSPoints_); pData[TSMinValue*numTSPoints_ + currentTSPoint_] = pROI->min; pData[TSMaxValue*numTSPoints_ + currentTSPoint_] = pROI->max; pData[TSMeanValue*numTSPoints_ + currentTSPoint_] = pROI->mean; pData[TSTotal*numTSPoints_ + currentTSPoint_] = pROI->total; pData[TSNet*numTSPoints_ + currentTSPoint_] = pROI->net; pData[TSTimestamp*numTSPoints_ + currentTSPoint_] = pArray->timeStamp; } setDoubleParam(roi, NDPluginROIStatMinValue, pROI->min); setDoubleParam(roi, NDPluginROIStatMaxValue, pROI->max); setDoubleParam(roi, NDPluginROIStatMeanValue, pROI->mean); setDoubleParam(roi, NDPluginROIStatTotal, pROI->total); setDoubleParam(roi, NDPluginROIStatNet, pROI->net); asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s ROI=%d, min=%f, max=%f, mean=%f, total=%f, net=%f\n", functionName, roi, pROI->min, pROI->max, pROI->mean, pROI->total, pROI->net); callParamCallbacks(roi); } if (TSAcquiring) { currentTSPoint_++; setIntegerParam(NDPluginROIStatTSCurrentPoint, currentTSPoint_); if (currentTSPoint_ >= numTSPoints_) { setIntegerParam(NDPluginROIStatTSAcquiring, 0); doTimeSeriesCallbacks(); } } NDPluginDriver::endProcessCallbacks(pArray, true, true); callParamCallbacks(); delete[] pROIs; }
long epicsShareAPI dbGetLinkValue(struct link *plink, short dbrType, void *pbuffer, long *poptions, long *pnRequest) { long status = 0; if (plink->type == CONSTANT) { if (poptions) *poptions = 0; if (pnRequest) *pnRequest = 0; } else if (plink->type == DB_LINK) { struct pv_link *ppv_link = &(plink->value.pv_link); DBADDR *paddr = ppv_link->pvt; dbCommon *precord = plink->value.pv_link.precord; /* scan passive records with links that are process passive */ if (ppv_link->pvlMask&pvlOptPP) { dbCommon *pfrom = paddr->precord; unsigned char pact; pact = precord->pact; precord->pact = TRUE; status = dbScanPassive(precord,pfrom); precord->pact = pact; if (status) return status; } if(precord!= paddr->precord) { inherit_severity(ppv_link,precord,paddr->precord->stat,paddr->precord->sevr); } if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) { status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); } else { unsigned short dbfType = paddr->field_type; long no_elements = paddr->no_elements; if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE) { status = S_db_badDbrtype; recGblRecordError(status, precord, "GetLinkValue Failed"); recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); return status; } /* attempt to make a fast link */ if ((!poptions || *poptions == 0) && no_elements == 1 && (!pnRequest || *pnRequest == 1) && paddr->special != SPC_ATTRIBUTE) { ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType]; status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); } else { ppv_link->getCvt = 0; status = dbGet(paddr, dbrType, pbuffer, poptions, pnRequest, NULL); } } ppv_link->lastGetdbrType = dbrType; if (status) { recGblRecordError(status, precord, "dbGetLinkValue"); recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); } } else if (plink->type == CA_LINK) { struct dbCommon *precord = plink->value.pv_link.precord; const struct pv_link *pcalink = &plink->value.pv_link; epicsEnum16 sevr, stat; status=dbCaGetLink(plink,dbrType,pbuffer,&stat,&sevr,pnRequest); if (status) { recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); } else { inherit_severity(pcalink,precord,stat,sevr); } if (poptions) *poptions = 0; } else { cantProceed("dbGetLinkValue: Illegal link type"); } return status; }
static void registryInit(int tableSize) { if(tableSize==0) tableSize = DEFAULT_TABLE_SIZE; gphInitPvt(&gphPvt,tableSize); if(!gphPvt) cantProceed("registry why did gphInitPvt fail\n"); }