/* main program */ int main( int argc, char *argv[] ) { /* system and variable names */ const char *sysNam = ( argc > 1 ) ? argv[1] : "ca"; const char *varNam = ( argc > 2 ) ? argv[2] : "demo:voltage"; void *sys; void *var; int status; /* create system */ status = pvSysCreate( sysNam, 0, &sys ); if ( status ) { printf( "pvSysCreate( %s ) failure\n", sysNam ); return -1; } /* create variable */ status = pvVarCreate( sys, varNam, NULL, NULL, 0, &var ); if ( status ) { printf( "pvVarCreate( %s, %s ) failure\n", sysNam, varNam ); return -1; } /* monitor variable as double (assume scalar) */ status = pvVarMonitorOn( var, pvTypeDOUBLE, 1, event, NULL, NULL ); if ( status ) { printf( "pvVarMonitorOn( %s ) failure\n", varNam ); } /* shouldn't need this! */ pvSysPend( sys, 1, FALSE ); /* block for 10 seconds */ pvSysPend( sys, 10, TRUE ); /* tidy up */ pvVarDestroy( var ); pvSysDestroy( sys ); return 0; }
/* * 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; }
/* * Assign/Connect to a channel. * Assign to a zero-length string ("") disconnects/de-assigns, * in safe mode, creates an anonymous PV. */ epicsShareFunc pvStat epicsShareAPI seq_pvAssign(SS_ID ss, VAR_ID varId, const char *pvName) { SPROG *sp = ss->sprog; CHAN *ch = sp->chan + varId; pvStat status = pvStatOK; DBCHAN *dbch = ch->dbch; if (!pvName) pvName = ""; DEBUG("Assign %s to \"%s\"\n", ch->varName, pvName); epicsMutexMustLock(sp->programLock); if (dbch) /* was assigned to a named PV */ { status = pvVarDestroy(dbch->pvid); dbch->pvid = NULL; sp->assignCount -= 1; if (dbch->connected) /* see connection handler */ { dbch->connected = FALSE; sp->connectCount--; /* Must not call seq_monitor(ch, FALSE), it would give an error because channel is already dead. Instead mark that no subscriptions are active so when seq_monitor gets called when we re-create the channel, it actually does something. */ dbch->monid = NULL; /* 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 == NULL || pvName[0] == 0) /* new name is empty -> free resources */ { if (dbch) { free(ch->dbch->ssMetaData); free(ch->dbch); } } else /* new name is non-empty -> create resources */ { if (!dbch) { dbch = new(DBCHAN); if (!dbch) { errlogSevPrintf(errlogFatal, "pvAssign: calloc failed\n"); return pvStatERROR; } } dbch->dbName = epicsStrDup(pvName); if (!dbch->dbName) { errlogSevPrintf(errlogFatal, "pvAssign: epicsStrDup failed\n"); free(dbch); return pvStatERROR; } if ((sp->options & OPT_SAFE) && sp->numSS > 0) { dbch->ssMetaData = newArray(PVMETA, sp->numSS); if (!dbch->ssMetaData) { errlogSevPrintf(errlogFatal, "pvAssign: calloc failed\n"); free(dbch->dbName); free(dbch); return pvStatERROR; } } ch->dbch = dbch; sp->assignCount++; status = pvVarCreate( sp->pvSys, /* PV system context */ dbch->dbName, /* DB channel name */ seq_conn_handler, /* connection handler routine */ ch, /* user ptr is CHAN structure */ sp->debug, /* debug level (inherited) */ &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)); if (ch->dbch->ssMetaData) free(ch->dbch->ssMetaData); free(ch->dbch->dbName); free(ch->dbch); } } epicsMutexUnlock(sp->programLock); return status; }