asynNDArrayDriver::asynNDArrayDriver(const char *portName, int maxAddr, int maxBuffers, size_t maxMemory, int interfaceMask, int interruptMask, int asynFlags, int autoConnect, int priority, int stackSize) : asynPortDriver(portName, maxAddr, interfaceMask | asynInt32Mask | asynFloat64Mask | asynOctetMask | asynInt32ArrayMask | asynGenericPointerMask | asynDrvUserMask, interruptMask | asynInt32Mask | asynFloat64Mask | asynOctetMask | asynInt32ArrayMask | asynGenericPointerMask, asynFlags, autoConnect, priority, stackSize), pNDArrayPool(NULL), queuedArrayCountMutex_(NULL), queuedArrayCount_(0), queuedArrayUpdateRun_(true) { char versionString[20]; static const char *functionName = "asynNDArrayDriver"; /* Save the stack size and priority for other threads that this object may create */ if (stackSize <= 0) stackSize = epicsThreadGetStackSize(epicsThreadStackMedium); threadStackSize_ = stackSize; if (priority <= 0) priority = epicsThreadPriorityMedium; threadPriority_ = priority; this->pNDArrayPoolPvt_ = new NDArrayPool(this, maxMemory); this->pNDArrayPool = this->pNDArrayPoolPvt_; this->queuedArrayCountMutex_ = new epicsMutex(); /* Allocate pArray pointer array */ this->pArrays = (NDArray **)calloc(maxAddr, sizeof(NDArray *)); this->pAttributeList = new NDAttributeList(); createParam(NDPortNameSelfString, asynParamOctet, &NDPortNameSelf); createParam(NDADCoreVersionString, asynParamOctet, &NDADCoreVersion); createParam(NDDriverVersionString, asynParamOctet, &NDDriverVersion); createParam(NDArraySizeXString, asynParamInt32, &NDArraySizeX); createParam(NDArraySizeYString, asynParamInt32, &NDArraySizeY); createParam(NDArraySizeZString, asynParamInt32, &NDArraySizeZ); createParam(NDArraySizeString, asynParamInt32, &NDArraySize); createParam(NDNDimensionsString, asynParamInt32, &NDNDimensions); createParam(NDDimensionsString, asynParamInt32, &NDDimensions); createParam(NDDataTypeString, asynParamInt32, &NDDataType); createParam(NDColorModeString, asynParamInt32, &NDColorMode); createParam(NDUniqueIdString, asynParamInt32, &NDUniqueId); createParam(NDTimeStampString, asynParamFloat64, &NDTimeStamp); createParam(NDEpicsTSSecString, asynParamInt32, &NDEpicsTSSec); createParam(NDEpicsTSNsecString, asynParamInt32, &NDEpicsTSNsec); createParam(NDBayerPatternString, asynParamInt32, &NDBayerPattern); createParam(NDCodecString, asynParamOctet, &NDCodec); createParam(NDCompressedSizeString, asynParamInt32, &NDCompressedSize); createParam(NDArrayCounterString, asynParamInt32, &NDArrayCounter); createParam(NDFilePathString, asynParamOctet, &NDFilePath); createParam(NDFilePathExistsString, asynParamInt32, &NDFilePathExists); createParam(NDFileNameString, asynParamOctet, &NDFileName); createParam(NDFileNumberString, asynParamInt32, &NDFileNumber); createParam(NDFileTemplateString, asynParamOctet, &NDFileTemplate); createParam(NDAutoIncrementString, asynParamInt32, &NDAutoIncrement); createParam(NDFullFileNameString, asynParamOctet, &NDFullFileName); createParam(NDFileFormatString, asynParamInt32, &NDFileFormat); createParam(NDAutoSaveString, asynParamInt32, &NDAutoSave); createParam(NDWriteFileString, asynParamInt32, &NDWriteFile); createParam(NDReadFileString, asynParamInt32, &NDReadFile); createParam(NDFileWriteModeString, asynParamInt32, &NDFileWriteMode); createParam(NDFileWriteStatusString, asynParamInt32, &NDFileWriteStatus); createParam(NDFileWriteMessageString, asynParamOctet, &NDFileWriteMessage); createParam(NDFileNumCaptureString, asynParamInt32, &NDFileNumCapture); createParam(NDFileNumCapturedString, asynParamInt32, &NDFileNumCaptured); createParam(NDFileCaptureString, asynParamInt32, &NDFileCapture); createParam(NDFileDeleteDriverFileString, asynParamInt32, &NDFileDeleteDriverFile); createParam(NDFileLazyOpenString, asynParamInt32, &NDFileLazyOpen); createParam(NDFileCreateDirString, asynParamInt32, &NDFileCreateDir); createParam(NDFileTempSuffixString, asynParamOctet, &NDFileTempSuffix); createParam(NDAttributesFileString, asynParamOctet, &NDAttributesFile); createParam(NDAttributesStatusString, asynParamInt32, &NDAttributesStatus); createParam(NDAttributesMacrosString, asynParamOctet, &NDAttributesMacros); createParam(NDArrayDataString, asynParamGenericPointer, &NDArrayData); createParam(NDArrayCallbacksString, asynParamInt32, &NDArrayCallbacks); createParam(NDPoolMaxBuffersString, asynParamInt32, &NDPoolMaxBuffers); createParam(NDPoolAllocBuffersString, asynParamInt32, &NDPoolAllocBuffers); createParam(NDPoolFreeBuffersString, asynParamInt32, &NDPoolFreeBuffers); createParam(NDPoolMaxMemoryString, asynParamFloat64, &NDPoolMaxMemory); createParam(NDPoolUsedMemoryString, asynParamFloat64, &NDPoolUsedMemory); createParam(NDPoolEmptyFreeListString, asynParamInt32, &NDPoolEmptyFreeList); createParam(NDNumQueuedArraysString, asynParamInt32, &NDNumQueuedArrays); /* Here we set the values of read-only parameters and of read/write parameters that cannot * or should not get their values from the database. Note that values set here will override * those in the database for output records because if asyn device support reads a value from * the driver with no error during initialization then it sets the output record to that value. * If a value is not set here then the read request will return an error (uninitialized). * Values set here will be overridden by values from save/restore if they exist. */ setStringParam (NDPortNameSelf, portName); epicsSnprintf(versionString, sizeof(versionString), "%d.%d.%d", ADCORE_VERSION, ADCORE_REVISION, ADCORE_MODIFICATION); setStringParam(NDADCoreVersion, versionString); // We set the driver version to the same thing, which is appropriate for plugins in ADCore // Other drivers need to set this after this constructor setStringParam(NDDriverVersion, versionString); setIntegerParam(NDArraySizeX, 0); setIntegerParam(NDArraySizeY, 0); setIntegerParam(NDArraySizeZ, 0); setIntegerParam(NDArraySize, 0); setIntegerParam(NDNDimensions, 0); setIntegerParam(NDColorMode, NDColorModeMono); setIntegerParam(NDUniqueId, 0); setDoubleParam (NDTimeStamp, 0.); setIntegerParam(NDEpicsTSSec, 0); setIntegerParam(NDEpicsTSNsec, 0); setIntegerParam(NDBayerPattern, 0); setIntegerParam(NDArrayCounter, 0); /* Set the initial values of FileSave, FileRead, and FileCapture so the readbacks are initialized */ setIntegerParam(NDWriteFile, 0); setIntegerParam(NDReadFile, 0); setIntegerParam(NDFileCapture, 0); setIntegerParam(NDFileWriteStatus, 0); setStringParam (NDFileWriteMessage, ""); /* We set FileTemplate to a reasonable value because it cannot be defined in the database, since it is a * waveform record. However, the waveform record does not currently read the driver value for initialization! */ setStringParam (NDFilePath, ""); setStringParam (NDFileName, ""); setIntegerParam(NDFileNumber, 0); setIntegerParam(NDAutoIncrement, 0); setStringParam (NDFileTemplate, "%s%s_%3.3d.dat"); setIntegerParam(NDFileNumCaptured, 0); setIntegerParam(NDFileCreateDir, 0); setStringParam (NDFileTempSuffix, ""); setStringParam (NDAttributesFile, ""); setIntegerParam(NDAttributesStatus, NDAttributesFileNotFound); setStringParam (NDAttributesMacros, ""); setIntegerParam(NDPoolAllocBuffers, this->pNDArrayPool->getNumBuffers()); setIntegerParam(NDPoolFreeBuffers, this->pNDArrayPool->getNumFree()); setDoubleParam(NDPoolMaxMemory, 0); setDoubleParam(NDPoolUsedMemory, 0); setIntegerParam(NDNumQueuedArrays, 0); queuedArrayEvent_ = epicsEventCreate(epicsEventEmpty); queuedArrayUpdateDone_ = epicsEventCreate(epicsEventEmpty); /* Create the thread that updates the queued array count */ char taskName[100]; epicsSnprintf(taskName, sizeof(taskName)-1, "%s_updateQueuedArrayCount", portName); epicsThreadId queuedArrayThreadId = epicsThreadCreate(taskName, this->threadPriority_, this->threadStackSize_, (EPICSTHREADFUNC)updateQueuedArrayCountC, this); if (queuedArrayThreadId == 0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s error creating updateQueuedArrayCount thread\n", driverName, functionName); } }
int main (int argc, char *argv[]) { int i; int result; /* CA result */ OutputT format = plain; /* User specified format */ RequestT request = get; /* User specified request type */ int isArray = 0; /* Flag for array operation */ int enumAsString = 0; /* Force ENUM values to be strings */ int count = 1; int opt; /* getopt() current option */ chtype dbrType = DBR_STRING; char *pend; EpicsStr *sbuf; double *dbuf; char *cbuf = 0; char *ebuf = 0; void *pbuf; int len = 0; int waitStatus; struct dbr_gr_enum bufGrEnum; int nPvs; /* Number of PVs */ pv* pvs; /* Array of PV structures */ LINE_BUFFER(stdout); /* Configure stdout buffering */ putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */ while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); return 0; case 'n': /* Force interpret ENUM as index number */ enumAsNr = 1; enumAsString = 0; break; case 's': /* Force interpret ENUM as menu string */ enumAsString = 1; enumAsNr = 0; break; case 'S': /* Treat char array as (long) string */ charArrAsStr = 1; isArray = 0; break; case 't': /* Select terse output format */ format = terse; break; case 'l': /* Select long output format */ format = all; break; case 'a': /* Select array mode */ isArray = 1; charArrAsStr = 0; break; case 'c': /* Select put_callback mode */ request = callback; break; case 'w': /* Set CA timeout value */ if(epicsScanDouble(optarg, &caTimeout) != 1) { fprintf(stderr, "'%s' is not a valid timeout value " "- ignored. ('caput -h' for help.)\n", optarg); caTimeout = DEFAULT_TIMEOUT; } break; case '#': /* Array count */ if (sscanf(optarg,"%d", &count) != 1) { fprintf(stderr, "'%s' is not a valid array element count " "- ignored. ('caput -h' for help.)\n", optarg); count = 0; } break; case 'p': /* CA priority */ if (sscanf(optarg,"%u", &caPriority) != 1) { fprintf(stderr, "'%s' is not a valid CA priority " "- ignored. ('caget -h' for help.)\n", optarg); caPriority = DEFAULT_CA_PRIORITY; } if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX; break; case 'F': /* Store this for output and tool_lib formatting */ fieldSeparator = (char) *optarg; break; case '?': fprintf(stderr, "Unrecognized option: '-%c'. ('caput -h' for help.)\n", optopt); return 1; case ':': fprintf(stderr, "Option '-%c' requires an argument. ('caput -h' for help.)\n", optopt); return 1; default : usage(); return 1; } } nPvs = argc - optind; /* Remaining arg list are PV names and values */ if (nPvs < 1) { fprintf(stderr, "No pv name specified. ('caput -h' for help.)\n"); return 1; } if (nPvs == 1) { fprintf(stderr, "No value specified. ('caput -h' for help.)\n"); return 1; } nPvs = 1; /* One PV - the rest is value(s) */ epId = epicsEventCreate(epicsEventEmpty); /* Create empty EPICS event (semaphore) */ /* Start up Channel Access */ result = ca_context_create(ca_enable_preemptive_callback); if (result != ECA_NORMAL) { fprintf(stderr, "CA error %s occurred while trying " "to start channel access.\n", ca_message(result)); return 1; } /* Allocate PV structure array */ pvs = calloc (nPvs, sizeof(pv)); if (!pvs) { fprintf(stderr, "Memory allocation for channel structure failed.\n"); return 1; } /* Connect channels */ pvs[0].name = argv[optind] ; /* Copy PV name from command line */ result = connect_pvs(pvs, nPvs); /* If the connection fails, we're done */ if (result) { ca_context_destroy(); return result; } /* Get values from command line */ optind++; if (isArray) { optind++; /* In case of array skip first value (nr * of elements) - actual number of values is used */ count = argc - optind; } else { /* Concatenate the remaining line to one string * (sucks but is compatible to the former version) */ for (i = optind; i < argc; i++) { len += strlen(argv[i]); len++; } cbuf = calloc(len, sizeof(char)); if (!cbuf) { fprintf(stderr, "Memory allocation failed.\n"); return 1; } strcpy(cbuf, argv[optind]); if (argc > optind+1) { for (i = optind + 1; i < argc; i++) { strcat(cbuf, " "); strcat(cbuf, argv[i]); } } if ((argc - optind) >= 1) count = 1; argv[optind] = cbuf; } sbuf = calloc (count, sizeof(EpicsStr)); dbuf = calloc (count, sizeof(double)); if(!sbuf || !dbuf) { fprintf(stderr, "Memory allocation failed\n"); return 1; } /* ENUM? Special treatment */ if (ca_field_type(pvs[0].chid) == DBR_ENUM) { /* Get the ENUM strings */ result = ca_array_get (DBR_GR_ENUM, 1, pvs[0].chid, &bufGrEnum); result = ca_pend_io(caTimeout); if (result == ECA_TIMEOUT) { fprintf(stderr, "Read operation timed out: ENUM data was not read.\n"); return 1; } if (enumAsNr) { /* Interpret values as numbers */ for (i = 0; i < count; ++i) { dbuf[i] = epicsStrtod(*(argv+optind+i), &pend); if (*(argv+optind+i) == pend) { /* Conversion didn't work */ fprintf(stderr, "Enum index value '%s' is not a number.\n", *(argv+optind+i)); return 1; } if (dbuf[i] >= bufGrEnum.no_str) { fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", *(argv+optind+i)); } } dbrType = DBR_DOUBLE; } else { /* Interpret values as strings */ for (i = 0; i < count; ++i) { epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr)); *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0'; dbrType = DBR_STRING; /* Compare to ENUM strings */ for (len = 0; len < bufGrEnum.no_str; len++) if (!strcmp(sbuf[i], bufGrEnum.strs[len])) break; if (len >= bufGrEnum.no_str) { /* Not a string? Try as number */ dbuf[i] = epicsStrtod(sbuf[i], &pend); if (sbuf[i] == pend || enumAsString) { fprintf(stderr, "Enum string value '%s' invalid.\n", sbuf[i]); return 1; } if (dbuf[i] >= bufGrEnum.no_str) { fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", sbuf[i]); } dbrType = DBR_DOUBLE; } } } } else { /* Not an ENUM */ if (charArrAsStr) { dbrType = DBR_CHAR; ebuf = calloc(len, sizeof(char)); if(!ebuf) { fprintf(stderr, "Memory allocation failed\n"); return 1; } count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1; } else { for (i = 0; i < count; ++i) { epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr)); *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0'; } dbrType = DBR_STRING; } } /* Read and print old data */ if (format != terse) { printf("Old : "); result = caget(pvs, nPvs, format, 0, 0); } /* Write new data */ if (dbrType == DBR_STRING) pbuf = sbuf; else if (dbrType == DBR_CHAR) pbuf = ebuf; else pbuf = dbuf; if (request == callback) { /* Use callback version of put */ pvs[0].status = ECA_NORMAL; /* All ok at the moment */ result = ca_array_put_callback ( dbrType, count, pvs[0].chid, pbuf, put_event_handler, (void *) pvs); } else { /* Use standard put with defined timeout */ result = ca_array_put (dbrType, count, pvs[0].chid, pbuf); } result = ca_pend_io(caTimeout); if (result == ECA_TIMEOUT) { fprintf(stderr, "Write operation timed out: Data was not written.\n"); return 1; } if (request == callback) { /* Also wait for callbacks */ waitStatus = epicsEventWaitWithTimeout( epId, caTimeout ); if (waitStatus) fprintf(stderr, "Write callback operation timed out\n"); /* retrieve status from callback */ result = pvs[0].status; } if (result != ECA_NORMAL) { fprintf(stderr, "Error occured writing data.\n"); return 1; } /* Read and print new data */ if (format != terse) printf("New : "); result = caget(pvs, nPvs, format, 0, 0); /* Shut down Channel Access */ ca_context_destroy(); return result; }
/*Constructor */ drvSIS3820::drvSIS3820(const char *portName, int baseAddress, int interruptVector, int interruptLevel, int maxChans, int maxSignals, bool useDma, int fifoBufferWords) : drvSIS38XX(portName, maxChans, maxSignals), useDma_(useDma) { int status; epicsUInt32 controlStatusReg; epicsUInt32 moduleID; static const char* functionName="SIS3820"; setIntegerParam(SIS38XXModel_, MODEL_SIS3820); /* Call devLib to get the system address that corresponds to the VME * base address of the board. */ status = devRegisterAddress("drvSIS3820", SIS3820_ADDRESS_TYPE, (size_t)baseAddress, SIS3820_BOARD_SIZE, (volatile void **)®isters_); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, Can't register VME address 0x%x\n", driverName, functionName, portName, baseAddress); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Registered VME address: 0x%x to local address: %p size: 0x%X\n", driverName, functionName, baseAddress, registers_, SIS3820_BOARD_SIZE); /* Call devLib to get the system address that corresponds to the VME * FIFO address of the board. */ fifoBaseVME_ = (epicsUInt32 *)(baseAddress + SIS3820_FIFO_BASE); status = devRegisterAddress("drvSIS3820", SIS3820_ADDRESS_TYPE, (size_t)fifoBaseVME_, SIS3820_FIFO_BYTE_SIZE, (volatile void **)&fifoBaseCPU_); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, Can't register FIFO address 0x%x\n", driverName, functionName, portName, baseAddress + SIS3820_FIFO_BASE); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Registered VME FIFO address: %p to local address: %p size: 0x%X\n", driverName, functionName, fifoBaseVME_, fifoBaseCPU_, SIS3820_FIFO_BYTE_SIZE); /* Probe VME bus to see if card is there */ status = devReadProbe(4, (char *) &(registers_->control_status_reg), (char *) &controlStatusReg); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: devReadProbe failure for address %p = %d\n", driverName, functionName, ®isters_->control_status_reg, status); return; } /* Get the module info from the card */ moduleID = (registers_->moduleID_reg & 0xFFFF0000) >> 16; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: module ID=%x\n", driverName, functionName, moduleID); firmwareVersion_ = registers_->moduleID_reg & 0x0000FFFF; setIntegerParam(SIS38XXFirmware_, firmwareVersion_); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: firmware=%d\n", driverName, functionName, firmwareVersion_); // Allocate FIFO readout buffer // fifoBufferWords input argument is in words, must be less than SIS3820_FIFO_WORD_SIZE if (fifoBufferWords == 0) fifoBufferWords = SIS3820_FIFO_WORD_SIZE; if (fifoBufferWords > SIS3820_FIFO_WORD_SIZE) fifoBufferWords = SIS3820_FIFO_WORD_SIZE; fifoBufferWords_ = fifoBufferWords; #ifdef vxWorks fifoBuffer_ = (epicsUInt32*) memalign(8, fifoBufferWords_*sizeof(epicsUInt32)); #else void *ptr; status = posix_memalign(&ptr, 8, fifoBufferWords_*sizeof(epicsUInt32)); if(status != 0) { printf("Error: posix_memalign status = %d\n", status); } fifoBuffer_ = (epicsUInt32*)ptr; #endif if (fifoBuffer_ == NULL) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: posix_memalign failure for fifoBuffer_ = %d\n", driverName, functionName, status); return; } dmaDoneEventId_ = epicsEventCreate(epicsEventEmpty); // Create the DMA ID if (useDma_) { dmaId_ = sysDmaCreate(dmaCallbackC, (void*)this); if (dmaId_ == 0 || (int)dmaId_ == -1) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: sysDmaCreate failed, errno=%d. Disabling use of DMA.\n", driverName, functionName, errno); useDma_ = false; } } /* Reset card */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: resetting port %s\n", driverName, functionName, portName); registers_->key_reset_reg = 1; /* Clear FIFO */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: clearing FIFO\n", driverName, functionName); resetFIFO(); // Disable 25MHz test pulses and test mode registers_->control_status_reg = CTRL_COUNTER_TEST_25MHZ_DISABLE; registers_->control_status_reg = CTRL_COUNTER_TEST_MODE_DISABLE; /* Set up the interrupt service routine */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: interruptServiceRoutine pointer %p\n", driverName, functionName, intFuncC); status = devConnectInterruptVME(interruptVector, intFuncC, this); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't connect to vector % d\n", driverName, functionName, interruptVector); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Connected interrupt vector: %d\n\n", driverName, functionName, interruptVector); /* Write interrupt level to hardware */ registers_->irq_config_reg &= ~SIS3820_IRQ_LEVEL_MASK; registers_->irq_config_reg |= (interruptLevel << 8); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq after setting IntLevel= 0x%x\n", driverName, functionName, registers_->irq_config_reg); /* Write interrupt vector to hardware */ registers_->irq_config_reg &= ~SIS3820_IRQ_VECTOR_MASK; registers_->irq_config_reg |= interruptVector; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq = 0x%08x\n", driverName, functionName, registers_->irq_config_reg); /* Initialize board in MCS mode. This will also set the initial value of the operation mode register. */ setAcquireMode(ACQUIRE_MODE_MCS); /* Create the thread that reads the FIFO */ if (epicsThreadCreate("SIS3820FIFOThread", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)readFIFOThreadC, this) == NULL) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: epicsThreadCreate failure\n", driverName, functionName); return; } else asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: epicsThreadCreate success\n", driverName, functionName); erase(); /* Enable interrupts in hardware */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq before enabling interrupts= 0x%08x\n", driverName, functionName, registers_->irq_config_reg); registers_->irq_config_reg |= SIS3820_IRQ_ENABLE; /* Enable interrupt level in EPICS */ status = devEnableInterruptLevel(intVME, interruptLevel); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't enable enterrupt level %d\n", driverName, functionName, interruptLevel); return; } exists_ = true; return; }
int main(int argc,char **argv) { char *pval; double sleepSecs = 0.0; int clearEvery = 0; int indValue = 1; int indNumberCallback = 1; while((argc>1) && (argv[1][0] == '-')) { int i; char option; int narg; option = toupper((argv[1])[1]); pval = argv[2]; argc -= 1; narg = 1; if(option=='S') { sscanf(pval,"%lf",&sleepSecs); argc -= 1; ++narg; } else if(option=='C') { sscanf(pval,"%d",&clearEvery); argc -= 1; ++narg; } else if(option=='V') { verbose = 1; } else { usageExit(); } for(i=1; i<argc; i++) argv[i] = argv[i + narg]; } if(argc != 4) usageExit(); pvname = argv[1]; pvalue1 = argv[2]; pvalue2 = argv[3]; pevent = epicsEventCreate(epicsEventEmpty); SEVCHK(ca_context_create(ca_enable_preemptive_callback), "ca_task_initialize"); while(1) { SEVCHK(ca_search(pvname,&mychid),"ca_search_and_connect"); if(ca_pend_io(3.0)!=ECA_NORMAL) { epicsThreadSleep(5.0); continue; } while(1) { epicsEventWaitStatus status; if(indValue==0) { indValue = 1; pvalue = pvalue2; } else { indValue = 0; pvalue=pvalue1; } if(++indNumberCallback >= MAXnumberCallback) indNumberCallback=0; numberCallback[indNumberCallback] = ++expectedCallback; status = ca_array_put_callback(DBR_STRING,1,mychid, pvalue,putCallback,&numberCallback[indNumberCallback]); if(status!=ECA_NORMAL) { printf("ca_array_put_callback %s\n",ca_message(status)); epicsThreadSleep(2.0); continue; } if((clearEvery>0) && ((expectedCallback % clearEvery)==0)) { ca_flush_io(); epicsThreadSleep(sleepSecs); SEVCHK(ca_clear_channel(mychid),"ca_clear_channel"); ca_flush_io(); expectedCallback = 0; epicsThreadSleep(sleepSecs); if(verbose) { printTime(); printf("Issued ca_clear_channel expectedCallback %d\n", expectedCallback); } break; } ca_flush_io(); if(verbose) { printTime(); printf("Issued ca_put_callback expectedCallback %d\n", expectedCallback); } while(1) { status = epicsEventWaitWithTimeout(pevent,10.0); if(status==epicsEventWaitTimeout) { if(verbose) { printTime(); printf("timeout after 10 seconds\n"); } continue; } break; } if(status!=epicsEventWaitOK) { int i; printTime(); printf("eventWait status %d\n",status); for(i=0; i<MAXnumberCallback; i++) numberCallback[i]=0; } epicsThreadSleep(sleepSecs); } } ca_task_exit(); return(0); }
/** Constructor for the testAsynPortDriver class. * Calls constructor for the asynPortDriver base class. * \param[in] portName The name of the asyn port driver to be created. * \param[in] maxPoints The maximum number of points in the volt and time arrays */ testAsynPortDriver::testAsynPortDriver(const char *portName, int maxPoints) : asynPortDriver(portName, 1, /* maxAddr */ (int)NUM_SCOPE_PARAMS, asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask, /* Interface mask */ asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask, /* Interrupt mask */ 0, /* asynFlags. This driver does not block and it is not multi-device, so flag is 0 */ 1, /* Autoconnect */ 0, /* Default priority */ 0) /* Default stack size*/ { asynStatus status; int i; const char *functionName = "testAsynPortDriver"; /* Make sure maxPoints is positive */ if (maxPoints < 1) maxPoints = 100; /* Allocate the waveform array */ pData_ = (epicsFloat64 *)calloc(maxPoints, sizeof(epicsFloat64)); /* Allocate the time base array */ pTimeBase_ = (epicsFloat64 *)calloc(maxPoints, sizeof(epicsFloat64)); /* Set the time base array */ for (i=0; i<maxPoints; i++) pTimeBase_[i] = (double)i / (maxPoints-1) * NUM_DIVISIONS; eventId_ = epicsEventCreate(epicsEventEmpty); createParam(P_RunString, asynParamInt32, &P_Run); createParam(P_MaxPointsString, asynParamInt32, &P_MaxPoints); createParam(P_TimePerDivString, asynParamFloat64, &P_TimePerDiv); createParam(P_TimePerDivSelectString, asynParamInt32, &P_TimePerDivSelect); createParam(P_VertGainString, asynParamFloat64, &P_VertGain); createParam(P_VertGainSelectString, asynParamInt32, &P_VertGainSelect); createParam(P_VoltsPerDivString, asynParamFloat64, &P_VoltsPerDiv); createParam(P_VoltsPerDivSelectString, asynParamInt32, &P_VoltsPerDivSelect); createParam(P_VoltOffsetString, asynParamFloat64, &P_VoltOffset); createParam(P_TriggerDelayString, asynParamFloat64, &P_TriggerDelay); createParam(P_NoiseAmplitudeString, asynParamFloat64, &P_NoiseAmplitude); createParam(P_UpdateTimeString, asynParamFloat64, &P_UpdateTime); createParam(P_WaveformString, asynParamFloat64Array, &P_Waveform); createParam(P_TimeBaseString, asynParamFloat64Array, &P_TimeBase); createParam(P_MinValueString, asynParamFloat64, &P_MinValue); createParam(P_MaxValueString, asynParamFloat64, &P_MaxValue); createParam(P_MeanValueString, asynParamFloat64, &P_MeanValue); for (i=0; i<NUM_VERT_SELECTIONS; i++) { // Compute vertical volts per division in mV voltsPerDivValues_[i] = 0; voltsPerDivStrings_[i] = (char *)calloc(MAX_ENUM_STRING_SIZE, sizeof(char)); voltsPerDivSeverities_[i] = 0; } /* Set the initial values of some parameters */ setIntegerParam(P_MaxPoints, maxPoints); setIntegerParam(P_Run, 0); setIntegerParam(P_VertGainSelect, 10); setVertGain(); setDoubleParam (P_VoltsPerDiv, 1.0); setDoubleParam (P_VoltOffset, 0.0); setDoubleParam (P_TriggerDelay, 0.0); setDoubleParam (P_TimePerDiv, 0.001); setDoubleParam (P_UpdateTime, 0.5); setDoubleParam (P_NoiseAmplitude, 0.1); setDoubleParam (P_MinValue, 0.0); setDoubleParam (P_MaxValue, 0.0); setDoubleParam (P_MeanValue, 0.0); /* Create the thread that computes the waveforms in the background */ status = (asynStatus)(epicsThreadCreate("testAsynPortDriverTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)::simTask, this) == NULL); if (status) { printf("%s:%s: epicsThreadCreate failure\n", driverName, functionName); return; } }