int simRegDevSetStatus( const char* name, int connected) { regDevice* device; if (!name) { printf ("usage: simRegDevSetStatus name, 0|1\n"); return S_dev_badArgument; } device = regDevFind(name); if (!device) { errlogSevPrintf(errlogFatal, "simRegDevSetStatus: %s not found\n", name); return S_dev_noDevice; } if (device->magic != MAGIC) { errlogSevPrintf(errlogFatal, "simRegDevSetStatus: %s is not a simRegDev\n", name); return S_dev_wrongDevice; } device->connected = connected; if (simRegDevDebug >= 1) printf ("simRegDevSetStatus %s: trigger input records\n", device->name); scanIoRequest(device->ioscanpvt); return S_dev_success; }
/* * Return whether the last get completed. In safe mode, as a * side effect, copy value from shared buffer to state set local buffer. */ epicsShareFunc boolean epicsShareAPI seq_pvGetComplete(SS_ID ss, VAR_ID varId) { epicsEventId getSem = ss->getSemId[varId]; SPROG *sp = ss->sprog; CHAN *ch = sp->chan + varId; pvStat status; if (!ch->dbch) { /* Anonymous PVs always complete immediately */ if (!(sp->options & OPT_SAFE)) errlogSevPrintf(errlogMajor, "pvGetComplete(%s): user error (variable not assigned)\n", ch->varName); return TRUE; } if (!ss->getReq[varId]) { errlogSevPrintf(errlogMinor, "pvGetComplete(%s): no pending get request for this variable\n", ch->varName); return TRUE; } switch (epicsEventTryWait(getSem)) { case epicsEventWaitOK: ss->getReq[varId] = NULL; epicsEventSignal(getSem); status = check_connected(ch->dbch, metaPtr(ch,ss)); /* TODO: returning either TRUE or FALSE here seems wrong. We return TRUE, so that state sets don't hang. Still means that user code has to check status by calling pvStatus and/or pvMessage. */ if (status) return TRUE; /* In safe mode, copy value and meta data from shared buffer to ss local buffer. */ if (sp->options & OPT_SAFE) /* Copy regardless of whether dirty flag is set or not */ ss_read_buffer(ss, ch, FALSE); return TRUE; case epicsEventWaitTimeout: return FALSE; case epicsEventWaitError: ss->getReq[varId] = NULL; epicsEventSignal(getSem); errlogSevPrintf(errlogFatal, "pvGetComplete: " "epicsEventTryWait(getSemId[%d]) failure\n", varId); default: /* pacify gcc which does not understand the we checked all possibilities */ return FALSE; } }
int simRegDevRead( regDevice *device, size_t offset, unsigned int dlen, size_t nelem, void* pdata, int prio, regDevTransferComplete callback, const char* user) { if (!device || device->magic != MAGIC) { errlogSevPrintf(errlogMajor, "simRegDevRead %s: illegal device handle\n", user); return S_dev_wrongDevice; } if (device->connected == 0) { return S_dev_noDevice; } if (simRegDevDebug & DBG_IN) printf ("simRegDevRead %s %s:%"Z"u: %u bytes * %"Z"u elements, prio=%d\n", user, device->name, offset, dlen, nelem, prio); if (nelem > 1 && device->lock) return simRegDevAsynTransfer(device, dlen, nelem, device->buffer+offset, pdata, NULL, prio, callback, user, FALSE); regDevCopy(dlen, nelem, device->buffer+offset, pdata, NULL, device->swap); return S_dev_success; }
/* * Get value from a queued PV. */ epicsShareFunc boolean seq_pvGetQ(SS_ID ss, CH_ID chId) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; void *var = valPtr(ch,ss); EF_ID ev_flag = ch->syncedTo; PVMETA *meta = metaPtr(ch,ss); boolean was_empty; struct getq_cp_arg arg = {ch, var, meta}; if (!ch->queue) { errlogSevPrintf(errlogMajor, "pvGetQ(%s): user error (not queued)\n", ch->varName ); return FALSE; } was_empty = seqQueueGetF(ch->queue, getq_cp, &arg); if (ev_flag) { epicsMutexMustLock(sp->lock); /* If queue is now empty, clear the event flag */ if (seqQueueIsEmpty(ch->queue)) { bitClear(sp->evFlags, ev_flag); } epicsMutexUnlock(sp->lock); } return (!was_empty); }
static pvStat wait_complete( pvEventType evtype, SS_ID ss, PVREQ **req, DBCHAN *dbch, PVMETA *meta, double tmo) { const char *call = evtype == pvEventGet ? "pvGet" : "pvPut"; while (*req) { switch (epicsEventWaitWithTimeout(ss->syncSem, tmo)) { case epicsEventWaitOK: break; case epicsEventWaitTimeout: *req = NULL; /* cancel the request */ completion_timeout(evtype, meta); return meta->status; case epicsEventWaitError: errlogSevPrintf(errlogFatal, "%s: epicsEventWaitWithTimeout() failure\n", call); *req = NULL; /* cancel the request */ completion_failure(evtype, meta); return meta->status; } } return check_connected(dbch, meta); }
/* * Return whether the last get completed. In safe mode, as a * side effect, copy value from shared buffer to state set local buffer. */ epicsShareFunc boolean seq_pvGetComplete( SS_ID ss, CH_ID chId) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; if (!ch->dbch) { /* Anonymous PVs always complete immediately */ if (!optTest(sp, OPT_SAFE)) errlogSevPrintf(errlogMajor, "pvGetComplete(%s): user error (not assigned to a PV)\n", ch->varName); return TRUE; } else if (!ss->getReq[chId]) { pvStat status = check_connected(ch->dbch, metaPtr(ch,ss)); if (status == pvStatOK && optTest(sp, OPT_SAFE)) { /* In safe mode, copy value and meta data from shared buffer to ss local buffer. */ /* Copy regardless of whether dirty flag is set or not */ ss_read_buffer(ss, ch, FALSE); } return TRUE; } return FALSE; }
static pvStat seq_pvSingleMonitor(SS_ID ss, CH_ID chId, boolean turn_on, const char *what) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; DBCHAN *dbch = ch->dbch; pvStat status; if (!dbch) { if (optTest(sp, OPT_SAFE)) { ch->monitored = TRUE; return pvStatOK; } else { errlogSevPrintf(errlogMajor, "%s(%s): user error (not assigned to a PV)\n", what, ch->varName ); return pvStatERROR; } } ch->monitored = turn_on; status = seq_camonitor(ch, turn_on); if (status != pvStatOK) { pv_call_failure(dbch, metaPtr(ch,ss), status); } return status; }
void seqCreatePvSys(SPROG *sp) { int debug = sp->debug; pvStat status = pvSysCreate(sp->pvSysName, max(0, debug-1), &sp->pvSys); if (status != pvStatOK) errlogSevPrintf(errlogFatal, "pvSysCreate(\"%s\") failure\n", sp->pvSysName); }
void mk3Driver::checkErrorCode(int code) { // 0 = no error if (code != 0) { char answer[50]; m_interface->checkErrorCode(code, answer, 50); errlogSevPrintf(errlogMajor, "%s", answer); // If .net timeout try to re-intialise if (code == -3) { errlogSevPrintf(errlogMajor, "%s","Trying to re-establish .NET connection"); m_interface->initialise(); } } }
int simRegDevWrite( regDevice *device, size_t offset, unsigned int dlen, size_t nelem, void* pdata, void* pmask, int prio, regDevTransferComplete callback, const char* user) { if (!device || device->magic != MAGIC) { errlogSevPrintf(errlogMajor, "simRegDevWrite: illegal device handle\n"); return S_dev_wrongDevice; } if (device->connected == 0) { return S_dev_noDevice; } if (simRegDevDebug & DBG_OUT) { size_t n; printf ("simRegDevWrite %s %s:%"Z"u: %u bytes * %"Z"u elements, prio=%d\n", user, device->name, offset, dlen, nelem, prio); for (n=0; n<nelem && n<10; n++) { switch (dlen) { case 1: printf (" %02x",((epicsUInt8*)pdata)[n*dlen]); break; case 2: printf (" %04x",((epicsUInt16*)pdata)[n*dlen]); break; case 4: printf (" %08x",((epicsUInt32*)pdata)[n*dlen]); break; case 8: printf (" %08llx",((unsigned long long*)pdata)[n*dlen]); break; } } printf ("\n"); } if (nelem > 1 && device->lock) return simRegDevAsynTransfer(device, dlen, nelem, pdata, device->buffer+offset, pmask, prio, callback, user, TRUE); regDevCopy(dlen, nelem, pdata, device->buffer+offset, pmask, device->swap); /* We got new data: trigger all interested input records */ if (simRegDevDebug & DBG_OUT) printf ("simRegDevWrite %s: trigger input records\n", device->name); scanIoRequest(device->ioscanpvt); return S_dev_success; }
int simRegDevAsynTransfer( regDevice *device, unsigned int dlen, size_t nelem, void* src, void* dest, void* pmask, int prio, regDevTransferComplete callback, const char* user, int isOutput) { simRegDevMessage* msg; if (simRegDevDebug & (isOutput ? DBG_OUT : DBG_IN)) printf ("simRegDevAsynTransfer %s %s: copy %s %u bytes * %"Z"u elements\n", user, device->name, isOutput ? "out" : "in", dlen, nelem); epicsMutexLock(device->lock); if (device->msgFreelist[prio] == NULL) { msg = calloc(sizeof(simRegDevMessage),1); if (msg) msg->timer = epicsTimerQueueCreateTimer(device->queue[prio], simRegDevCallback, msg); if (msg == NULL || msg->timer == NULL) { errlogSevPrintf(errlogMajor, "simRegDevAllocMessage %s %s: out of memory\n", user, device->name); if (msg) free(msg); epicsMutexUnlock(device->lock); return S_dev_noMemory; } } else { msg = device->msgFreelist[prio]; device->msgFreelist[prio] = device->msgFreelist[prio]->next; } msg->next = NULL; msg->device = device; msg->dlen = dlen; msg->nelem = nelem; msg->src = src; msg->dest = dest; msg->pmask = pmask; msg->prio = prio; msg->callback = callback; msg->user = user; msg->isOutput = isOutput; epicsMutexUnlock(device->lock); if (simRegDevDebug & (isOutput ? DBG_OUT : DBG_IN)) printf ("simRegDevAsynTransfer %s %s: starting timer %g seconds\n", user, device->name, nelem*0.01); epicsTimerStartDelay(msg->timer, nelem*0.01); return ASYNC_COMPLETION; }
int caPutLogAsInit() { if (!asActive) { errlogSevPrintf(errlogFatal, "caPutLog: access security is disabled\n"); return caPutLogError; } /* Initialize the free list of log elements */ if (!logDataFreeList) { freeListInitPvt(&logDataFreeList, sizeof(LOGDATA), FREE_LIST_SIZE); } /* Initialize the Trap Write Listener */ listenerId = asTrapWriteRegisterListener(caPutLogAs); if (!listenerId) { errlogSevPrintf(errlogFatal, "caPutLog: asTrapWriteRegisterListener failed\n"); return caPutLogError; } return caPutLogSuccess; }
int simRegDevSetData( const char* name, size_t offset, int value) { regDevice* device; if (!name) { printf ("usage: simRegDevSetData name, offset, value\n"); return S_dev_badArgument; } device = regDevFind(name); if (!device) { errlogSevPrintf(errlogFatal, "simRegDevSetData: %s not found\n", name); return S_dev_noDevice; } if (device->magic != MAGIC) { errlogSevPrintf(errlogFatal, "simRegDevSetData: %s is not a simRegDev\n", name); return S_dev_wrongDevice; } if (offset > device->size) { errlogSevPrintf(errlogFatal, "simRegDevSetData: %s offset %"Z"d out of range (0-%"Z"d)\n", name, offset, device->size); return S_dev_badSignalNumber; } device->buffer[offset] = value; if (simRegDevDebug >= 1) printf ("simRegDevSetData %s: trigger input records\n", device->name); scanIoRequest(device->ioscanpvt); return S_dev_success; }
/// EPICS iocsh callable function to call constructor of lvDCOMInterface(). /// \param[in] portName @copydoc initArg0 /// \param[in] configSection @copydoc initArg1 /// \param[in] configFile @copydoc initArg2 /// \param[in] host @copydoc initArg3 /// \param[in] options @copydoc initArg4 /// \param[in] progid @copydoc initArg5 /// \param[in] username @copydoc initArg6 /// \param[in] password @copydoc initArg7 int isisdaeConfigure(const char *portName, int options, const char *host, const char* username, const char* password) { try { isisdaeInterface* iface = new isisdaeInterface(host, options, username, password); if (iface != NULL) { isisdaeDriver* driver = new isisdaeDriver(iface, portName); if (driver != NULL) { if (epicsThreadCreate("daeCAS", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)daeCASThread, iface) == 0) { printf("epicsThreadCreate failure\n"); return(asynError); } } else { errlogSevPrintf(errlogMajor, "isisdaeConfigure failed (NULL)\n"); return(asynError); } return(asynSuccess); } else { errlogSevPrintf(errlogMajor, "isisdaeConfigure failed (NULL)\n"); return(asynError); } } catch(const std::exception& ex) { errlogSevPrintf(errlogMajor, "isisdaeConfigure failed: %s\n", ex.what()); return(asynError); } }
void isisdaeDriver::reportErrors(const char* exc_text) { std::string msgs = m_iface->getAllMessages(); setStringParam(P_AllMsgs, msgs.c_str()); setStringParam(P_ErrMsgs, exc_text); std::string mess_ts; isisdaeInterface::stripTimeStamp(exc_text, mess_ts); // std::cerr << mess_ts << std::endl; errlogSevPrintf(errlogMajor, "%s", mess_ts.c_str()); // getAsynMessages will pick these up and report to screen // errlogSevPrintf(errlogInfo, "%s", msgs.c_str()); m_iface->resetMessages(); }
int simRegDevGetData( const char* name, size_t offset, int *value) { regDevice* device; if (!name) { printf ("usage: simRegDevGetData name, offset, &value\n"); return S_dev_badArgument; } device = regDevFind(name); if (!device) { errlogSevPrintf(errlogFatal, "simRegDevGetData: %s not found\n", name); return S_dev_noDevice; } if (device->magic != MAGIC) { errlogSevPrintf(errlogFatal, "simRegDevGetData: %s is not a simRegDev\n", name); return S_dev_wrongDevice; } if (offset > device->size) { errlogSevPrintf(errlogFatal, "simRegDevGetData: %s offset %"Z"d out of range (0-%"Z"d)\n", name, offset, device->size); return S_dev_badSignalNumber; } *value = device->buffer[offset]; return S_dev_success; }
IOSCANPVT simRegDevGetInScanPvt( regDevice *device, size_t offset, int ivec, const char* name) { if (!device || device->magic != MAGIC) { errlogSevPrintf(errlogMajor, "simRegDevGetInScanPvt %s: illegal device handle\n", name); return NULL; } return device->ioscanpvt; }
/// EPICS iocsh callable function to call constructor of NetShrVarInterface(). /// The function is registered via NetShrVarRegister(). /// /// @param[in] portName @copydoc initArg0 /// @param[in] configSection @copydoc initArg1 /// @param[in] configFile @copydoc initArg2 /// @param[in] pollPeriod @copydoc initArg3 /// @param[in] options @copydoc initArg4 int NetShrVarConfigure(const char *portName, const char* configSection, const char *configFile, int pollPeriod, int options) { try { NetShrVarInterface* netvarint = new NetShrVarInterface(configSection, configFile, options); if (netvarint != NULL) { new NetShrVarDriver(netvarint, pollPeriod, portName); return(asynSuccess); } else { errlogSevPrintf(errlogFatal, "NetShrVarConfigure failed (NULL)\n"); return(asynError); } } catch(const std::exception& ex) { errlogSevPrintf(errlogFatal, "NetShrVarConfigure failed: %s\n", ex.what()); return(asynError); } }
void NetShrVarInterface::createParams(asynPortDriver* driver) { static const char* functionName = "createParams"; m_driver = driver; getParams(); for(params_t::iterator it=m_params.begin(); it != m_params.end(); ++it) { NvItem* item = it->second; if (item->type == "float64") { m_driver->createParam(it->first.c_str(), asynParamFloat64, &(item->id)); } else if (item->type == "int32" || item->type == "boolean") { m_driver->createParam(it->first.c_str(), asynParamInt32, &(item->id)); } else if (item->type == "string") { m_driver->createParam(it->first.c_str(), asynParamOctet, &(item->id)); } else if (item->type == "float64array") { m_driver->createParam(it->first.c_str(), asynParamFloat64Array, &(item->id)); } else if (item->type == "float32array") { m_driver->createParam(it->first.c_str(), asynParamFloat32Array, &(item->id)); } else if (item->type == "int32array") { m_driver->createParam(it->first.c_str(), asynParamInt32Array, &(item->id)); } else if (item->type == "int16array") { m_driver->createParam(it->first.c_str(), asynParamInt16Array, &(item->id)); } else if (item->type == "int8array") { m_driver->createParam(it->first.c_str(), asynParamInt8Array, &(item->id)); } else { errlogSevPrintf(errlogMajor, "%s:%s: unknown type %s for parameter %s\n", driverName, functionName, item->type.c_str(), it->first.c_str()); } } connectVars(); }
static long initRecord (dbCommon *record) { static const int typesize[] = {MAX_STRING_SIZE,1,1,2,2,4,4,4,8,2}; aaoRecord *aao = (aaoRecord *) record; aao->bptr = calloc(aao->nelm, typesize[aao->ftvl]); if (aao->bptr == NULL) { errlogSevPrintf (errlogFatal, "initRecord %s: can't allocate memory for data array\n", record->name); return ERROR; } return streamInitRecord (record, &aao->out, readData, writeData) == ERROR ? ERROR : OK; }
static void anonymous_put(SS_ID ss, CHAN *ch) { char *var = valPtr(ch,ss); if (ch->queue) { QUEUE queue = ch->queue; pvType type = ch->type->getType; /*BUG? should that be putType?*/ size_t size = ch->type->size; boolean full; struct putq_cp_arg arg = {ch, var}; DEBUG("anonymous_put: type=%d, size=%d, count=%d, buf_size=%d, q=%p\n", type, size, ch->count, pv_size_n(type, ch->count), queue); print_channel_value(DEBUG, ch, var); /* Note: Must lock here because multiple state sets can issue pvPut calls concurrently. OTOH, no need to lock against CA callbacks, because anonymous and named PVs are disjoint. */ epicsMutexMustLock(ch->varLock); full = seqQueuePutF(queue, putq_cp, &arg); if (full) { errlogSevPrintf(errlogMinor, "pvPut on queued channel '%s' (anonymous): " "last queue element overwritten (queue is full)\n", ch->varName ); } epicsMutexUnlock(ch->varLock); } else { /* Set dirty flag only if monitored */ ss_write_buffer(ch, var, 0, ch->monitored); } /* If there's an event flag associated with this channel, set it */ if (ch->syncedTo) seq_efSet(ss, ch->syncedTo); /* Wake up each state set that uses this channel in an event */ ss_wakeup(ss->prog, ch->eventNum); }
/* * Cancel the last asynchronous put request. */ epicsShareFunc void seq_pvPutCancel( SS_ID ss, CH_ID chId) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; if (!ch->dbch) { if (!optTest(sp, OPT_SAFE)) errlogSevPrintf(errlogMinor, "pvPutCancel(%s): user error (not assigned to a PV)\n", ch->varName); } else { ss->putReq[chId] = NULL; /* cancel the request */ } }
int simRegDevConfigure( const char* name, size_t size, int swapEndianFlag, int async) { regDevice* device; if (name == NULL) { printf("usage: simRegDevConfigure(\"name\", size, swapEndianFlag)\n"); printf("maps allocated memory block to device \"name\""); printf("\"name\" must be a unique string on this IOC\n"); return S_dev_success; } device = (regDevice*)calloc(sizeof(regDevice)+size-1,1); if (device == NULL) { errlogSevPrintf(errlogFatal, "simRegDevConfigure %s: out of memory\n", name); return errno; } device->magic = MAGIC; device->name = strdup(name); device->size = size; device->connected = 1; device->swap = swapEndianFlag; if (async) { int i; device->lock = epicsMutexCreate(); for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) { const unsigned int prio [3] = {epicsThreadPriorityLow, epicsThreadPriorityMedium, epicsThreadPriorityHigh}; device->queue[i] = epicsTimerQueueAllocate(FALSE, prio[i]); } } regDevRegisterDevice(name, &simRegDevSupport, device, size); scanIoInit(&device->ioscanpvt); return S_dev_success; }
static void daeCASThread(void* arg) { exServer *pCAS; unsigned debugLevel = 0u; double executionTime = 0.0; double asyncDelay = 0.1; const char* pvPrefix; unsigned aliasCount = 1u; unsigned scanOn = true; unsigned syncScan = true; unsigned maxSimultAsyncIO = 1000u; isisdaeInterface* iface = static_cast<isisdaeInterface*>(arg); printf("starting cas server\n"); pvPrefix = macEnvExpand("$(MYPVPREFIX)DAE:"); try { pCAS = new exServer ( pvPrefix, aliasCount, scanOn != 0, syncScan == 0, asyncDelay, maxSimultAsyncIO, iface ); } catch ( ... ) { errlogSevPrintf (errlogMajor, "Server initialization error\n" ); errlogFlush (); return; } pCAS->setDebugLevel(debugLevel); try { while (true) { fileDescriptorManager.process(1000.0); } } catch(const std::exception& ex) { std::cerr << ex.what() << std::endl; } //pCAS->show(2u); delete pCAS; errlogFlush (); }
/* * Cancel a monitor. */ epicsShareFunc pvStat epicsShareAPI seq_pvStopMonitor(SS_ID ss, VAR_ID varId) { SPROG *sp = ss->sprog; CHAN *ch = sp->chan + varId; DBCHAN *dbch = ch->dbch; if (!dbch && (sp->options & OPT_SAFE)) { ch->monitored = FALSE; return pvStatOK; } if (!dbch) { errlogSevPrintf(errlogMajor, "pvStopMonitor(%s): user error (variable not assigned)\n", ch->varName ); return pvStatERROR; } ch->monitored = FALSE; return seq_monitor(ch, FALSE); }
epicsShareFunc QUEUE seqQueueCreate(size_t numElems, size_t elemSize) { QUEUE q = new(struct seqQueue); if (!q) { errlogSevPrintf(errlogFatal, "seqQueueCreate: out of memory\n"); return 0; } /* check arguments to establish invariants */ if (numElems == 0) { errlogSevPrintf(errlogFatal, "seqQueueCreate: numElems must be positive\n"); free(q); return 0; } if (elemSize == 0) { errlogSevPrintf(errlogFatal, "seqQueueCreate: elemSize must be positive\n"); free(q); return 0; } if (numElems > seqQueueMaxNumElems) { errlogSevPrintf(errlogFatal, "seqQueueCreate: numElems too large\n"); free(q); return 0; } DEBUG("%s:%d:calloc(%u,%u)\n",__FILE__,__LINE__,numElems, elemSize); q->buffer = (char *)calloc(numElems, elemSize); if (!q->buffer) { errlogSevPrintf(errlogFatal, "seqQueueCreate: out of memory\n"); free(q); return 0; } q->mutex = epicsMutexCreate(); if (!q->mutex) { errlogSevPrintf(errlogFatal, "seqQueueCreate: out of memory\n"); free(q->buffer); free(q); return 0; } q->elemSize = elemSize; q->numElems = numElems; q->overflow = FALSE; q->rd = q->wr = 0; return q; }
/* * Return whether the last put completed. */ static boolean seq_pvSinglePutComplete( SS_ID ss, CH_ID chId) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; if (!ch->dbch) { /* Anonymous PVs always complete immediately */ if (!(sp->options & OPT_SAFE)) errlogSevPrintf(errlogMajor, "pvPutComplete(%s): user error (not assigned to a PV)\n", ch->varName); return TRUE; } else if (!ss->putReq[chId]) { check_connected(ch->dbch, metaPtr(ch,ss)); return TRUE; } return FALSE; }
static pvStat check_pending( pvEventType evtype, SS_ID ss, PVREQ **req, const char *varName, DBCHAN *dbch, PVMETA *meta, enum compType compType, double tmo) { const char *call = evtype == pvEventGet ? "pvGet" : "pvPut"; assert(evtype != pvEventMonitor); if (compType == SYNC) { if (tmo <= 0.0) { errlogSevPrintf(errlogMajor, "%s(%s,SYNC,%f): user error (timeout must be positive)\n", call, varName, tmo); return pvStatERROR; } while (*req) { /* a request is already pending (must be an async request) */ double before, after; pvStat status; pvTimeGetCurrentDouble(&before); switch (epicsEventWaitWithTimeout(ss->syncSem, tmo)) { case epicsEventWaitOK: status = check_connected(dbch, meta); if (status != pvStatOK) return status; pvTimeGetCurrentDouble(&after); tmo -= (after - before); if (tmo > 0.0) break; /* else: fall through to timeout */ case epicsEventWaitTimeout: errlogSevPrintf(errlogMajor, "%s(ss %s, var %s, pv %s): failed (timeout " "waiting for other %s requests to finish)\n", call, ss->ssName, varName, dbch->dbName, call ); completion_timeout(evtype, meta); return meta->status; case epicsEventWaitError: errlogSevPrintf(errlogFatal, "%s: epicsEventWaitWithTimeout() failure\n", call); completion_failure(evtype, meta); return meta->status; } } } else if (compType == ASYNC) { if (*req) { errlogSevPrintf(errlogMajor, "%s(ss %s, var %s, pv %s): user error " "(there is already a %s pending for this channel/" "state set combination)\n", call, ss->ssName, varName, dbch->dbName, call ); return pvStatERROR; } } return pvStatOK; }
/* * Assign/Connect to a channel. * Assign to a zero-length string ("") disconnects/de-assigns, * in safe mode, creates an anonymous PV. */ epicsShareFunc pvStat seq_pvAssign(SS_ID ss, CH_ID chId, const char *pvName) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; pvStat status = pvStatOK; DBCHAN *dbch; if (!pvName) pvName = ""; DEBUG("Assign %s to \"%s\"\n", ch->varName, pvName); epicsMutexMustLock(sp->lock); dbch = ch->dbch; if (dbch) /* was assigned to a named PV */ { ch->dbch = 0; epicsMutexUnlock(sp->lock); status = pvVarDestroy(&dbch->pvid); epicsMutexMustLock(sp->lock); sp->assignCount--; if (dbch->connected) /* see connection handler */ { dbch->connected = FALSE; sp->connectCount--; /* Must not call seq_camonitor(ch, FALSE), it would give an error because channel is already dead. pvVarDestroy takes care that the monid inside the pvid gets invalidated. */ /* Note ch->monitored remains on because it is a configuration value that belongs to the variable and newly created channels for the same variable should inherit this configuration. */ } if (status != pvStatOK) { errlogSevPrintf(errlogFatal, "pvAssign(var %s, pv %s): pvVarDestroy() failure: " "%s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); } free(dbch->dbName); } if (pvName[0] == 0) /* new name is empty -> free resources */ { if (dbch) { free(dbch); } } else /* new name is non-empty -> create resources */ { if (!dbch) { dbch = new(DBCHAN); if (!dbch) { errlogSevPrintf(errlogFatal, "pvAssign: calloc failed\n"); epicsMutexUnlock(sp->lock); return pvStatERROR; } } dbch->dbName = epicsStrDup(pvName); if (!dbch->dbName) { errlogSevPrintf(errlogFatal, "pvAssign: epicsStrDup failed\n"); free(dbch); epicsMutexUnlock(sp->lock); return pvStatERROR; } ch->dbch = dbch; status = pvVarCreate( sp->pvSys, /* PV system context */ dbch->dbName, /* DB channel name */ seq_conn_handler, /* connection handler routine */ seq_event_handler, /* event handler routine */ ch, /* user ptr is CHAN structure */ &dbch->pvid); /* ptr to pvid */ if (status != pvStatOK) { errlogSevPrintf(errlogFatal, "pvAssign(var %s, pv %s): pvVarCreate() failure: " "%s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); free(ch->dbch->dbName); free(ch->dbch); } else { sp->assignCount++; } } epicsMutexUnlock(sp->lock); return status; }
/* * Put a variable's value to a PV, with timeout. */ epicsShareFunc pvStat seq_pvPutTmo(SS_ID ss, CH_ID chId, enum compType compType, double tmo) { PROG *sp = ss->prog; CHAN *ch = sp->chan + chId; pvStat status; unsigned count; char *var = valPtr(ch,ss); /* ptr to value */ PVREQ *req; DBCHAN *dbch = ch->dbch; PVMETA *meta = metaPtr(ch,ss); DEBUG("pvPut: pv name=%s, var=%p\n", dbch ? dbch->dbName : "<anonymous>", var); /* First handle anonymous PV (safe mode only) */ if (optTest(sp, OPT_SAFE) && !dbch) { anonymous_put(ss, ch); return pvStatOK; } if (!dbch) { errlogSevPrintf(errlogMajor, "pvPut(%s): user error (not assigned to a PV)\n", ch->varName ); return pvStatERROR; } /* Check for channel connected */ status = check_connected(dbch, meta); if (status != pvStatOK) return status; /* Determine whether to perform synchronous, asynchronous, or plain put ((+a) option was never honored for put, so DEFAULT means fire-and-forget) */ status = check_pending(pvEventPut, ss, ss->putReq + chId, ch->varName, dbch, meta, compType, tmo); if (status != pvStatOK) return status; /* Determine number of elements to put (don't try to put more than db count) */ count = dbch->dbCount; /* Perform the PV put operation (either non-blocking or with a callback routine specified) */ if (compType == DEFAULT) { status = pvVarPutNoBlock( &dbch->pvid, /* PV id */ ch->type->putType, /* data type */ count, /* element count */ (pvValue *)var); /* data value */ if (status != pvStatOK) { pv_call_failure(dbch, meta, status); errlogSevPrintf(errlogFatal, "pvPut(var %s, pv %s): pvVarPutNoBlock() failure: %s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); return status; } } else { /* Allocate and initialize a pv request */ req = (PVREQ *)freeListMalloc(sp->pvReqPool); req->ss = ss; req->ch = ch; assert(ss->putReq[chId] == NULL); ss->putReq[chId] = req; status = pvVarPutCallback( &dbch->pvid, /* PV id */ ch->type->putType, /* data type */ count, /* element count */ (pvValue *)var, /* data value */ req); /* user arg */ if (status != pvStatOK) { pv_call_failure(dbch, meta, status); errlogSevPrintf(errlogFatal, "pvPut(var %s, pv %s): pvVarPutCallback() failure: %s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); ss->putReq[chId] = NULL; /* cancel the request */ freeListFree(sp->pvReqPool, req); check_connected(dbch, meta); return status; } if (compType == SYNC) /* wait for completion */ { pvSysFlush(sp->pvSys); status = wait_complete(pvEventPut, ss, ss->putReq + chId, dbch, meta, tmo); if (status != pvStatOK) return status; } } return pvStatOK; }