int epicsShareAPI astac(const char *pname,const char *user,const char *location) { DBADDR *paddr; long status; ASCLIENTPVT *pasclientpvt=NULL; dbCommon *precord; dbFldDes *pflddes; char *puser; char *plocation; paddr = dbCalloc(1,sizeof(DBADDR) + sizeof(ASCLIENTPVT)); pasclientpvt = (ASCLIENTPVT *)(paddr + 1); status=dbNameToAddr(pname,paddr); if(status) { errMessage(status,"dbNameToAddr error"); return(1); } precord = paddr->precord; pflddes = paddr->pfldDes; puser = asCalloc(1,strlen(user)+1); strcpy(puser,user); plocation = asCalloc(1,strlen(location)+1); strcpy(plocation,location); status = asAddClient(pasclientpvt,precord->asp, (int)pflddes->as_level,puser,plocation); if(status) { errMessage(status,"asAddClient error"); return(1); } else { asPutClientPvt(*pasclientpvt,(void *)precord->name); asRegisterClientCallback(*pasclientpvt,astacCallback); } return(0); }
static void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32 c, epicsInt32 d) { epicsInt32 buf[4]; epicsInt32 expect[4]; long nReq = NELEMENTS(buf), i; unsigned match; DBADDR addr; expect[0] = a; expect[1] = b; expect[2] = c; expect[3] = d; if (dbNameToAddr(pv, &addr)) testAbort("Unknown PV '%s'", pv); if (dbGet(&addr, DBR_LONG, buf, NULL, &nReq, NULL)) testAbort("Failed to get '%s'", pv); match = elen==nReq; for (i=0; i<nReq && i<elen; i++) { match &= buf[i]==expect[i]; } testOk(match, "dbGet(\"%s\") matches", pv); if (elen!=nReq) testDiag("lengths don't match %ld != %ld", elen, nReq); for (i=0; i<nReq && i<elen; i++) { if(buf[i]!=expect[i]) testDiag("[%ld] -> %d != %d", i, (int)expect[i], (int)buf[i]); } }
long epicsShareAPI dbtpn(char *pname,char *pvalue) { long status; tpnInfo *ptpnInfo; DBADDR *pdbaddr=NULL; putNotify *ppn=NULL; char *psavevalue; int len; len = strlen(pvalue); /*allocate space for value immediately following DBADDR*/ pdbaddr = dbCalloc(1,sizeof(DBADDR) + len+1); psavevalue = (char *)(pdbaddr + 1); strcpy(psavevalue,pvalue); status = dbNameToAddr(pname,pdbaddr); if(status) { errMessage(status, "dbtpn: dbNameToAddr"); free((void *)pdbaddr); return(-1); } ppn = dbCalloc(1,sizeof(putNotify)); ppn->paddr = pdbaddr; ppn->pbuffer = psavevalue; ppn->nRequest = 1; ppn->dbrType = DBR_STRING; ppn->userCallback = dbtpnCallback; ptpnInfo = dbCalloc(1,sizeof(tpnInfo)); ptpnInfo->ppn = ppn; ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty); ppn->usrPvt = ptpnInfo; epicsThreadCreate("dbtpn",epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread,ptpnInfo); return(0); }
/* toggle printing after processing a certain record */ long epicsShareAPI dbap(const 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; /* * Toggle print after process field in record */ if (precord->bkpt & BKPT_PRINT_MASK) { printf(" BKPT> Auto print off for record %s\n", precord->name); precord->bkpt &= BKPT_PRINT_OFF_MASK; } else { printf(" BKPT> Auto print on for record %s\n", precord->name); precord->bkpt |= BKPT_PRINT_MASK; } return(0); }
static void checkArrD(const char *pv, long elen, double a, double b, double c, double d) { double buf[4]; double expect[4]; long nReq = NELEMENTS(buf), i; unsigned match; DBADDR addr; expect[0] = a; expect[1] = b; expect[2] = c; expect[3] = d; if (dbNameToAddr(pv, &addr)) testAbort("Unknown PV '%s'", pv); if (dbGet(&addr, DBR_DOUBLE, buf, NULL, &nReq, NULL)) testAbort("Failed to get '%s'", pv); match = elen==nReq; for (i=0; i<nReq && i<elen; i++) { match &= fabs(buf[i]-expect[i])<0.01; } testOk(match, "dbGet(\"%s\") matches", pv); if (elen!=nReq) testDiag("lengths don't match %ld != %ld", elen, nReq); for (i=0; i<nReq && i<elen; i++) { if (fabs(buf[i]-expect[i])>=0.01) testDiag("[%ld] -> %f != %f", i, expect[i], buf[i]); } }
static long initSiWriteRead(stringinRecord *precord) { DBLINK *plink = &precord->inp; devPvt *pdevPvt; asynStatus status; asynUser *pasynUser; asynInterface *pasynInterface; asynOctet *poctet; char *userParam = 0; pdevPvt = callocMustSucceed(1,sizeof(*pdevPvt),"devTestBlock::initCommon"); precord->dpvt = pdevPvt; pdevPvt->precord = (dbCommon *)precord; /* Create asynUser */ pasynUser = pasynManager->createAsynUser(callbackSiWriteRead, 0); pasynUser->userPvt = pdevPvt; pdevPvt->pasynUser = pasynUser; status = pasynEpicsUtils->parseLink(pasynUser, plink, &pdevPvt->portName, &pdevPvt->addr,&userParam); if (status != asynSuccess) { printf("%s devTestBlock::initCommon error in link %s\n", precord->name, pasynUser->errorMessage); goto bad; } /* see if initial VAL is "blockAll" */ if(strcmp(precord->val,"blockAll")==0) pdevPvt->blockAll = 1; /* let queueDelay just be .1*/ pdevPvt->queueDelay = .1; /* Connect to device */ status = pasynManager->connectDevice(pasynUser, pdevPvt->portName, pdevPvt->addr); if (status != asynSuccess) { printf("%s devTestBlock::initCommon connectDevice failed %s\n", precord->name, pasynUser->errorMessage); goto bad; } pasynInterface = pasynManager->findInterface(pasynUser,asynOctetType,1); if(!pasynInterface) { printf("%s devTestBlock::initCommon interface %s not found\n", precord->name,asynOctetType); goto bad; } pdevPvt->poctet = poctet = pasynInterface->pinterface; pdevPvt->octetPvt = pasynInterface->drvPvt; callbackSetCallback(queueItDelayed,&pdevPvt->callback); callbackSetUser(pdevPvt,&pdevPvt->callback); if(dbNameToAddr(userParam,&pdevPvt->dbAddr)) { printf("%s devTestBlock:initDbAddr record %s not present\n", precord->name,userParam); precord->pact = 1; } return(0); bad: precord->pact=1; return(-1); }
static long nameToAddr(const char *pname, DBADDR *paddr) { long status = dbNameToAddr(pname, paddr); if (status) { printf("PV '%s' not found\n", pname); } return status; }
bool DbPvPut::init(PVStructure::shared_pointer const &pvRequest) { propertyMask = dbUtil->getProperties( channelPutRequester, pvRequest, dbAddr, true); if(propertyMask==dbUtil->noAccessBit) return false; if(propertyMask==dbUtil->noModBit) { channelPutRequester->message( "field not allowed to be changed",errorMessage); return 0; } pvStructure = PVStructure::shared_pointer( dbUtil->createPVStructure( channelPutRequester, propertyMask, dbAddr, pvRequest)); if (!pvStructure.get()) return false; if (propertyMask & dbUtil->dbPutBit) { if (propertyMask & dbUtil->processBit) { channelPutRequester->message( "process determined by dbPutField", errorMessage); } } else if (propertyMask&dbUtil->processBit) { process = true; pNotify.reset(new (struct putNotify)()); notifyAddr.reset(new DbAddr()); memcpy(notifyAddr.get(), &dbAddr, sizeof(DbAddr)); DbAddr *paddr = notifyAddr.get(); struct dbCommon *precord = paddr->precord; char buffer[sizeof(precord->name) + 10]; strcpy(buffer, precord->name); strcat(buffer, ".PROC"); if (dbNameToAddr(buffer, paddr)) { throw std::logic_error("dbNameToAddr failed"); } struct putNotify *pn = pNotify.get(); pn->userCallback = this->notifyCallback; pn->paddr = paddr; pn->nRequest = 1; pn->dbrType = DBR_CHAR; pn->usrPvt = this; if (propertyMask & dbUtil->blockBit) block = true; } int numFields = pvStructure->getNumberFields(); bitSet.reset(new BitSet(numFields)); channelPutRequester->channelPutConnect( Status::Ok, getPtrSelf(), pvStructure->getStructure()); return true; }
/* * Fills out pnode and precord structures for dbc() and dbs() * MUST LOCK OUT STACK BEFORE ENTRY */ static long FIND_CONT_NODE( const char *record_name, struct LS_LIST **ppnode, struct dbCommon **pprecord) { struct dbAddr addr; struct LS_LIST *pnode; struct dbCommon *precord = NULL; long status = 0; if (record_name == NULL) { /* * Search through stack, taking the first entry that * is currently stopped at a breakpoint. */ pnode = (struct LS_LIST *) ellFirst(&lset_stack); while (pnode != NULL) { if (pnode->precord != NULL) { precord = pnode->precord; break; } pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode); } if (pnode == NULL) { printf(" BKPT> No records are currently stopped\n"); return(S_db_notStopped); } } else { /* * 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; FIND_LOCKSET(precord, pnode); if (pnode == NULL || pnode->precord == NULL) { printf(" BKPT> Currently not stopped in this lockset\n"); return(S_db_notStopped); } } *pprecord = precord; *ppnode = pnode; return(0); }
LOCAL int connect(void **pab1771IXPvt,DBLINK *plink,boolean *isEng) { DBENTRY dbEntry; DBENTRY *pdbEntry = &dbEntry; DBADDR dbAddr; deviceData *pdeviceData; ab1771IXRecord *precord; recordPvt *precordPvt; long status; char buffer[MAX_BUFFER]; char *recordname = &buffer[0]; char *pstring; unsigned short signal; char *pLeftbracket; char *pRightbracket; if(plink->type!=INST_IO) return(ab1771IXFatalError); pstring = plink->value.instio.string; if(strlen(pstring)>=MAX_BUFFER) return(ab1771IXFatalError); strcpy(buffer,pstring); pLeftbracket = strchr(buffer,'['); pRightbracket = strchr(buffer,']'); if(!pLeftbracket || !pRightbracket) { errlogPrintf("link was not of the form record[signal]\n"); return(ab1771IXFatalError); } *pLeftbracket++ = '\0'; *pRightbracket = '\0'; sscanf(pLeftbracket,"%hu",&signal); dbInitEntry(pdbbase,pdbEntry); status = dbFindRecord(pdbEntry,recordname); if(status) return(ab1771IXNoRecord); if(strcmp(dbGetRecordTypeName(pdbEntry),"ab1771IX")!=0) return(ab1771IXIllegalRecordType); dbFinishEntry(pdbEntry); status = dbNameToAddr(recordname,&dbAddr); if(status) return(ab1771IXNoRecord); precord = (ab1771IXRecord *)dbAddr.precord; if(!(precordPvt = (recordPvt *)precord->dpvt)) { printf("%s precordPvt is NULL ?\n",precord->name); return(ab1771IXFatalError); } if(signal>=NUM_CHANS) return(ab1771IXIllegalType); if(signal<=3) { *isEng = ((precord->typa==ab1771IX_TYPE_MV)?FALSE:TRUE); } else { *isEng = ((precord->typb==ab1771IX_TYPE_MV)?FALSE:TRUE); } pdeviceData = dbCalloc(1,sizeof(deviceData)); pdeviceData->precord = precord; pdeviceData->signal = signal; *pab1771IXPvt = (void *)pdeviceData; return(ab1771IXOK); }
/*utility routine to dump raw messages*/ int ab1771IXpm(char *recordname) { DBENTRY dbEntry; DBENTRY *pdbEntry = &dbEntry; DBADDR dbAddr; ab1771IXRecord *precord; recordPvt *precordPvt; long status; short *pdata; int i; dbInitEntry(pdbbase,pdbEntry); status = dbFindRecord(pdbEntry,recordname); if(status) { printf("Cant find %s\n",recordname); return(0); } if(strcmp(dbGetRecordTypeName(pdbEntry),"ab1771IX")!=0) { printf("Not a ab1771IXRecord\n"); return(0); } dbFinishEntry(pdbEntry); status = dbNameToAddr(recordname,&dbAddr); if(status) { printf("Cant find %s\n",recordname); return(0); } precord = (ab1771IXRecord *)dbAddr.precord; if(!(precordPvt = (recordPvt *)precord->dpvt)) { printf("dpvt is NULL\n"); return(0); } printf("output message"); pdata = precord->outm; for(i=0; i< NUM_WORDS_OUT; i++) { if(i%10 == 0) printf("\n"); printf(" %4hx",*pdata); pdata++; } printf("\ninput message"); pdata = precord->inpm; for(i=0; i< NUM_WORDS_IN; i++) { if(i%10 == 0) printf("\n"); printf(" %4hx",*pdata); pdata++; } printf("\n"); return(0); }
static long init_record_subArray( subArrayRecord *pior) { /* parse device dependent option string and set data pointer */ struct dbAddr *pWfDbAddr; waveformRecord *pwf; dbNameToAddr(pior->inp.value.constantStr, pWfDbAddr); pwf = (waveformRecord*) pWfDbAddr->precord; if( pwf == 0 ) { printf(__FILE__":%d: Error Can't find %s \n", __LINE__, pior->inp.value.constantStr); exit(1); } pior->dpvt = (void*) pwf; return(0); }
ChannelFind::shared_pointer DbPvProvider::channelFind( string const & channelName, ChannelFindRequester::shared_pointer const &channelFindRequester) { struct dbAddr dbAddr; long result = dbNameToAddr(channelName.c_str(),&dbAddr); if(result==0) { channelFindRequester->channelFindResult( Status::Ok, channelFinder, true); } else { Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found"); channelFindRequester.get()->channelFindResult( notFoundStatus, channelFinder, false); } return channelFinder; }
void mdsPlusShotID(int param) { int status; char buf[40]; DBADDR *paddr; paddr = (DBADDR *)dbCalloc(1, sizeof(struct dbAddr)); /* sleep */ epicsThreadSleep(2.0); /*status = dbPutLink(shotIdOutLink, DBR_LONG, &shotId, 1);*/ /* Put next pulse number */ sprintf(buf, "icrf:pulseid.VAL"); status = dbNameToAddr(buf, paddr); status = dbPutField(paddr, DBR_LONG, &shotId, 1); free(paddr); if(genSubDebug > 0) printf("genSub: mdsPlusShotID() next shot number [%ld]. Status=%d\n",shotId,status); }
/* Try to parse scan period from record's SCAN field. * Sounds simple, but I ended up with this mess. * Is there a more elegant way to get this? * Returns <= 0 for error. */ static double get_period(dbCommon *rec) { char *buf = 0, *p; size_t buf_size = 0, len; struct dbAddr scan_field; long options=0, count=1; double period = -1.0; if (rec->scan < SCAN_1ST_PERIODIC) return period; /* Best guess for holding SCAN field name and value */ if (! EIP_reserve_buffer((void**)&buf, &buf_size, 50)) return period; /* Get SCAN field's address */ len = strlen (rec->name); if (! EIP_reserve_buffer((void**)&buf, &buf_size, len+6)) goto leave; memcpy(buf, rec->name, len); memcpy(buf+len, ".SCAN", 6); if (dbNameToAddr(buf, &scan_field) != 0) goto leave; /* Get value */ len = dbBufferSize(DBR_STRING, options, count); if (! EIP_reserve_buffer((void**)&buf, &buf_size, len)) goto leave; if (dbGet(&scan_field, DBR_STRING, buf, &options, &count, 0) != 0) goto leave; if (! strstr(buf, "second")) goto leave; period = strtod(buf, &p); if (p==buf || period==HUGE_VAL || period==-HUGE_VAL) period = -1.0; leave: free(buf); return period; }
static void hookPass1(initHookState state) { DBENTRY entry; DBADDR addr; if(state!=initHookAfterInitDatabase) return; testDiag("initHookAfterInitDatabase"); dbInitEntry(pdbbase, &entry); if(dbFindRecord(&entry, "rec0.VAL")==0) { aoRecord *prec = entry.precnode->precord; testOk(prec->val==3, "VAL %d==3 (init_record value)", (int)prec->val); testOk1(dbPutString(&entry, "4")==0); testOk(prec->val==4, "VAL %d==4", (int)prec->val); } else{ testFail("Missing rec0"); testSkip(1, "missing record"); } /* Can't restore links in pass 1 */ if(dbNameToAddr("rec1.VAL", &addr)) { testFail("missing rec1"); testSkip(3, "missing record"); } else { struct rset *prset = dbGetRset(&addr); dbfType ftype = addr.field_type; long count=-1, offset=-1, maxcount = addr.no_elements; testOk1(prset && prset->get_array_info && prset->put_array_info); testOk1((*prset->get_array_info)(&addr, &count, &offset)==0); /* count is ignored */ testOk1((*dbPutConvertRoutine[DBF_DOUBLE][ftype])(&addr, values, NELEMENTS(values), maxcount,offset)==0); testOk1((*prset->put_array_info)(&addr, NELEMENTS(values))==0); } dbFinishEntry(&entry); }
/* * 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); }
Channel::shared_pointer DbPvProvider::createChannel( string const & channelName, ChannelRequester::shared_pointer const &channelRequester, short priority, string const & address) { struct dbAddr dbAddr; long result = dbNameToAddr(channelName.c_str(),&dbAddr); if(result!=0) { Status notFoundStatus(Status::STATUSTYPE_ERROR,"pv not found"); channelRequester->channelCreated( notFoundStatus, Channel::shared_pointer()); return Channel::shared_pointer(); } std::tr1::shared_ptr<DbAddr> addr(new DbAddr()); memcpy(addr.get(),&dbAddr,sizeof(dbAddr)); DbPvPtr v3Channel(new DbPv( getPtrSelf(), channelRequester,channelName,addr)); v3Channel->init(); channelRequester->channelCreated(Status::Ok,v3Channel); return v3Channel; }
static void checkLinks(acalcoutRecord *pcalc) { DBLINK *plink; rpvtStruct *prpvt = (rpvtStruct *)pcalc->rpvt; int i; int isCaLink = 0; int isCaLinkNc = 0; unsigned short *plinkValid; dbAddr Addr; dbAddr *pAddr = &Addr; if (aCalcoutRecordDebug >= 10) printf("checkLinks() for %p\n", (void *)pcalc); plink = &pcalc->inpa; plinkValid = &pcalc->inav; for (i=0; i<MAX_FIELDS+ARRAY_MAX_FIELDS+1; i++, plink++, plinkValid++) { if (plink->type == CA_LINK) { isCaLink = 1; if (dbCaIsLinkConnected(plink)) { if (*plinkValid == acalcoutINAV_EXT_NC) { *plinkValid = acalcoutINAV_EXT; db_post_events(pcalc,plinkValid,DBE_VALUE); } /* If this is the outlink, get the type of field it's connected to. If it's connected * to a link field, and the outlink is not a CA link, complain, because this won't work. * Also, if .WAIT, then the link must be a CA link. */ if (plink == &pcalc->out) { prpvt->outlink_field_type = dbCaGetLinkDBFtype(plink); if (aCalcoutRecordDebug >= 10) printf("acalcout:checkLinks: outlink type = %d\n", prpvt->outlink_field_type); if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { if ((pAddr->field_type >= DBF_INLINK) && (pAddr->field_type <= DBF_FWDLINK)) { if (!(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):checkLinks:non-CA link to link field\n", plink->value.pv_link.pvname); } } } if (pcalc->wait && !(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):checkLinks: Can't wait with non-CA link attribute\n", plink->value.pv_link.pvname); } } } else { if (*plinkValid == acalcoutINAV_EXT_NC) { isCaLinkNc = 1; } else if (*plinkValid == acalcoutINAV_EXT) { *plinkValid = acalcoutINAV_EXT_NC; db_post_events(pcalc,plinkValid,DBE_VALUE); isCaLinkNc = 1; } if (plink == &pcalc->out) prpvt->outlink_field_type = DBF_NOACCESS; /* don't know type */ } } } if (isCaLinkNc) prpvt->caLinkStat = CA_LINKS_NOT_OK; else if (isCaLink) prpvt->caLinkStat = CA_LINKS_ALL_OK; else prpvt->caLinkStat = NO_CA_LINKS; if (!prpvt->wd_id_1_LOCK && isCaLinkNc) { /* Schedule another CALLBACK */ prpvt->wd_id_1_LOCK = 1; callbackRequestDelayed(&prpvt->checkLinkCb,.5); } }
static void check(short dbr_type) { dbChannel *pch; db_field_log *pfl, *pfl2; dbAddr valaddr; dbAddr offaddr; const char *offname = NULL, *valname = NULL, *typname = NULL; epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19}; epicsInt32 *ar10_0_1 = ar; epicsInt32 ar10_4_1[10] = {14,15,16,17,18,19,10,11,12,13}; epicsInt32 ar5_0_1[10] = {12,13,14,15,16}; epicsInt32 ar5_3_1[10] = {15,16,17,18,19}; epicsInt32 ar5_5_1[10] = {17,18,19,10,11}; epicsInt32 ar5_9_1[10] = {11,12,13,14,15}; epicsInt32 ar5_0_2[10] = {12,14,16}; epicsInt32 ar5_3_2[10] = {15,17,19}; epicsInt32 ar5_5_2[10] = {17,19,11}; epicsInt32 ar5_9_2[10] = {11,13,15}; epicsInt32 ar5_0_3[10] = {12,15}; epicsInt32 ar5_3_3[10] = {15,18}; epicsInt32 ar5_5_3[10] = {17,10}; epicsInt32 ar5_9_3[10] = {11,14}; epicsInt32 off = 0; switch (dbr_type) { case DBR_LONG: offname = "x.OFF"; valname = "x.VAL"; typname = "long"; break; case DBR_DOUBLE: offname = "y.OFF"; valname = "y.VAL"; typname = "double"; break; case DBR_STRING: offname = "z.OFF"; valname = "z.VAL"; typname = "string"; break; default: testDiag("Invalid data type %d", dbr_type); } (void) dbNameToAddr(offname, &offaddr); (void) dbNameToAddr(valname, &valaddr); (void) dbPutField(&valaddr, DBR_LONG, ar, 10); /* Default: should not change anything */ testHead("Ten %s elements from rec, increment 1, full size (default)", typname); createAndOpen(valname, "{\"arr\":{}}", "(default)", &pch, 1); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); TEST1(10, 0, 1, "no offset"); TEST1(10, 4, 1, "wrapped"); dbChannelDelete(pch); testHead("Ten %s elements from rec, increment 1, out-of-bound start parameter", typname); createAndOpen(valname, "{\"arr\":{\"s\":-500}}", "out-of-bound start", &pch, 1); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); TEST1(10, 4, 1, "wrapped"); dbChannelDelete(pch); testHead("Ten %s elements from rec, increment 1, out-of-bound end parameter", typname); createAndOpen(valname, "{\"arr\":{\"e\":500}}", "out-of-bound end", &pch, 1); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); TEST1(10, 4, 1, "wrapped"); dbChannelDelete(pch); testHead("Ten %s elements from rec, increment 1, zero increment parameter", typname); createAndOpen(valname, "{\"arr\":{\"i\":0}}", "zero increment", &pch, 1); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); TEST1(10, 4, 1, "wrapped"); dbChannelDelete(pch); testHead("Ten %s elements from rec, increment 1, invalid increment parameter", typname); createAndOpen(valname, "{\"arr\":{\"i\":-30}}", "invalid increment", &pch, 1); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); TEST1(10, 4, 1, "wrapped"); dbChannelDelete(pch); #define TEST5(Incr, Left, Right, Type) \ testHead("Five %s elements from rec, increment " #Incr ", " Type " addressing", typname); \ createAndOpen(valname, "{\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \ "(" #Left ":" #Incr ":" #Right ")", &pch, 1); \ testOk(pch->final_type == valaddr.field_type, \ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \ testOk(pch->final_no_elements == 4 / Incr + 1, \ "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \ TEST1(5, 0, Incr, "no offset"); \ TEST1(5, 3, Incr, "from upper block"); \ TEST1(5, 5, Incr, "wrapped"); \ TEST1(5, 9, Incr, "from lower block"); \ dbChannelDelete(pch); /* Contiguous block of 5 */ TEST5(1, 2, 6, "regular"); TEST5(1, -8, 6, "left side from-end"); TEST5(1, 2, -4, "right side from-end"); TEST5(1, -8, -4, "both sides from-end"); /* 5 elements with increment 2 */ TEST5(2, 2, 6, "regular"); TEST5(2, -8, 6, "left side from-end"); TEST5(2, 2, -4, "right side from-end"); TEST5(2, -8, -4, "both sides from-end"); /* 5 elements with increment 3 */ TEST5(3, 2, 6, "regular"); TEST5(3, -8, 6, "left side from-end"); TEST5(3, 2, -4, "right side from-end"); TEST5(3, -8, -4, "both sides from-end"); /* From buffer (plugin chain) */ #define TEST5B(Incr, Left, Right, Type) \ testHead("Five %s elements from buffer, increment " #Incr ", " Type " addressing", typname); \ createAndOpen(valname, "{\"arr\":{},\"arr\":{\"s\":" #Left ",\"e\":" #Right ",\"i\":" #Incr "}}", \ "(" #Left ":" #Incr ":" #Right ")", &pch, 2); \ testOk(pch->final_type == valaddr.field_type, \ "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); \ testOk(pch->final_no_elements == 4 / Incr + 1, \ "final no_elements correct (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); \ TEST1(5, 0, Incr, "no offset"); \ dbChannelDelete(pch); /* Contiguous block of 5 */ TEST5B(1, 2, 6, "regular"); TEST5B(1, -8, 6, "left side from-end"); TEST5B(1, 2, -4, "right side from-end"); TEST5B(1, -8, -4, "both sides from-end"); /* 5 elements with increment 2 */ TEST5B(2, 2, 6, "regular"); TEST5B(2, -8, 6, "left side from-end"); TEST5B(2, 2, -4, "right side from-end"); TEST5B(2, -8, -4, "both sides from-end"); /* 5 elements with increment 3 */ TEST5B(3, 2, 6, "regular"); TEST5B(3, -8, 6, "left side from-end"); TEST5B(3, 2, -4, "right side from-end"); TEST5B(3, -8, -4, "both sides from-end"); }
static long dbPutFieldLink(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest) { dbLinkInfo link_info; DBADDR *pdbaddr = NULL; dbCommon *precord = paddr->precord; dbCommon *lockrecs[2]; dbLocker locker; dbFldDes *pfldDes = paddr->pfldDes; long special = paddr->special; struct link *plink = (struct link *)paddr->pfield; const char *pstring = (const char *)pbuffer; struct dsxt *old_dsxt = NULL; struct dset *new_dset = NULL; struct dsxt *new_dsxt = NULL; devSup *new_devsup = NULL; long status; int isDevLink; short scan; STATIC_ASSERT(DBLOCKER_NALLOC>=2); switch (dbrType) { case DBR_CHAR: case DBR_UCHAR: if (pstring[nRequest - 1] != '\0') return S_db_badDbrtype; break; case DBR_STRING: break; default: return S_db_badDbrtype; } status = dbParseLink(pstring, pfldDes->field_type, &link_info); if (status) return status; if (link_info.ltype == PV_LINK && (link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) { DBADDR tempaddr; if (dbNameToAddr(link_info.target, &tempaddr)==0) { /* This will become a DB link. */ pdbaddr = malloc(sizeof(*pdbaddr)); if (!pdbaddr) { status = S_db_noMemory; goto cleanup; } *pdbaddr = tempaddr; /* struct copy */ } } isDevLink = ellCount(&precord->rdes->devList) > 0 && pfldDes->isDevLink; memset(&locker, 0, sizeof(locker)); lockrecs[0] = precord; lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL; dbLockerPrepare(&locker, lockrecs, 2); dbScanLockMany(&locker); scan = precord->scan; if (isDevLink) { new_devsup = dbDTYPtoDevSup(precord->rdes, precord->dtyp); if (new_devsup) { new_dset = new_devsup->pdset; new_dsxt = new_devsup->pdsxt; } } if (dbCanSetLink(plink, &link_info, new_devsup)) { /* link type mis-match prevents assignment */ status = S_dbLib_badField; goto unlock; } if (isDevLink) { if (precord->dset) { devSup *old_devsup = dbDSETtoDevSup(precord->rdes, precord->dset); if (old_devsup) old_dsxt = old_devsup->pdsxt; } if (new_dsxt == NULL || new_dsxt->add_record == NULL || (precord->dset && old_dsxt == NULL) || (old_dsxt && old_dsxt->del_record == NULL)) { status = S_db_noSupport; goto unlock; } if (scan == menuScanI_O_Intr) { scanDelete(precord); precord->scan = menuScanPassive; } if (old_dsxt) { status = old_dsxt->del_record(precord); if (status) goto restoreScan; } } switch (plink->type) { /* Old link type */ case DB_LINK: case CA_LINK: case CONSTANT: dbRemoveLink(&locker, plink); /* link type becomes PV_LINK */ break; case PV_LINK: case MACRO_LINK: break; /* should never get here */ default: /* Hardware address */ if (!isDevLink) { status = S_db_badHWaddr; goto restoreScan; } break; } if (special) status = dbPutSpecial(paddr, 0); if (!status) status = dbSetLink(plink, &link_info, new_devsup); if (!status && special) status = dbPutSpecial(paddr, 1); if (status) { if (isDevLink) { precord->dset = NULL; precord->pact = TRUE; } goto postScanEvent; } if (isDevLink) { precord->dpvt = NULL; precord->dset = new_dset; precord->pact = FALSE; status = new_dsxt->add_record(precord); if (status) { precord->dset = NULL; precord->pact = TRUE; goto postScanEvent; } } switch (plink->type) { /* New link type */ case PV_LINK: case CONSTANT: dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr); break; case DB_LINK: case CA_LINK: case MACRO_LINK: break; /* should never get here */ default: /* Hardware address */ if (!isDevLink) { status = S_db_badHWaddr; goto postScanEvent; } break; } db_post_events(precord, plink, DBE_VALUE | DBE_LOG); restoreScan: if (isDevLink && scan == menuScanI_O_Intr) { /* undo scanDelete() */ precord->scan = scan; scanAdd(precord); } postScanEvent: if (scan != precord->scan) db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG); unlock: dbScanUnlockMany(&locker); dbLockerFinalize(&locker); cleanup: free(link_info.target); return status; }
static void check(short dbr_type) { dbChannel *pch; db_field_log *pfl; dbAddr valaddr; dbAddr offaddr; const char *offname = NULL, *valname = NULL, *typname = NULL; epicsInt32 buf[26]; long off, req; int i; switch (dbr_type) { case DBR_LONG: offname = "i32.OFF"; valname = "i32.VAL"; typname = "long"; break; case DBR_DOUBLE: offname = "f64.OFF"; valname = "f64.VAL"; typname = "double"; break; case DBR_STRING: offname = "c40.OFF"; valname = "c40.VAL"; typname = "string"; break; default: testDiag("Invalid data type %d", dbr_type); } (void) dbNameToAddr(offname, &offaddr); (void) dbNameToAddr(valname, &valaddr); testHead("Ten %s elements", typname); /* Fill the record's array field with data, 10..19 */ epicsInt32 ar[10] = {10,11,12,13,14,15,16,17,18,19}; (void) dbPutField(&valaddr, DBR_LONG, ar, 10); /* Open a channel to it, make sure no filters present */ createAndOpen(valname, &pch); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); /* TEST1 sets the record's OFF field, then requests 10 elements from the channel, * passing in a transparent db_field_log and converting the data to LONG on the way in. * It checks that it got back the expected data and the right number of elements. */ #define TEST1(Size, Offset, Text, Expected) \ testDiag("Reading from offset = %d (%s)", Offset, Text); \ off = Offset; req = 10; \ memset(buf, 0, sizeof(buf)); \ (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ pfl = db_create_read_log(pch); \ testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \ testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \ if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \ for (i=0; i<Size; i++) \ testDiag("Element %d expected %d got %d", i, Expected[i], buf[i]); \ db_delete_field_log(pfl); const epicsInt32 res_10_0[] = {10,11,12,13,14,15,16,17,18,19}; TEST1(10, 0, "no offset", res_10_0); const epicsInt32 res_10_4[] = {14,15,16,17,18,19,10,11,12,13}; TEST1(10, 4, "wrapped", res_10_4); /* Partial array */ testHead("Five %s elements", typname); off = 0; /* Reset offset for writing the next buffer */ (void) dbPutField(&offaddr, DBR_LONG, &off, 1); (void) dbPutField(&valaddr, DBR_LONG, &ar[5], 5); createAndOpen(valname, &pch); testOk(pch->final_type == valaddr.field_type, "final type unchanged (%d->%d)", valaddr.field_type, pch->final_type); testOk(pch->final_no_elements == valaddr.no_elements, "final no_elements unchanged (%ld->%ld)", valaddr.no_elements, pch->final_no_elements); const epicsInt32 res_5_0[] = {15,16,17,18,19}; TEST1(5, 0, "no offset", res_5_0); const epicsInt32 res_5_3[] = {18,19,15,16,17}; TEST1(5, 3, "wrapped", res_5_3); /* TEST2 sets the record's OFF field, then requests 15 elements from the channel * but passes in a db_field_log with alternate data, converting that data to LONG. * It checks that it got back the expected data and the right number of elements. */ #define TEST2(Size, Offset, Text, Expected) \ testDiag("Reading from offset = %d (%s)", Offset, Text); \ off = Offset; req = 15; \ memset(buf, 0, sizeof(buf)); \ (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ pfl = db_create_read_log(pch); \ pfl->type = dbfl_type_ref; \ pfl->field_type = DBF_CHAR; \ pfl->field_size = 1; \ pfl->no_elements = 26; \ pfl->u.r.dtor = freeArray; \ pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \ testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \ if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \ for (i=0; i<Size; i++) \ testDiag("Element %d expected '%c' got '%c'", i, Expected[i], buf[i]); \ db_delete_field_log(pfl); testHead("Fifteen letters from field-log instead of %s", typname); const epicsInt32 res_15[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'}; TEST2(15, 0, "no offset", res_15); TEST2(15, 10, "ignored", res_15); dbChannelDelete(pch); }
static long init_record(acalcoutRecord *pcalc, int pass) { DBLINK *plink; int i; double *pvalue; unsigned short *plinkValid; short error_number; acalcoutDSET *pacalcoutDSET; dbAddr Addr; dbAddr *pAddr = &Addr; rpvtStruct *prpvt; if (pass==0) { pcalc->vers = VERSION; pcalc->rpvt = (void *)calloc(1, sizeof(struct rpvtStruct)); if ((pcalc->nuse < 0) || (pcalc->nuse > pcalc->nelm)) { pcalc->nuse = pcalc->nelm; db_post_events(pcalc,&pcalc->nuse,DBE_VALUE|DBE_LOG); } return(0); } if (!(pacalcoutDSET = (acalcoutDSET *)pcalc->dset)) { recGblRecordError(S_dev_noDSET,(void *)pcalc,"acalcout:init_record"); return(S_dev_noDSET); } /* must have write defined */ if ((pacalcoutDSET->number < 5) || (pacalcoutDSET->write == NULL)) { recGblRecordError(S_dev_missingSup,(void *)pcalc,"acalcout:init_record"); return(S_dev_missingSup); } prpvt = (rpvtStruct *)pcalc->rpvt; plink = &pcalc->inpa; pvalue = &pcalc->a; plinkValid = &pcalc->inav; for (i=0; i<(MAX_FIELDS+ARRAY_MAX_FIELDS+1); i++, plink++, pvalue++, plinkValid++) { if (plink->type == CONSTANT) { /* Don't InitConstantLink the array links or the output link. */ if (i < MAX_FIELDS) { recGblInitConstantLink(plink,DBF_DOUBLE,pvalue); db_post_events(pcalc,pvalue,DBE_VALUE); } *plinkValid = acalcoutINAV_CON; if (plink == &pcalc->out) prpvt->outlink_field_type = DBF_NOACCESS; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* the PV we're linked to resides on this ioc */ *plinkValid = acalcoutINAV_LOC; if (plink == &pcalc->out) { prpvt->outlink_field_type = pAddr->field_type; if ((pAddr->field_type >= DBF_INLINK) && (pAddr->field_type <= DBF_FWDLINK)) { if (!(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):init_record:non-CA link to link field\n", plink->value.pv_link.pvname); } } if (pcalc->wait && !(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):init_record: Can't wait with non-CA link attribute\n", plink->value.pv_link.pvname); } } } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = acalcoutINAV_EXT_NC; prpvt->caLinkStat = CA_LINKS_NOT_OK; if (plink == &pcalc->out) prpvt->outlink_field_type = DBF_NOACCESS; /* don't know field type */ } db_post_events(pcalc,plinkValid,DBE_VALUE); } pcalc->clcv = aCalcPostfix(pcalc->calc,pcalc->rpcl,&error_number); if (pcalc->clcv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: init_record: Illegal CALC field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->clcv,DBE_VALUE); pcalc->oclv = aCalcPostfix(pcalc->ocal, pcalc->orpc,&error_number); if (pcalc->oclv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: init_record: Illegal OCAL field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->oclv,DBE_VALUE); callbackSetCallback(checkLinksCallback, &prpvt->checkLinkCb); callbackSetPriority(0, &prpvt->checkLinkCb); callbackSetUser(pcalc, &prpvt->checkLinkCb); prpvt->wd_id_1_LOCK = 0; if (prpvt->caLinkStat == CA_LINKS_NOT_OK) { callbackRequestDelayed(&prpvt->checkLinkCb,1.0); prpvt->wd_id_1_LOCK = 1; } if (pacalcoutDSET->init_record ) { return (*pacalcoutDSET->init_record)(pcalc); } return(0); }
static long special(DBADDR *paddr, int after) { calcoutRecord *prec = (calcoutRecord *)paddr->precord; rpvtStruct *prpvt = prec->rpvt; DBADDR dbaddr; DBADDR *pAddr = &dbaddr; short error_number; int fieldIndex = dbGetFieldIndex(paddr); int lnkIndex; DBLINK *plink; double *pvalue; epicsEnum16 *plinkValid; if (!after) return 0; switch(fieldIndex) { case(calcoutRecordCALC): prec->clcv = postfix(prec->calc, prec->rpcl, &error_number); if (prec->clcv){ recGblRecordError(S_db_badField, (void *)prec, "calcout: special(): Illegal CALC field"); errlogPrintf("%s.CALC: %s in expression \"%s\"\n", prec->name, calcErrorStr(error_number), prec->calc); } db_post_events(prec, &prec->clcv, DBE_VALUE); return 0; case(calcoutRecordOCAL): prec->oclv = postfix(prec->ocal, prec->orpc, &error_number); if (prec->dopt == calcoutDOPT_Use_OVAL && prec->oclv){ recGblRecordError(S_db_badField, (void *)prec, "calcout: special(): Illegal OCAL field"); errlogPrintf("%s.OCAL: %s in expression \"%s\"\n", prec->name, calcErrorStr(error_number), prec->ocal); } db_post_events(prec, &prec->oclv, DBE_VALUE); return 0; case(calcoutRecordINPA): case(calcoutRecordINPB): case(calcoutRecordINPC): case(calcoutRecordINPD): case(calcoutRecordINPE): case(calcoutRecordINPF): case(calcoutRecordINPG): case(calcoutRecordINPH): case(calcoutRecordINPI): case(calcoutRecordINPJ): case(calcoutRecordINPK): case(calcoutRecordINPL): case(calcoutRecordOUT): lnkIndex = fieldIndex - calcoutRecordINPA; plink = &prec->inpa + lnkIndex; pvalue = &prec->a + lnkIndex; plinkValid = &prec->inav + lnkIndex; if (plink->type == CONSTANT) { if (fieldIndex != calcoutRecordOUT) { recGblInitConstantLink(plink, DBF_DOUBLE, pvalue); db_post_events(prec, pvalue, DBE_VALUE); } *plinkValid = calcoutINAV_CON; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* if the PV resides on this ioc */ *plinkValid = calcoutINAV_LOC; } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = calcoutINAV_EXT_NC; /* DO_CALLBACK, if not already scheduled */ if (!prpvt->cbScheduled) { callbackRequestDelayed(&prpvt->checkLinkCb, .5); prpvt->cbScheduled = 1; prpvt->caLinkStat = CA_LINKS_NOT_OK; } } db_post_events(prec, plinkValid, DBE_VALUE); return 0; case(calcoutRecordOEVT): prec->epvt = eventNameToHandle(prec->oevt); return 0; default: recGblDbaddrError(S_db_badChoice, paddr, "calc: special"); return(S_db_badChoice); } }
static long init_record(calcoutRecord *prec, int pass) { DBLINK *plink; int i; double *pvalue; epicsEnum16 *plinkValid; short error_number; calcoutDSET *pcalcoutDSET; DBADDR dbaddr; DBADDR *pAddr = &dbaddr; rpvtStruct *prpvt; if (pass == 0) { prec->rpvt = (rpvtStruct *) callocMustSucceed(1, sizeof(rpvtStruct), "calcoutRecord"); return 0; } if (!(pcalcoutDSET = (calcoutDSET *)prec->dset)) { recGblRecordError(S_dev_noDSET, (void *)prec, "calcout:init_record"); return S_dev_noDSET; } /* must have write defined */ if ((pcalcoutDSET->number < 5) || (pcalcoutDSET->write ==NULL)) { recGblRecordError(S_dev_missingSup, (void *)prec, "calcout:init_record"); return S_dev_missingSup; } prpvt = prec->rpvt; plink = &prec->inpa; pvalue = &prec->a; plinkValid = &prec->inav; for (i = 0; i <= CALCPERFORM_NARGS; i++, plink++, pvalue++, plinkValid++) { if (plink->type == CONSTANT) { /* Don't InitConstantLink the .OUT link */ if (i < CALCPERFORM_NARGS) { recGblInitConstantLink(plink, DBF_DOUBLE, pvalue); } *plinkValid = calcoutINAV_CON; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* PV resides on this ioc */ *plinkValid = calcoutINAV_LOC; } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = calcoutINAV_EXT_NC; prpvt->caLinkStat = CA_LINKS_NOT_OK; } } prec->clcv = postfix(prec->calc, prec->rpcl, &error_number); if (prec->clcv){ recGblRecordError(S_db_badField, (void *)prec, "calcout: init_record: Illegal CALC field"); errlogPrintf("%s.CALC: %s in expression \"%s\"\n", prec->name, calcErrorStr(error_number), prec->calc); } prec->oclv = postfix(prec->ocal, prec->orpc, &error_number); if (prec->dopt == calcoutDOPT_Use_OVAL && prec->oclv){ recGblRecordError(S_db_badField, (void *)prec, "calcout: init_record: Illegal OCAL field"); errlogPrintf("%s.OCAL: %s in expression \"%s\"\n", prec->name, calcErrorStr(error_number), prec->ocal); } prpvt = prec->rpvt; callbackSetCallback(checkLinksCallback, &prpvt->checkLinkCb); callbackSetPriority(0, &prpvt->checkLinkCb); callbackSetUser(prec, &prpvt->checkLinkCb); prpvt->cbScheduled = 0; prec->epvt = eventNameToHandle(prec->oevt); if (pcalcoutDSET->init_record) pcalcoutDSET->init_record(prec); prec->pval = prec->val; prec->mlst = prec->val; prec->alst = prec->val; prec->lalm = prec->val; prec->povl = prec->oval; return 0; }
/* * 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); }
static long dbPutFieldLink(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest) { dbCommon *precord = paddr->precord; dbFldDes *pfldDes = paddr->pfldDes; long special = paddr->special; DBLINK *plink = (DBLINK *)paddr->pfield; const char *pstring = (const char *)pbuffer; DBENTRY dbEntry; DBADDR dbaddr; struct dsxt *old_dsxt = NULL; struct dset *new_dset = NULL; struct dsxt *new_dsxt = NULL; long status; int isDevLink; short scan; switch (dbrType) { case DBR_CHAR: case DBR_UCHAR: if (pstring[nRequest - 1] != '\0') return S_db_badDbrtype; break; case DBR_STRING: break; default: return S_db_badDbrtype; } dbInitEntry(pdbbase, &dbEntry); status = dbFindRecord(&dbEntry, precord->name); if (!status) status = dbFindField(&dbEntry, pfldDes->name); if (status) goto finish; isDevLink = ellCount(&precord->rdes->devList) > 0 && (strcmp(pfldDes->name, "INP") == 0 || strcmp(pfldDes->name, "OUT") == 0); dbLockSetGblLock(); dbLockSetRecordLock(precord); scan = precord->scan; if (isDevLink) { devSup *pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp); if (pdevSup) { new_dset = pdevSup->pdset; new_dsxt = pdevSup->pdsxt; } if (precord->dset) { pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset); if (pdevSup) old_dsxt = pdevSup->pdsxt; } if (new_dsxt == NULL || new_dsxt->add_record == NULL || (precord->dset && old_dsxt == NULL) || (old_dsxt && old_dsxt->del_record == NULL)) { status = S_db_noSupport; goto unlock; } if (scan == menuScanI_O_Intr) { scanDelete(precord); precord->scan = menuScanPassive; } if (old_dsxt) { status = old_dsxt->del_record(precord); if (status) goto restoreScan; } } switch (plink->type) { /* Old link type */ case DB_LINK: free(plink->value.pv_link.pvt); plink->value.pv_link.pvt = 0; plink->type = PV_LINK; plink->value.pv_link.getCvt = 0; plink->value.pv_link.pvlMask = 0; plink->value.pv_link.lastGetdbrType = 0; dbLockSetSplit(precord); break; case CA_LINK: dbCaRemoveLink(plink); plink->type = PV_LINK; plink->value.pv_link.getCvt = 0; plink->value.pv_link.pvlMask = 0; plink->value.pv_link.lastGetdbrType = 0; break; case CONSTANT: break; /* do nothing */ case PV_LINK: case MACRO_LINK: break; /* should never get here */ default: /* Hardware address */ if (!isDevLink) { status = S_db_badHWaddr; goto restoreScan; } break; } if (special) status = dbPutSpecial(paddr, 0); if (!status) status = dbPutString(&dbEntry, pstring); if (!status && special) status = dbPutSpecial(paddr, 1); if (status) { if (isDevLink) { precord->dset = NULL; precord->pact = TRUE; } goto postScanEvent; } if (isDevLink) { precord->dpvt = NULL; precord->dset = new_dset; precord->pact = FALSE; status = new_dsxt->add_record(precord); if (status) { precord->dset = NULL; precord->pact = TRUE; goto postScanEvent; } } switch (plink->type) { /* New link type */ case PV_LINK: if (plink == &precord->tsel) recGblTSELwasModified(plink); plink->value.pv_link.precord = precord; if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) && (dbNameToAddr(plink->value.pv_link.pvname, &dbaddr) == 0)) { /* It's a DB link */ DBADDR *pdbAddr; plink->type = DB_LINK; pdbAddr = dbMalloc(sizeof(struct dbAddr)); *pdbAddr = dbaddr; /* NB: structure copy */; plink->value.pv_link.pvt = pdbAddr; dbLockSetRecordLock(pdbAddr->precord); dbLockSetMerge(precord, pdbAddr->precord); } else { /* Make it a CA link */ char *pperiod; plink->type = CA_LINK; if (pfldDes->field_type == DBF_INLINK) { plink->value.pv_link.pvlMask |= pvlOptInpNative; } dbCaAddLink(plink); if (pfldDes->field_type == DBF_FWDLINK) { pperiod = strrchr(plink->value.pv_link.pvname, '.'); if (pperiod && strstr(pperiod, "PROC")) plink->value.pv_link.pvlMask |= pvlOptFWD; } } break; case CONSTANT: break; case DB_LINK: case CA_LINK: case MACRO_LINK: break; /* should never get here */ default: /* Hardware address */ if (!isDevLink) { status = S_db_badHWaddr; goto postScanEvent; } break; } db_post_events(precord, plink, DBE_VALUE | DBE_LOG); restoreScan: if (isDevLink && scan == menuScanI_O_Intr) { /* undo scanDelete() */ precord->scan = scan; scanAdd(precord); } postScanEvent: if (scan != precord->scan) db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG); unlock: dbLockSetGblUnlock(); finish: dbFinishEntry(&dbEntry); return status; }
void mdsPlusPut_Task(int param) { unsigned long i; int socket; int null=0; int dtypeFloat = DTYPE_FLOAT; int dataDesc,timeDesc; int status=1, j; float tdT; float toffT; int tnoRd; int tshotID; char ttagName[20]; char ttreeID[20]; char tserverID[20]; float *timeBase; DBADDR *paddr; paddr = (DBADDR *)dbCalloc(1, sizeof(struct dbAddr)); if(genSubDebug > 0) printf("Start MdsPut. ##############.\n"); status = dbNameToAddr(mpActivePV, paddr); enum16Val = 1; status = dbPutField(paddr, DBR_ENUM, &enum16Val, 1); status = mdsPlusCreatePulse(); /* loop numNode times */ for(j = 0;j < numNode; j++) { if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() started. Task Position=%d, Flag=%ld\n",j,pmdsPutData[j].putFlag); if(pmdsPutData[j].putFlag == 0) goto endloop; epicsThreadSleep(0.01); tnoRd=(int)(pmdsPutData[j].noRd); tshotID=(int)(pmdsPutData[j].shotID); strcpy(ttagName,pmdsPutData[j].tagName); strcpy(ttreeID,pmdsPutData[j].treeID); strcpy(tserverID,pmdsPutData[j].serverID); tdT=pmdsPutData[j].dT; toffT=pmdsPutData[j].offT; if(genSubDebug > 3) printf("genSub: mdsPlusPut_Task() MdsConnect Ready. ServerID=[%s] TreeID=[%s] tagName=[%s] dt=[%f] off=[%f] noRd=[%d]\n",tserverID, ttreeID, ttagName, tdT, toffT, tnoRd); /* Connect server and open tree*/ socket=MdsConnect(tserverID); if(socket == -1) { printf("genSub: Error connecting to mdsip server[%s].\n",tserverID); break; } if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() MdsConnected[%s]\n",tserverID); status=MdsOpen(ttreeID, &tshotID); if( !status_ok(status) ) { printf("genSub: Error opening tree [%s] for shot [%d].\n", ttreeID,tshotID ); break; } if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() MdsOpened [%s] shot number [%d].\n", ttreeID,tshotID); /* put data */ timeBase = (float *)malloc(tnoRd*sizeof(float)); for(i=0;i<tnoRd;i++) *(timeBase + i) = ((float)i)*tdT + toffT; dataDesc=descr(&dtypeFloat,pmdsPutData[j].dataArray,&tnoRd, &null); timeDesc=descr(&dtypeFloat,timeBase, &tnoRd, &null); status=MdsPut(ttagName,"BUILD_SIGNAL($1,,$2)",&dataDesc,&timeDesc,&null); if( !status_ok(status) ) { printf("genSub: Error writing signal.\n"); break; } if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() MdsPutted to tag [%s]. shot number [%d], noRd=[%d].\n", ttagName,tshotID,tnoRd); if(genSubDebug > 10) for(i=0;i<tnoRd;i++) { printf("timeBase=%f,data=%f\n", *((float *)timeBase+i),*((float *)pmdsPutData[j].dataArray+i)); } free(timeBase); status=MdsClose(ttreeID, &tshotID); if( !status_ok(status) ) { printf("genSub: Error closing tree for shot [%d].\n",tshotID ); break; } if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() MdsClosed [%s] shot number [%d]\n",ttreeID,tshotID); endloop: if(genSubDebug > 5) printf("genSub: mdsPlusPut_Task() Data discarded for taskPos[%d].\n",j); } status = mdsPlusPrepNext(); /* end of mdsput */ startMdsPut = 0; status = dbNameToAddr(mpActivePV, paddr); enum16Val = 0; status = dbPutField(paddr, DBR_ENUM, &enum16Val, 1); free(paddr); }
static long special(dbAddr *paddr, int after) { acalcoutRecord *pcalc = (acalcoutRecord *)(paddr->precord); rpvtStruct *prpvt = (struct rpvtStruct *)pcalc->rpvt; dbAddr Addr; dbAddr *pAddr = &Addr; short error_number; int fieldIndex = dbGetFieldIndex(paddr); int lnkIndex; DBLINK *plink; double *pvalue; unsigned short *plinkValid; if (!after) return(0); switch (fieldIndex) { case acalcoutRecordCALC: pcalc->clcv = aCalcPostfix(pcalc->calc, pcalc->rpcl, &error_number); if (pcalc->clcv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: special(): Illegal CALC field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->clcv,DBE_VALUE); return(0); break; case acalcoutRecordOCAL: pcalc->oclv = aCalcPostfix(pcalc->ocal, pcalc->orpc, &error_number); if (pcalc->oclv) { recGblRecordError(S_db_badField,(void *)pcalc, "acalcout: special(): Illegal OCAL field"); if (aCalcoutRecordDebug >= 10) printf("acalcPostfix returns: %d\n", error_number); } db_post_events(pcalc,&pcalc->oclv,DBE_VALUE); return(0); break; case acalcoutRecordNUSE: if ((pcalc->nuse < 0) || (pcalc->nuse > pcalc->nelm)) { pcalc->nuse = pcalc->nelm; db_post_events(pcalc,&pcalc->nuse,DBE_VALUE); return(-1); } return(0); break; case(acalcoutRecordINPA): case(acalcoutRecordINPB): case(acalcoutRecordINPC): case(acalcoutRecordINPD): case(acalcoutRecordINPE): case(acalcoutRecordINPF): case(acalcoutRecordINPG): case(acalcoutRecordINPH): case(acalcoutRecordINPI): case(acalcoutRecordINPJ): case(acalcoutRecordINPK): case(acalcoutRecordINPL): case(acalcoutRecordINAA): case(acalcoutRecordINBB): case(acalcoutRecordINCC): case(acalcoutRecordINDD): case(acalcoutRecordINEE): case(acalcoutRecordINFF): case(acalcoutRecordINGG): case(acalcoutRecordINHH): case(acalcoutRecordINII): case(acalcoutRecordINJJ): case(acalcoutRecordINKK): case(acalcoutRecordINLL): case(acalcoutRecordOUT): lnkIndex = fieldIndex - acalcoutRecordINPA; plink = &pcalc->inpa + lnkIndex; pvalue = &pcalc->a + lnkIndex; plinkValid = &pcalc->inav + lnkIndex; if (plink->type == CONSTANT) { if (fieldIndex <= acalcoutRecordINPL) { recGblInitConstantLink(plink,DBF_DOUBLE,pvalue); db_post_events(pcalc,pvalue,DBE_VALUE); } *plinkValid = acalcoutINAV_CON; if (fieldIndex == acalcoutRecordOUT) prpvt->outlink_field_type = DBF_NOACCESS; } else if (!dbNameToAddr(plink->value.pv_link.pvname, pAddr)) { /* PV resides on this ioc */ *plinkValid = acalcoutINAV_LOC; if (fieldIndex == acalcoutRecordOUT) { prpvt->outlink_field_type = pAddr->field_type; if ((pAddr->field_type >= DBF_INLINK) && (pAddr->field_type <= DBF_FWDLINK)) { if (!(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):special:non-CA link to link field\n", plink->value.pv_link.pvname); } } if (pcalc->wait && !(plink->value.pv_link.pvlMask & pvlOptCA)) { printf("aCalcoutRecord(%s):special: Can't wait with non-CA link attribute\n", plink->value.pv_link.pvname); } } } else { /* pv is not on this ioc. Callback later for connection stat */ *plinkValid = acalcoutINAV_EXT_NC; /* DO_CALLBACK, if not already scheduled */ if (!prpvt->wd_id_1_LOCK) { callbackRequestDelayed(&prpvt->checkLinkCb,.5); prpvt->wd_id_1_LOCK = 1; prpvt->caLinkStat = CA_LINKS_NOT_OK; } if (fieldIndex == acalcoutRecordOUT) prpvt->outlink_field_type = DBF_NOACCESS; /* don't know */ } db_post_events(pcalc,plinkValid,DBE_VALUE); return(0); break; default: recGblDbaddrError(S_db_badChoice,paddr,"calc: special"); return(S_db_badChoice); } return(0); }
/* * Add breakpoint to a lock set * 1. Convert name to address and check breakpoint mask. * 2. Lock database. * 3. If empty, initialize lock set stack and its semaphore. * 4. Take that semaphore. * 5. Find lockset in the list. If it doesn't exist, create it. * 6. Turn on breakpoint field in record. * 7. Add breakpoint to list of breakpoints in structure. * 8. Spawn continuation task if it isn't already running. */ long epicsShareAPI dbb(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> Breakpoint already set in this record\n"); return(S_db_bkptSet); } dbScanLock(precord); /* * Add lock set to the stack of lock sets that * contain breakpoints and/or stopped records. */ epicsMutexMustLock(bkpt_stack_sem); FIND_LOCKSET(precord, pnode); if (pnode == NULL) { /* lockset not found, create node, add to end of list */ pnode = (struct LS_LIST *) malloc(sizeof(struct LS_LIST)); if (pnode == NULL) { printf(" BKPT> Out of memory\n"); dbScanUnlock(precord); epicsMutexUnlock(bkpt_stack_sem); return(1); } pnode->precord = NULL; /* initialize breakpoint list */ ellInit(&pnode->bp_list); /* initialize entry point queue */ ellInit(&pnode->ep_queue); /* create execution semaphore */ pnode->ex_sem = epicsEventCreate(epicsEventEmpty); if (pnode->ex_sem == NULL) { printf(" BKPT> Out of memory\n"); dbScanUnlock(precord); epicsMutexUnlock(bkpt_stack_sem); return(1); } pnode->taskid = 0; pnode->step = 0; pnode->l_num = dbLockGetLockId(precord); ellAdd(&lset_stack, (ELLNODE *)pnode); ++lset_stack_count; } /* * Add record to breakpoint list */ pbl = (struct BP_LIST *) malloc(sizeof(struct BP_LIST)); if (pbl == NULL) { printf(" BKPT> Out of memory\n"); dbScanUnlock(precord); epicsMutexUnlock(bkpt_stack_sem); return(1); } pbl->precord = precord; ellAdd(&pnode->bp_list, (ELLNODE *)pbl); /* * Turn on breakpoint field in record */ precord->bkpt |= BKPT_ON_MASK; if (! pnode->taskid) { #ifdef BKPT_DIAG printf(" BKPT> Spawning task: %s\n", precord->name); #endif /* * Spawn continuation task */ pnode->taskid = epicsThreadCreate("bkptCont",epicsThreadPriorityScanLow-1, epicsThreadGetStackSize(epicsThreadStackBig), (EPICSTHREADFUNC)dbBkptCont,precord); if (pnode->taskid == 0) { printf(" BKPT> Cannot spawn task to process record\n"); pnode->taskid = 0; dbScanUnlock(precord); epicsMutexUnlock(bkpt_stack_sem); return(1); } } epicsMutexUnlock(bkpt_stack_sem); dbScanUnlock(precord); return(0); }