Files
epics-base/src/libCom/sydSubrSSF.c

1095 lines
32 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.
/* $Id$
* Author: Roger A. Cole
* Date: 12-04-90
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991-92, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .00 12-04-90 rac initial version
* .01 06-18-91 rac installed in SCCS
* .02 06-19-91 rac replace <fields.h> with <alarm.h>
* .03 08-14-91 rac
* .04 02-27-92 rac do ts rounding here instead of sydSubr.c
* .05 08-18-92 rac add SYD_FC_STOP function code
* .06 09-09-92 rac allow reading text values such as `no data'; look at
* the _end_ of the file to do name searches; handle
* channels which are missing and/or disconnected;
* discontinue use of special malloc routines
*
* make options
* -DvxWorks makes a version for VxWorks
* -DNDEBUG don't compile assert() checking
* -DDEBUG compile various debug code
*/
/*+/mod***********************************************************************
* TITLE sydSubrSSF.c - acquire synchronous samples from AR `sample set' files
*
* DESCRIPTION
*
*-***************************************************************************/
#include <genDefs.h>
#define SYD_PRIVATE
#include <sydDefs.h>
#include <alarm.h>
#ifndef INC_tsDefs_h
# include <tsDefs.h>
#endif
#ifndef INCLcadefh
# include <cadef.h>
#endif
#ifdef vxWorks
# include <vxWorks.h>
# include <ioLib.h> /* for O_RDWR and O_RDONLY definitions */
# include <stdioLib.h>
# include <strLib.h>
#else
# include <stdio.h>
# include <sys/file.h> /* for O_RDWR and O_RDONLY definitions */
# include <string.h>
# include <strings.h>
#endif
long sydSSFFunc();
static long sydSSFFuncGetGR();
static long sydSSFFuncReadData();
static long sydSSFFuncSeekSample();
static long sydSSFFuncSeekStamp();
/*+/macro*********************************************************************
* NAME posXxx - text file search and positioning routines
*
* DESCRIPTION
* These routines allow setting the position for text files. The
* file may be positioned at its beginning or its end. It is
* supported to search, either forward or backward, for a string,
* leaving the file positioned at the beginning of the string.
*
* long pos;
* FILE *pStream;
*
* pos = posBOF(pStream);
* pos = posEOF(pStream);
* pos = posKeyFwd("key", pStream);
* pos = posKeyRev("key", pStream, pos);
* pos = posPos(pStream, pos);
*
* RETURNS
* position, or
* <0 if an error occurs
*
* BUGS
* o the use of fseek and ftell doesn't match the Standard C specification
* and may be non-portable. They have been verified to function
* properly under SunOS 4.1 and VxWorks 4.0.2.
*
*-*/
static long posBOF();
static long posEOF();
static long posKeyFwd();
static long posKeyRev();
static long posPos();
/*+/internal******************************************************************
* NAME posBOF - position file at the beginning
*
*-*/
static long
posBOF(pStream)
FILE *pStream;
{
if (fseek(pStream, 0L, 0) < 0) {
perror("posBOF: fseek error");
return -1;
}
return ftell(pStream);
}
/*+/internal******************************************************************
* NAME posEOF - position file at the end
*
*-*/
static long
posEOF(pStream)
FILE *pStream;
{
if (fseek(pStream, 0L, 2) < 0) {
perror("posEOF: fseek error");
return -1;
}
return ftell(pStream);
}
/*+/internal******************************************************************
* NAME posKeyFwd - search forward for a string
*
* RETURNS
* position of key (its first character), or
* -1 if search fails
*
*-*/
static long
posKeyFwd(key, pStream)
char *key;
FILE *pStream;
{
int i, lastChar;
int c;
long pos;
lastChar = strlen(key) - 1;
i = 0;
if ((pos = ftell(pStream)) < 0) {
if (!feof(pStream))
perror("posKeyFwd: ftell error");
return -1;
}
while (1) {
if ((c = fgetc(pStream)) == EOF)
return -1;
if ((char)c == key[i]) {
if (i == lastChar)
break;
i++;
}
else {
if (i == 0) {
if ((pos = ftell(pStream)) < 0) {
if (!feof(pStream))
perror("posKeyFwd: ftell error");
return -1;
}
}
else if (i == 1) {
pos++;
if ((char)c != key[0])
i = 0;
}
else {
pos++;
if (fseek(pStream, pos, 0) != 0) {
if (!feof(pStream))
perror("posKeyFwd: fseek error");
return -1;
}
i = 0;
}
}
}
if (fseek(pStream, pos, 0) != 0) {
if (!feof(pStream))
perror("posKeyFwd: fseek error");
return -1;
}
return pos;
}
/*+/internal******************************************************************
* NAME posKeyRev - search backward for a string
*
* RETURNS
* position of key (its first character), or
* -1 if search fails
*
*-*/
static long
posKeyRev(key, pStream, lastPos)
char *key;
FILE *pStream;
long lastPos; /* I position to start search; -1 for EOF */
{
int i, lastChar;
int c;
long pos;
lastChar = i = strlen(key) - 1;
if (lastPos >= 0) {
if (fseek(pStream, lastPos, 0) != 0) {
if (!feof(pStream))
perror("posKeyRev: fseek error");
return -1;
}
}
else {
if (fseek(pStream, 0L, 2) != 0) {
if (!feof(pStream))
perror("posKeyRev: fseek error");
return -1;
}
}
while (1) {
if (ftell(pStream) <= 0)
return -1;
if (fseek(pStream, -1L, 1) != 0) {
if (!feof(pStream))
perror("posKeyRev: fseek error");
return -1;
}
if ((c = fgetc(pStream)) == EOF)
return -1;
if (fseek(pStream, -1L, 1) != 0) {
if (!feof(pStream))
perror("posKeyRev: fseek error");
return -1;
}
if ((char)c == key[i]) {
if (i == 0)
break;
i--;
}
else
i = lastChar;
}
if ((pos = ftell(pStream)) < 0)
perror("posKeyRev: ftell error");
return pos;
}
/*+/internal******************************************************************
* NAME posPos - set file to desired position
*
*-*/
static long
posPos(pStream, pos)
FILE *pStream;
long pos;
{
if (fseek(pStream, pos, 0) < 0) {
perror("posPos: fseek error");
return -1;
}
return ftell(pStream);
}
/*+/subr**********************************************************************
* NAME sydOpenSSF
*
*-*/
long
sydOpenSSF(ppSspec, filePath)
SYD_SPEC **ppSspec; /* O pointer to synchronous set spec pointer */
char *filePath; /* I path name for `sample set' archive file */
{
long stat;
assert(ppSspec != NULL);
if ((*ppSspec = (SYD_SPEC *)malloc(sizeof(SYD_SPEC))) == NULL)
return S_syd_noMem;
(*ppSspec)->pFunc = sydSSFFunc;
(*ppSspec)->type = SYD_TY_SSF;
if ((stat = sydSSFFunc(*ppSspec, NULL,SYD_FC_INIT,filePath)) != S_syd_OK){
free((char *)*ppSspec);
*ppSspec = NULL;
return stat;
}
(*ppSspec)->nInBufs = 2;
return sydOpen(ppSspec);
}
/*+/subr**********************************************************************
* NAME sydSSFFunc - handle "sample set" data file interactions
*
* DESCRIPTION
*
* sydSSFFunc(pSspec, NULL, SYD_FC_INIT, filePath) open "sample set" file
* sydSSFFunc(pSspec, pSChan, SYD_FC_OPEN, NULL) chanName already in pSChan
* sydSSFFunc(pSspec, pSChan, SYD_FC_READ, NULL)
* sydSSFFunc(pSspec, pSChan, SYD_FC_POSITION, &stamp)
* sydSSFFunc(pSspec, pSChan, SYD_FC_CLOSE, NULL)
* sydSSFFunc(pSspec, NULL, SYD_FC_FILEINFO, outStream)
* sydSSFFunc(pSspec, NULL, SYD_FC_WRAPUP, NULL) close "sample set" file
*
* RETURNS
* S_syd_OK, or
* S_syd_EOF, or
* other code indicating error
*
* BUGS
* o doesn't detect or report EOF
* o doesn't do anything (or even detect) overwriting un-sampled
* buffers (for SYD_FC_READ)
* o needs a "get graphics information" function and function code
* o if a channel wasn't connected when the last snapshot in the file
* was written, its elCount is assumed to be 1
*
* SEE ALSO
*
* EXAMPLE
*
*-*/
long
sydSSFFunc(pSspec, pStruct, funcCode, pArg)
SYD_SPEC *pSspec; /* IO pointer to synchronous set spec */
void *pStruct; /* IO pointer to data struct used by funcCode */
enum sydFuncCode funcCode;/* I function code */
void *pArg; /* I pointer to arg, as required by funcCode */
{
SYD_CHAN *pSChan; /* pointer to syncSet channel descriptor */
FILE *ssFile; /* file pointer for sample set data file */
long retStat=S_syd_OK;
long stat;
int i;
long pos;
char record[120];
char recDelim;
char *pRecord;
char *pField;
char delim;
char chanName[db_name_dim+2];
chtype type;
int elCount;
pSChan = (SYD_CHAN *)pStruct;
if (pSspec != NULL)
ssFile = (FILE *)pSspec->pHandle;
if (funcCode == SYD_FC_INIT) {
if ((ssFile = fopen((char *)pArg, "r")) == NULL) {
(void)printf("couldn't open %s\n", (char *)pArg);
perror(NULL);
retStat = S_syd_ERROR;
}
pSspec->pHandle = (void *)ssFile;
}
else if (funcCode == SYD_FC_OPEN) {
if ((pos = posKeyRev("%endHeader%", ssFile, -1L)) < 0) {
(void)printf("couldn't find %%endHeader%%\n");
(void)posBOF(ssFile);
return S_syd_chanNotFound;
}
strcpy(chanName, "\n");
strcat(chanName, pSChan->name);
strcat(chanName, " ");
if ((pos = posKeyFwd(chanName, ssFile)) < 0)
return S_syd_chanNotFound;
assert(sizeof(record) == 120);
fgetc(ssFile); /* skip over the \n */
if (fgets(record, 120, ssFile) == NULL)
assertAlways(0);
pRecord = record;
recDelim = record[strlen(record)-1];
if (nextChanNameField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
if (strcmp(pField, pSChan->name) != 0)
assertAlways(0);
pSChan->pHandle = NULL;
if (nextAlphField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
dbf_text_to_type(pField, type);
if (type >= 0) {
pSChan->dbfType = type;
pSChan->dbrType = dbf_type_to_DBR_TIME(type);
pSChan->dbrGrType = dbf_type_to_DBR_GR(type);
stat = sscanf(pRecord, "%*d %*d %d", &elCount);
assert(stat == 1);
pSChan->elCount = elCount;
}
else {
pSChan->dbfType = TYPENOTCONN;
pSChan->dbrType = TYPENOTCONN;
pSChan->dbrGrType = TYPENOTCONN;
pSChan->elCount = 1;
}
sydSSFFuncGetGR(pSspec, pSChan);
pSChan->sync = SYD_SY_NONF; /* force channel to be sync */
(void)posBOF(ssFile);
}
else if (funcCode == SYD_FC_READ) {
TS_STAMP timeStamp;
enum sydBStatus bufStat, newStat;
int bufNum, oldBufNum, first=1;
char typeText[80];
/*-----------------------------------------------------------------------------
* find the next line with SAMPLE: and get the time stamp. When done:
* o bufStat will be one of:
* SYD_B_RESTART this sample starts a new "run" of data
* SYD_B_FULL this is an ordinary sample
* SYD_B_EOF end of file
* SYD_B_MISSING no value for this channel i nthis sample
* o the file will be positioned following the %endHeader% line
* o if time stamp rounding has been requested, it will be done
*----------------------------------------------------------------------------*/
while (1) {
newStat = SYD_B_EMPTY;
bufStat = sydSSFFuncSeekSample(ssFile, &timeStamp);
if (pSspec->roundNsec > 0)
sydTsRound(&timeStamp, pSspec->roundNsec);
/*-----------------------------------------------------------------------------
* now, read the actual data. This is done by processing all the data
* lines in the file, storing those which match a channel in the synchronous
* set. (This is somewhat contrary to the "advertising" for this function
* code, which implies that only a single channel is read.) When done:
* o all channels in the set will have an appropriate buffer status
* o all channels will have the same time stamp
* o all channels with data will have the data in the buffer
* o all channels will have .lastInBuf updated
*----------------------------------------------------------------------------*/
pSChan = pSspec->pChanHead;
if (first) {
oldBufNum = pSChan->lastInBuf;
bufNum = NEXT_INBUF(pSChan, oldBufNum);
first = 0;
}
while (pSChan != NULL) {
if (bufStat != SYD_B_EOF)
pSChan->inStatus[bufNum] = SYD_B_MISSING;
else
pSChan->inStatus[bufNum] = bufStat;
pSChan->pInBuf[bufNum]->tfltval.stamp = timeStamp;
pSChan->lastInBuf = bufNum;
if (pSChan->firstInBuf < 0)
pSChan->firstInBuf = bufNum;
pSChan = pSChan->pNext;
}
if (bufStat == SYD_B_EOF)
return S_syd_EOF;
while (1) {
stat = fscanf(ssFile, "%s", chanName);
assert(stat == 1);
if ((pSChan = sydChanFind(pSspec, chanName)) != NULL) {
(void)fscanf(ssFile, "%s", typeText);
dbf_text_to_type(typeText, type);
if (pSChan->dbfType == TYPENOTCONN && type >= 0) {
pSChan->dbfType = type;
pSChan->dbrType = dbf_type_to_DBR_TIME(type);
pSChan->dbrGrType = dbf_type_to_DBR_GR(type);
sydSSFFuncGetGR(pSspec, pSChan);
}
stat = sydSSFFuncReadData(pSChan, ssFile,
bufStat, bufNum, oldBufNum, type);
if (pSChan->inStatus[bufNum] != SYD_B_MISSING &&
newStat == SYD_B_EMPTY) {
newStat = pSChan->inStatus[bufNum];
}
}
else if (strcmp(chanName, "%endData%") == 0)
break;
else {
while ((delim = fgetc(ssFile)) != EOF && delim != '\n')
; /* keep skipping until end of line */
}
}
if (newStat != SYD_B_EMPTY)
break;
}
}
else if (funcCode == SYD_FC_STOP) {
}
else if (funcCode == SYD_FC_POSITION) {
TS_STAMP *pStamp;
TS_STAMP stamp, earlyStamp;
long earlyPos;
pStamp = (TS_STAMP *)pArg;
if (pStamp == NULL) {
(void)posBOF(ssFile);
return retStat;
}
/*-----------------------------------------------------------------------------
* find 2 adjacent samples to make it easy to determine which way to
* search. There are several cases:
* 1. the file is at least 2 away from EOF and both stamps can be found
* forward
* 2. the file is 1 away from EOF--1 stamp backward and 1 forward
* 3. the file contains no stamps
* 4. the file is at EOF and both stamps must be found backward
* 5. the file only contains one stamp
*
* Cases 2 and 4 are treated by rewinding the file to avoid any backward
* searching. This transforms those cases into one of the other cases.
*
* When this section is done, `earlyStamp' and `stamp' will contain two
* adjacent stamps. If they are equal, then case 4 exists. The file
* will be positioned following `stamp'.
*----------------------------------------------------------------------------*/
earlyPos = sydSSFFuncSeekStamp(ssFile, &earlyStamp, 0, 0L);
pos = sydSSFFuncSeekStamp(ssFile, &stamp, 0, 0L);
if (earlyPos < 0 || pos < 0) {
(void)posBOF(ssFile);
earlyPos = sydSSFFuncSeekStamp(ssFile, &earlyStamp, 0, 0L);
if ((pos = sydSSFFuncSeekStamp(ssFile, &stamp, 0, 0L)) < 0) {
stamp = earlyStamp;
pos = earlyPos;
}
}
if (earlyPos < 0)
return S_syd_ERROR;
if (TsCmpStampsLT(pStamp, &earlyStamp)) {
(void)posBOF(ssFile);
earlyPos = sydSSFFuncSeekStamp(ssFile, &earlyStamp, 0, 0L);
if ((pos = sydSSFFuncSeekStamp(ssFile, &stamp, 0, 0L)) < 0) {
stamp = earlyStamp;
pos = earlyPos;
}
}
if (earlyPos < 0)
return S_syd_ERROR;
/*-----------------------------------------------------------------------------
* now, find the record with the proper time stamp, going forward
*----------------------------------------------------------------------------*/
while (1) {
if (TsCmpStampsLE(pStamp, &earlyStamp))
break;
else if (TsCmpStampsLE(pStamp, &stamp) &&
TsCmpStampsGE(pStamp, &earlyStamp)) {
if (TsCmpStampsEQ(pStamp, &earlyStamp)) {
stamp = earlyStamp;
pos = earlyPos;
}
break;
}
else if (TsCmpStampsEQ(&earlyStamp, &stamp))
break;
else if (TsCmpStampsGT(pStamp, &stamp)) {
earlyStamp = stamp;
earlyPos = pos;
pos = sydSSFFuncSeekStamp(ssFile, &stamp, 0, earlyPos);
if (pos < 0) {
stamp = earlyStamp;
pos = earlyPos;
}
}
}
/*-----------------------------------------------------------------------------
* finally, position the file at the proper record
*----------------------------------------------------------------------------*/
if (TsCmpStampsGT(pStamp, &stamp))
return S_syd_EOF;
if (TsCmpStampsLE(pStamp, &earlyStamp))
(void)posPos(ssFile, earlyPos);
else
(void)posPos(ssFile, pos);
}
else if (funcCode == SYD_FC_CLOSE) {
; /* no action to close a channel in sample set files */
}
else if (funcCode == SYD_FC_FILEINFO) {
TS_STAMP oldestStamp;
char oldestStampText[28];
TS_STAMP newestStamp;
char newestStampText[28];
int j;
if (posBOF(ssFile) < 0) {
(void)fprintf((FILE *)pArg, "error positioning file\n");
return S_syd_ERROR;
}
if (sydSSFFuncSeekStamp(ssFile, &oldestStamp, 0, 0L) < 0) {
(void)fprintf((FILE *)pArg, "error finding oldest time stamp\n");
return S_syd_ERROR;
}
if (sydSSFFuncSeekStamp(ssFile, &newestStamp, 1, -1L) < 0) {
(void)fprintf((FILE *)pArg, "error finding newest time stamp\n");
return S_syd_ERROR;
}
(void)fprintf((FILE *)pArg, "data from %s through %s\n",
tsStampToText(&oldestStamp, TS_TEXT_MMDDYY, oldestStampText),
tsStampToText(&newestStamp, TS_TEXT_MMDDYY, newestStampText) );
if (posKeyRev("%endHeader%", ssFile, -1L) < 0) {
(void)fprintf((FILE *)pArg,
"error locating %%endHeader%% in file\n");
return S_syd_ERROR;
}
(void)fgets(record, 120, ssFile); /* skip over endHeader */
while (1) {
if (fgets(record, 120, ssFile) == NULL) {
(void)fprintf((FILE *)pArg, "error reading channel name\n");
return S_syd_ERROR;
}
pRecord = record;
recDelim = record[strlen(record)-1];
if (nextChanNameField(&pRecord, &pField, &delim) <= 1) {
(void)fprintf((FILE *)pArg, "error reading channel type\n");
return S_syd_ERROR;
}
if (strcmp(pField, "%endData%") == 0)
break;
(void)strcpy(chanName, pField);
if (nextAlphField(&pRecord, &pField, &delim) <= 1) {
(void)fprintf((FILE *)pArg, "error reading channel type\n");
return S_syd_ERROR;
}
if (sscanf(pRecord, "%*d %*d %d", &elCount) != 1) {
(void)fprintf((FILE *)pArg, "error reading element count\n");
return S_syd_ERROR;
}
j = strlen(chanName);
if (j > 4) {
if (strncmp(&chanName[j-4], ".VAL", 4) == 0)
chanName[j-4] = '\0';
}
(void)fprintf((FILE *)pArg, "%s %d %s\n",
chanName, elCount, pField);
if (recDelim != '\n') {
while ((delim = fgetc(ssFile)) != EOF && delim != '\n')
; /* keep skipping until end of line */
}
}
if (posBOF(ssFile) < 0) {
(void)fprintf((FILE *)pArg, "error positioning file\n");
return S_syd_ERROR;
}
}
else if (funcCode == SYD_FC_WRAPUP) {
if (ssFile != NULL)
(void)close(ssFile);
pSspec->pHandle = NULL;
}
return retStat;
}
/*+/internal******************************************************************
* NAME sydSSFFuncReadData
*
* DESCRIPTION
* Read data from the file into the sync set. An entire snapshot is
* read. For each channel in the snapshot, the data is stored in the
* sync set only if the channel is in the set.
*
* BUGS
* o if a channel has a smaller elCount in the file than in the sync set,
* then the `extra' values in the sync set will be garbage
*
*-*/
static long
sydSSFFuncReadData(pSChan, ssFile, bufStat, bufNum, oldBufNum, type)
SYD_CHAN *pSChan; /* pointer to syncSet channel descriptor */
FILE *ssFile;
int bufStat, bufNum, oldBufNum;
chtype type;
{
long stat;
int alStat, alSev, elCount;
int i;
/*-----------------------------------------------------------------------------
* first, get and store the alarm status and severity .
* (This is done using the "float" form of the buffer, which is
* possible because for these items all types of buffers look the same.)
*----------------------------------------------------------------------------*/
stat = fscanf(ssFile, "%d%d%d", &alSev, &alStat, &elCount);
assert(stat == 3);
pSChan->pInBuf[bufNum]->tfltval.status = alStat;
pSChan->pInBuf[bufNum]->tfltval.severity = alSev;
/*-----------------------------------------------------------------------------
* now get the actual data
*----------------------------------------------------------------------------*/
if (pSChan->dbrType == TYPENOTCONN || type == TYPENOTCONN) {
stat = fscanf(ssFile, "%*s");
bufStat = SYD_B_MISSING;
}
else if (pSChan->dbrType == DBR_TIME_FLOAT) {
float *pFl, val;
pFl = &pSChan->pInBuf[bufNum]->tfltval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%f", &val);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
else if (i < (int) pSChan->elCount)
*pFl++ = val;
}
}
else if (pSChan->dbrType == DBR_TIME_SHORT) {
short *pSh, val;
pSh = &pSChan->pInBuf[bufNum]->tshrtval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%hd", &val);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
else if (i < (int) pSChan->elCount)
*pSh++ = val;
}
}
else if (pSChan->dbrType == DBR_TIME_DOUBLE) {
double *pDbl, val;
pDbl = &pSChan->pInBuf[bufNum]->tdblval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%lf", &val);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
else if (i < (int) pSChan->elCount)
*pDbl++ = val;
}
}
else if (pSChan->dbrType == DBR_TIME_LONG) {
long *pL, val;
pL = &pSChan->pInBuf[bufNum]->tlngval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%ld", &val);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
else if (i < (int) pSChan->elCount)
*pL++ = val;
}
}
else if (pSChan->dbrType == DBR_TIME_STRING) {
char *pC, val[db_strval_dim];
int nChar;
pC = pSChan->pInBuf[bufNum]->tstrval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%d", &nChar);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
assert(nChar > 0 && nChar < db_strval_dim);
if (fgets(val, nChar, ssFile) == NULL)
assertAlways(0);
if (i < (int) pSChan->elCount) {
strcpy(pC, val);
pC += db_strval_dim;
}
}
}
else if (pSChan->dbrType == DBR_TIME_CHAR) {
unsigned char *pC, val;
pC = &pSChan->pInBuf[bufNum]->tchrval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%c", &val);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
else if (i < (int) pSChan->elCount)
*pC++ = val;
}
}
else if (pSChan->dbrType == DBR_TIME_ENUM) {
unsigned short *pSh;
char state[80];
int iState;
pSh = &pSChan->pInBuf[bufNum]->tenmval.value;
for (i=0; i<elCount; i++) {
stat = fscanf(ssFile, "%s", state);
if (stat != 1) {
bufStat = SYD_B_MISSING;
break;
}
assert(strlen(state) < db_state_text_dim);
iState = 0;
while (1) {
if (iState >= pSChan->grBuf.genmval.no_str) {
pSChan->grBuf.genmval.no_str++;
(void)strcpy(pSChan->grBuf.genmval.strs[iState], state);
break;
}
else if (strcmp(pSChan->grBuf.genmval.strs[iState],state) == 0)
break;
iState++;
assert(iState < db_state_dim);
}
if (i < (int) pSChan->elCount)
*pSh++ = iState;
}
}
/*-----------------------------------------------------------------------------
* set the buffer status. If the previous record had a status of MISSING,
* then the buffer status will be SYD_B_RESTART; otherwise, the caller's
* status will be used. (Unless, of course, this routine discovered that
* the status needs to be something else.)
*----------------------------------------------------------------------------*/
if (bufStat == SYD_B_MISSING)
pSChan->inStatus[bufNum] = bufStat;
else if (oldBufNum >= 0 && pSChan->inStatus[oldBufNum] == SYD_B_MISSING)
pSChan->inStatus[bufNum] = SYD_B_RESTART;
else
pSChan->inStatus[bufNum] = bufStat;
return S_syd_OK;
}
/*+/internal******************************************************************
* NAME sydSSFFuncGetGR - simulate getting graphics information
*
*-*/
static long
sydSSFFuncGetGR(pSspec, pSChan)
SYD_SPEC *pSspec; /* pointer to syncSet specification */
SYD_CHAN *pSChan; /* pointer to syncSet channel descriptor */
{
int i;
if (pSChan->dbrType == DBR_TIME_FLOAT) {
#define FLT_DEST pSChan->grBuf.gfltval
FLT_DEST.status = NO_ALARM;
FLT_DEST.severity = NO_ALARM;
#if 1
FLT_DEST.precision = 3;
(void)strcpy(FLT_DEST.units, " ");
FLT_DEST.upper_disp_limit = 0.;
FLT_DEST.lower_disp_limit = 0.;
FLT_DEST.upper_alarm_limit = 0.;
FLT_DEST.lower_alarm_limit = 0.;
FLT_DEST.upper_warning_limit = 0.;
FLT_DEST.lower_warning_limit = 0.;
#else
#define FLT_SRC ArCDChanHdr(pChanDesc).graphics.floatGr
(void)strcpy(FLT_DEST.units, FLT_SRC.units);
FLT_DEST.upper_disp_limit = FLT_SRC.upDispLim;
FLT_DEST.lower_disp_limit = FLT_SRC.lowDispLim;
FLT_DEST.upper_alarm_limit = FLT_SRC.upAlmLim;
FLT_DEST.lower_alarm_limit = FLT_SRC.lowAlmLim;
FLT_DEST.upper_warning_limit = FLT_SRC.upWarnLim;
FLT_DEST.lower_warning_limit = FLT_SRC.lowWarnLim;
#endif
}
else if (pSChan->dbrType == DBR_TIME_SHORT) {
#define SHRT_DEST pSChan->grBuf.gshrtval
SHRT_DEST.status = NO_ALARM;
SHRT_DEST.severity = NO_ALARM;
#if 1
(void)strcpy(SHRT_DEST.units, " ");
SHRT_DEST.upper_disp_limit = 0;
SHRT_DEST.lower_disp_limit = 0;
SHRT_DEST.upper_alarm_limit = 0;
SHRT_DEST.lower_alarm_limit = 0;
SHRT_DEST.upper_warning_limit = 0;
SHRT_DEST.lower_warning_limit = 0;
#else
#define SHRT_SRC ArCDChanHdr(pChanDesc).graphics.shortGr
(void)strcpy(SHRT_DEST.units, SHRT_SRC.units);
SHRT_DEST.upper_disp_limit = SHRT_SRC.upDispLim;
SHRT_DEST.lower_disp_limit = SHRT_SRC.lowDispLim;
SHRT_DEST.upper_alarm_limit = SHRT_SRC.upAlmLim;
SHRT_DEST.lower_alarm_limit = SHRT_SRC.lowAlmLim;
SHRT_DEST.upper_warning_limit = SHRT_SRC.upWarnLim;
SHRT_DEST.lower_warning_limit = SHRT_SRC.lowWarnLim;
#endif
}
else if (pSChan->dbrType == DBR_TIME_DOUBLE) {
#define DBL_DEST pSChan->grBuf.gdblval
DBL_DEST.status = NO_ALARM;
DBL_DEST.severity = NO_ALARM;
#if 1
DBL_DEST.precision = 3;
(void)strcpy(DBL_DEST.units, " ");
DBL_DEST.upper_disp_limit = 0.;
DBL_DEST.lower_disp_limit = 0.;
DBL_DEST.upper_alarm_limit = 0.;
DBL_DEST.lower_alarm_limit = 0.;
DBL_DEST.upper_warning_limit = 0.;
DBL_DEST.lower_warning_limit = 0.;
#else
#define DBL_SRC ArCDChanHdr(pChanDesc).graphics.doubleGr
(void)strcpy(DBL_DEST.units, DBL_SRC.units);
DBL_DEST.upper_disp_limit = DBL_SRC.upDispLim;
DBL_DEST.lower_disp_limit = DBL_SRC.lowDispLim;
DBL_DEST.upper_alarm_limit = DBL_SRC.upAlmLim;
DBL_DEST.lower_alarm_limit = DBL_SRC.lowAlmLim;
DBL_DEST.upper_warning_limit = DBL_SRC.upWarnLim;
DBL_DEST.lower_warning_limit = DBL_SRC.lowWarnLim;
#endif
}
else if (pSChan->dbrType == DBR_TIME_LONG) {
#define LNG_DEST pSChan->grBuf.glngval
LNG_DEST.status = NO_ALARM;
LNG_DEST.severity = NO_ALARM;
#if 1
(void)strcpy(LNG_DEST.units, " ");
LNG_DEST.upper_disp_limit = 0;
LNG_DEST.lower_disp_limit = 0;
LNG_DEST.upper_alarm_limit = 0;
LNG_DEST.lower_alarm_limit = 0;
LNG_DEST.upper_warning_limit = 0;
LNG_DEST.lower_warning_limit = 0;
#else
#define LNG_SRC ArCDChanHdr(pChanDesc).graphics.longGr
(void)strcpy(LNG_DEST.units, LNG_SRC.units);
LNG_DEST.upper_disp_limit = LNG_SRC.upDispLim;
LNG_DEST.lower_disp_limit = LNG_SRC.lowDispLim;
LNG_DEST.upper_alarm_limit = LNG_SRC.upAlmLim;
LNG_DEST.lower_alarm_limit = LNG_SRC.lowAlmLim;
LNG_DEST.upper_warning_limit = LNG_SRC.upWarnLim;
LNG_DEST.lower_warning_limit = LNG_SRC.lowWarnLim;
#endif
}
else if (pSChan->dbrType == DBR_TIME_STRING) {
#define STR_DEST pSChan->grBuf.gstrval
STR_DEST.status = NO_ALARM;
STR_DEST.severity = NO_ALARM;
}
else if (pSChan->dbrType == DBR_TIME_ENUM) {
#define ENM_DEST pSChan->grBuf.genmval
ENM_DEST.status = NO_ALARM;
ENM_DEST.severity = NO_ALARM;
#if 1
ENM_DEST.no_str = 0;
#else
#define ENM_SRC ArCDChanHdr(pChanDesc).graphics.enumGr
ENM_DEST.no_str = ArCFChanNStates(pChanDesc);
for (i=0; i<ENM_DEST.no_str; i++)
(void)strcpy(ENM_DEST.strs[i], ArCFChanStates(pChanDesc)[i]);
#endif
}
else if (pSChan->dbrType == DBR_TIME_CHAR) {
#define CHR_DEST pSChan->grBuf.gchrval
CHR_DEST.status = NO_ALARM;
CHR_DEST.severity = NO_ALARM;
(void)strcpy(CHR_DEST.units, " ");
#if 1
CHR_DEST.upper_disp_limit = 0;
CHR_DEST.lower_disp_limit = 0;
CHR_DEST.upper_alarm_limit = 0;
CHR_DEST.lower_alarm_limit = 0;
CHR_DEST.upper_warning_limit = 0;
CHR_DEST.lower_warning_limit = 0;
#else
#define CHR_SRC ArCDChanHdr(pChanDesc).graphics.charGr
(void)strcpy(CHR_DEST.units, CHR_SRC.units);
CHR_DEST.upper_disp_limit = CHR_SRC.upDispLim;
CHR_DEST.lower_disp_limit = CHR_SRC.lowDispLim;
CHR_DEST.upper_alarm_limit = CHR_SRC.upAlmLim;
CHR_DEST.lower_alarm_limit = CHR_SRC.lowAlmLim;
CHR_DEST.upper_warning_limit = CHR_SRC.upWarnLim;
CHR_DEST.lower_warning_limit = CHR_SRC.lowWarnLim;
#endif
}
return S_syd_OK;
}
/*+/internal******************************************************************
* NAME sydSSFFuncSeekStamp - find a `SAMPLE: at' line
*
* DESCRIPTION
* Find a `SAMPLE: at' line and get the time stamp from it.
*
* If the search is forward, the file is left positioned following
* the stamp. If backward, the position is at the beginning of the
* line.
*
* RETURNS
* position of the line
*
*-*/
static long
sydSSFFuncSeekStamp(ssFile, pStamp, revFlag, pos)
FILE *ssFile;
TS_STAMP *pStamp;
int revFlag; /* I 1 says seek in reverse direction */
long pos; /* I position to start search if reverse; -1
says to start at EOF */
{
long bufStat;
char record[120], recDelim;
char *pRecord, *pField, delim;
long stat;
if (revFlag)
pos = posKeyRev("SAMPLE: at", ssFile, pos);
else
pos = posKeyFwd("SAMPLE: at", ssFile);
if (pos < 0)
return pos;
assert(sizeof(record) == 120);
if (fgets(record, 120, ssFile) == NULL)
return -1;
pRecord = record;
recDelim = record[strlen(record)-1];
if (nextNonSpaceField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
if (strcmp(pField, "SAMPLE:") != 0)
assertAlways(0);
if (nextNonSpaceField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
if (strcmp(pField, "at") != 0)
assertAlways(0);
stat = tsTextToStamp(pStamp, &pRecord);
assert(stat == S_ts_OK);
if (revFlag) {
if (posPos(ssFile, pos) < 0)
assertAlways(0);
}
return pos;
}
/*+/internal******************************************************************
* NAME sydSSFFuncSeekSample - find the next sample
*
* DESCRIPTION
* Finds the next `SAMPLE: at' line, gets the time stamp for the
* sample, and gets the `status' for the snapshot. The file is
* positioned following the %endHeader%, ready for reading the data.
*
* RETURNS
* SYD_B_RESTART if `initial' was specified on the `SAMPLE: at' line, or
* SYD_B_FULL
*
*-*/
static long
sydSSFFuncSeekSample(ssFile, pStamp)
FILE *ssFile;
TS_STAMP *pStamp;
{
long pos;
long bufStat;
char record[120], recDelim;
char *pRecord, *pField, delim;
long stat;
if ((pos = posKeyFwd("SAMPLE: at", ssFile)) < 0)
return SYD_B_EOF;
assert(sizeof(record) == 120);
if (fgets(record, 120, ssFile) == NULL)
return SYD_B_EOF;
pRecord = record;
recDelim = record[strlen(record)-1];
if (nextNonSpaceField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
if (strcmp(pField, "SAMPLE:") != 0)
assertAlways(0);
if (nextNonSpaceField(&pRecord, &pField, &delim) <= 1)
assertAlways(0);
if (strcmp(pField, "at") != 0)
assertAlways(0);
stat = tsTextToStamp(pStamp, &pRecord);
assert(stat == S_ts_OK);
while (*pRecord == '-')
pRecord++;
if (strncmp(pRecord, "initial", 7) == 0)
bufStat = SYD_B_RESTART;
else
bufStat = SYD_B_FULL;
if (recDelim != '\n') {
while ((delim = fgetc(ssFile)) != EOF && delim != '\n')
; /* keep skipping until end of line */
}
if (posKeyFwd("%endHeader%", ssFile) < 0)
return SYD_B_EOF;
else if (fgets(record, 120, ssFile) == NULL)
return SYD_B_EOF;
return bufStat;
}