Files
epics-base/src/std/rec/calcoutRecord.c
2017-04-25 20:37:09 -05:00

782 lines
23 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* calcout.c - Record Support Routines for calc with output records */
/*
* Author : Ned Arnold
* Based on recCalc.c by Julie Sander and Bob Dalesio
* Date: 7-27-87
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "alarm.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbLink.h"
#include "dbScan.h"
#include "cantProceed.h"
#include "epicsMath.h"
#include "errMdef.h"
#include "errlog.h"
#include "recSup.h"
#include "devSup.h"
#include "recGbl.h"
#include "special.h"
#include "callback.h"
#include "taskwd.h"
#include "menuIvoa.h"
#define GEN_SIZE_OFFSET
#include "calcoutRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
static long init_record(struct dbCommon *, int);
static long process(struct dbCommon *);
static long special(DBADDR *, int);
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
static long get_units(DBADDR *, char *);
static long get_precision(const DBADDR *, long *);
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double(DBADDR *, struct dbr_grDouble *);
static long get_control_double(DBADDR *, struct dbr_ctrlDouble *);
static long get_alarm_double(DBADDR *, struct dbr_alDouble *);
rset calcoutRSET = {
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset, calcoutRSET);
int calcoutODLYprecision = 2;
epicsExportAddress(int, calcoutODLYprecision);
double calcoutODLYlimit = 100000;
epicsExportAddress(double, calcoutODLYlimit);
typedef struct calcoutDSET {
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN write;
}calcoutDSET;
/* To provide feedback to the user as to the connection status of the
* links (.INxV and .OUTV), the following algorithm has been implemented ...
*
* A new PV_LINK is checked [in both init() and special()] to see if the
* target is local -- if so it is marked as such. If not, a checkLinkCb
* callback is scheduled to check the connection status later by calling
* dbIsLinkConnected(). Anytime there are unconnected CA_LINKs, another
* callback is scheduled. Once all connections are established, the CA_LINKs
* are checked whenever the record processes.
*
*/
#define NO_CA_LINKS 0
#define CA_LINKS_ALL_OK 1
#define CA_LINKS_NOT_OK 2
typedef struct rpvtStruct {
CALLBACK doOutCb;
CALLBACK checkLinkCb;
short cbScheduled;
short caLinkStat; /* NO_CA_LINKS, CA_LINKS_ALL_OK, CA_LINKS_NOT_OK */
} rpvtStruct;
static void checkAlarms(calcoutRecord *prec);
static void monitor(calcoutRecord *prec);
static int fetch_values(calcoutRecord *prec);
static void execOutput(calcoutRecord *prec);
static void checkLinks(calcoutRecord *prec);
static void checkLinksCallback(CALLBACK *arg);
static long writeValue(calcoutRecord *prec);
int calcoutRecDebug;
static long init_record(struct dbCommon *pcommon, int pass)
{
struct calcoutRecord *prec = (struct calcoutRecord *)pcommon;
DBLINK *plink;
int i;
double *pvalue;
epicsEnum16 *plinkValid;
short error_number;
calcoutDSET *pcalcoutDSET;
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++) {
/* Don't InitConstantLink the .OUT link */
if (i < CALCPERFORM_NARGS) {
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
}
if (dbLinkIsConstant(plink)) {
*plinkValid = calcoutINAV_CON;
}
else if (dbLinkIsVolatile(plink)) {
int conn = dbIsLinkConnected(plink);
if (conn)
*plinkValid = calcoutINAV_EXT;
else {
/* Monitor for connection */
*plinkValid = calcoutINAV_EXT_NC;
prpvt->caLinkStat = CA_LINKS_NOT_OK;
}
}
else {
/* PV must reside on this ioc */
*plinkValid = calcoutINAV_LOC;
if (!dbIsLinkConnected(plink)) {
errlogPrintf("calcout: %s.INP%c in no-vo disco state\n",
prec->name, i+'A');
}
}
}
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;
}
static long process(struct dbCommon *pcommon)
{
struct calcoutRecord *prec = (struct calcoutRecord *)pcommon;
rpvtStruct *prpvt = prec->rpvt;
int doOutput;
if (!prec->pact) {
prec->pact = TRUE;
/* if some links are CA, check connections */
if (prpvt->caLinkStat != NO_CA_LINKS) {
checkLinks(prec);
}
if (fetch_values(prec) == 0) {
if (calcPerform(&prec->a, &prec->val, prec->rpcl)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
} else {
prec->udf = isnan(prec->val);
}
}
checkAlarms(prec);
/* check for output link execution */
switch (prec->oopt) {
case calcoutOOPT_Every_Time:
doOutput = 1;
break;
case calcoutOOPT_On_Change:
doOutput = ! (fabs(prec->pval - prec->val) <= prec->mdel);
break;
case calcoutOOPT_Transition_To_Zero:
doOutput = ((prec->pval != 0.0) && (prec->val == 0.0));
break;
case calcoutOOPT_Transition_To_Non_zero:
doOutput = ((prec->pval == 0.0) && (prec->val != 0.0));
break;
case calcoutOOPT_When_Zero:
doOutput = (prec->val == 0.0);
break;
case calcoutOOPT_When_Non_zero:
doOutput = (prec->val != 0.0);
break;
default:
doOutput = 0;
break;
}
prec->pval = prec->val;
if (doOutput) {
if (prec->odly > 0.0) {
prec->dlya = 1;
recGblGetTimeStamp(prec);
db_post_events(prec, &prec->dlya, DBE_VALUE);
callbackRequestProcessCallbackDelayed(&prpvt->doOutCb,
prec->prio, prec, (double)prec->odly);
return 0;
} else {
prec->pact = FALSE;
execOutput(prec);
if (prec->pact) return 0;
prec->pact = TRUE;
}
}
recGblGetTimeStamp(prec);
} else { /* pact == TRUE */
if (prec->dlya) {
prec->dlya = 0;
recGblGetTimeStamp(prec);
db_post_events(prec, &prec->dlya, DBE_VALUE);
/* Make pact FALSE for asynchronous device support*/
prec->pact = FALSE;
execOutput(prec);
if (prec->pact) return 0;
prec->pact = TRUE;
} else {/*Device Support is asynchronous*/
writeValue(prec);
recGblGetTimeStamp(prec);
}
}
monitor(prec);
recGblFwdLink(prec);
prec->pact = FALSE;
return 0;
}
static long special(DBADDR *paddr, int after)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
rpvtStruct *prpvt = prec->rpvt;
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 (fieldIndex != calcoutRecordOUT)
recGblInitConstantLink(plink, DBF_DOUBLE, pvalue);
if (dbLinkIsConstant(plink)) {
db_post_events(prec, pvalue, DBE_VALUE);
*plinkValid = calcoutINAV_CON;
} else if (dbLinkIsVolatile(plink)) {
int conn = dbIsLinkConnected(plink);
if (conn)
*plinkValid = calcoutINAV_EXT;
else {
/* Monitor for connection */
*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;
}
}
}
else {
/* PV must reside on this ioc */
*plinkValid = calcoutINAV_LOC;
if (!dbIsLinkConnected(plink)) {
errlogPrintf("calcout: %s.INP%c in no-vo diso state\n",
prec->name, lnkIndex);
}
}
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);
}
}
#define indexof(field) calcoutRecord##field
static long get_linkNumber(int fieldIndex) {
if (fieldIndex >= indexof(A) && fieldIndex <= indexof(L))
return fieldIndex - indexof(A);
if (fieldIndex >= indexof(LA) && fieldIndex <= indexof(LL))
return fieldIndex - indexof(LA);
return -1;
}
static long get_units(DBADDR *paddr, char *units)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if(fieldIndex == indexof(ODLY)) {
strcpy(units, "s");
return 0;
}
if(paddr->pfldDes->field_type == DBF_DOUBLE) {
linkNumber = get_linkNumber(dbGetFieldIndex(paddr));
if (linkNumber >= 0)
dbGetUnits(&prec->inpa + linkNumber, units, DB_UNITS_SIZE);
else
strncpy(units,prec->egu,DB_UNITS_SIZE);
}
return 0;
}
static long get_precision(const DBADDR *paddr, long *pprecision)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if (fieldIndex == indexof(ODLY)) {
*pprecision = calcoutODLYprecision;
return 0;
}
*pprecision = prec->prec;
if (fieldIndex == indexof(VAL))
return 0;
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
short precision;
if (dbGetPrecision(&prec->inpa + linkNumber, &precision) == 0)
*pprecision = precision;
} else
recGblGetPrec(paddr, pprecision);
return 0;
}
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
switch (fieldIndex) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pgd->lower_disp_limit = prec->lopr;
pgd->upper_disp_limit = prec->hopr;
break;
case indexof(ODLY):
recGblGetGraphicDouble(paddr,pgd);
pgd->lower_disp_limit = 0.0;
break;
default:
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetGraphicLimits(&prec->inpa + linkNumber,
&pgd->lower_disp_limit,
&pgd->upper_disp_limit);
} else
recGblGetGraphicDouble(paddr,pgd);
}
return 0;
}
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
switch (dbGetFieldIndex(paddr)) {
case indexof(VAL):
case indexof(HIHI):
case indexof(HIGH):
case indexof(LOW):
case indexof(LOLO):
case indexof(LALM):
case indexof(ALST):
case indexof(MLST):
pcd->lower_ctrl_limit = prec->lopr;
pcd->upper_ctrl_limit = prec->hopr;
break;
case indexof(ODLY):
pcd->lower_ctrl_limit = 0.0;
pcd->upper_ctrl_limit = calcoutODLYlimit;
break;
default:
recGblGetControlDouble(paddr,pcd);
}
return 0;
}
static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
calcoutRecord *prec = (calcoutRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
int linkNumber;
if (fieldIndex == indexof(VAL)) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else {
linkNumber = get_linkNumber(fieldIndex);
if (linkNumber >= 0) {
dbGetAlarmLimits(&prec->inpa + linkNumber,
&pad->lower_alarm_limit,
&pad->lower_warning_limit,
&pad->upper_warning_limit,
&pad->upper_alarm_limit);
} else
recGblGetAlarmDouble(paddr, pad);
}
return 0;
}
static void checkAlarms(calcoutRecord *prec)
{
double val, hyst, lalm;
double alev;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
return;
}
val = prec->val;
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
prec->lalm = alev;
return;
}
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
}
static void execOutput(calcoutRecord *prec)
{
/* Determine output data */
switch(prec->dopt) {
case calcoutDOPT_Use_VAL:
prec->oval = prec->val;
break;
case calcoutDOPT_Use_OVAL:
if (calcPerform(&prec->a, &prec->oval, prec->orpc)) {
recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM);
} else {
prec->udf = isnan(prec->oval);
}
break;
}
if (prec->udf){
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
}
/* Check to see what to do if INVALID */
if (prec->nsev < INVALID_ALARM ) {
/* Output the value */
writeValue(prec);
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
} else switch (prec->ivoa) {
case menuIvoaContinue_normally:
writeValue(prec);
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
break;
case menuIvoaDon_t_drive_outputs:
break;
case menuIvoaSet_output_to_IVOV:
prec->oval = prec->ivov;
writeValue(prec);
/* post output event if set */
if (prec->epvt) postEvent(prec->epvt);
break;
default:
recGblRecordError(S_db_badField, (void *)prec,
"calcout:process Illegal IVOA field");
}
}
static void monitor(calcoutRecord *prec)
{
unsigned monitor_mask;
double *pnew;
double *pprev;
int i;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
recGblCheckDeadband(&prec->mlst, prec->val, prec->mdel, &monitor_mask, DBE_VALUE);
/* check for archive change */
recGblCheckDeadband(&prec->alst, prec->val, prec->adel, &monitor_mask, DBE_ARCHIVE);
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec, &prec->val, monitor_mask);
}
/* check all input fields for changes*/
for (i = 0, pnew = &prec->a, pprev = &prec->la; i<CALCPERFORM_NARGS;
i++, pnew++, pprev++) {
if ((*pnew != *pprev) || (monitor_mask&DBE_ALARM)) {
db_post_events(prec, pnew, monitor_mask|DBE_VALUE|DBE_LOG);
*pprev = *pnew;
}
}
/* Check OVAL field */
if (prec->povl != prec->oval) {
db_post_events(prec, &prec->oval, monitor_mask|DBE_VALUE|DBE_LOG);
prec->povl = prec->oval;
}
return;
}
static int fetch_values(calcoutRecord *prec)
{
DBLINK *plink; /* structure of the link field */
double *pvalue;
long status = 0;
int i;
for (i = 0, plink = &prec->inpa, pvalue = &prec->a; i<CALCPERFORM_NARGS;
i++, plink++, pvalue++) {
int newStatus;
newStatus = dbGetLink(plink, DBR_DOUBLE, pvalue, 0, 0);
if (!status) status = newStatus;
}
return(status);
}
static void checkLinksCallback(CALLBACK *arg)
{
calcoutRecord *prec;
rpvtStruct *prpvt;
callbackGetUser(prec, arg);
prpvt = prec->rpvt;
dbScanLock((dbCommon *)prec);
prpvt->cbScheduled = 0;
checkLinks(prec);
dbScanUnlock((dbCommon *)prec);
}
static void checkLinks(calcoutRecord *prec)
{
DBLINK *plink;
rpvtStruct *prpvt = prec->rpvt;
int i;
int stat;
int caLink = 0;
int caLinkNc = 0;
epicsEnum16 *plinkValid;
if (calcoutRecDebug) printf("checkLinks() for %p\n", prec);
plink = &prec->inpa;
plinkValid = &prec->inav;
for (i = 0; i<CALCPERFORM_NARGS+1; i++, plink++, plinkValid++) {
if (dbLinkIsVolatile(plink)) {
caLink = 1;
stat = dbIsLinkConnected(plink);
if (!stat && (*plinkValid == calcoutINAV_EXT_NC)) {
caLinkNc = 1;
}
else if (!stat && (*plinkValid == calcoutINAV_EXT)) {
*plinkValid = calcoutINAV_EXT_NC;
db_post_events(prec, plinkValid, DBE_VALUE);
caLinkNc = 1;
}
else if (stat && (*plinkValid == calcoutINAV_EXT_NC)) {
*plinkValid = calcoutINAV_EXT;
db_post_events(prec, plinkValid, DBE_VALUE);
}
}
}
if (caLinkNc)
prpvt->caLinkStat = CA_LINKS_NOT_OK;
else if (caLink)
prpvt->caLinkStat = CA_LINKS_ALL_OK;
else
prpvt->caLinkStat = NO_CA_LINKS;
if (!prpvt->cbScheduled && caLinkNc) {
/* Schedule another CALLBACK */
prpvt->cbScheduled = 1;
callbackRequestDelayed(&prpvt->checkLinkCb, .5);
}
}
static long writeValue(calcoutRecord *prec)
{
calcoutDSET *pcalcoutDSET = (calcoutDSET *)prec->dset;
if (!pcalcoutDSET || !pcalcoutDSET->write) {
errlogPrintf("%s DSET write does not exist\n", prec->name);
recGblSetSevr(prec, SOFT_ALARM, INVALID_ALARM);
prec->pact = TRUE;
return(-1);
}
return pcalcoutDSET->write(prec);
}