Initial revision
This commit is contained in:
506
varlog.c
Normal file
506
varlog.c
Normal file
@@ -0,0 +1,506 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
|
||||
V A R L O G
|
||||
|
||||
A module for keeping a log of a variable.
|
||||
|
||||
Mark Koennecke, September 1997
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
Paul Scherrer Institut
|
||||
CH-5423 Villigen-PSI
|
||||
|
||||
|
||||
The authors hereby grant permission to use, copy, modify, distribute,
|
||||
and license this software and its documentation for any purpose, provided
|
||||
that existing copyright notices are retained in all copies and that this
|
||||
notice is included verbatim in any distributions. No written agreement,
|
||||
license, or royalty fee is required for any of the authorized uses.
|
||||
Modifications to this software may be copyrighted by their authors
|
||||
and need not follow the licensing terms described here, provided that
|
||||
the new terms are clearly indicated on the first page of each file where
|
||||
they apply.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
||||
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
----------------------------------------------------------------------------*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include "fortify.h"
|
||||
#include "lld.h"
|
||||
#include "conman.h"
|
||||
#include "varlog.h"
|
||||
#include "commandlog.h"
|
||||
|
||||
/* maximum number of log entries, limit memory usage */
|
||||
#define MAXLOG 2000
|
||||
/*------------------------------------------------------------------------*/
|
||||
typedef struct __VarLog
|
||||
{
|
||||
int iList;
|
||||
time_t tFrequency;
|
||||
time_t tNext;
|
||||
int iCount;
|
||||
FILE *fd;
|
||||
}VarLog;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
time_t tTime;
|
||||
float fVal;
|
||||
}LogItem, *pLogItem;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int VarlogInit(pVarLog *self)
|
||||
{
|
||||
int i;
|
||||
pVarLog pNew = NULL;
|
||||
|
||||
pNew = (pVarLog)malloc(sizeof(VarLog));
|
||||
if(!pNew)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
pNew->tFrequency = 300; /* 5 minutes */
|
||||
pNew->tNext = 0;
|
||||
pNew->iCount = 0;
|
||||
pNew->fd = NULL;
|
||||
|
||||
i = LLDcreate(sizeof(LogItem));
|
||||
if(i < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNew->iList = i;
|
||||
*self = pNew;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int VarlogDelete(pVarLog self)
|
||||
{
|
||||
if(self->fd != NULL)
|
||||
{
|
||||
fclose(self->fd);
|
||||
}
|
||||
LLDdelete(self->iList);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int VarlogClear(pVarLog self)
|
||||
{
|
||||
int iRet, iList;
|
||||
|
||||
iList = self->iList;
|
||||
assert(iList >= 0);
|
||||
|
||||
iRet = LLDnodePtr2First(iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDelete(iList);
|
||||
iRet = LLDnodePtr2Prev(iList);
|
||||
iRet = LLDnodePtr2Next(iList);
|
||||
}
|
||||
self->tNext = 0;
|
||||
self->iCount = 0;
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void VLFormatTime(time_t tTime, char *pBuffer, int iBufLen)
|
||||
{
|
||||
struct tm *psTime;
|
||||
|
||||
/* make time string */
|
||||
psTime = localtime(&tTime);
|
||||
memset(pBuffer,0,iBufLen);
|
||||
strftime(pBuffer,iBufLen,"%Y-%d-%m %H:%M:%S",psTime);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int VarlogAdd(pVarLog self, float fVal)
|
||||
{
|
||||
LogItem sItem;
|
||||
time_t tCurrent;
|
||||
int iFile = 0;
|
||||
char pBuffer[80];
|
||||
|
||||
assert(self);
|
||||
|
||||
tCurrent = time(NULL);
|
||||
|
||||
/* check if we are logging to file */
|
||||
if(self->fd != NULL)
|
||||
{
|
||||
iFile = 1;
|
||||
}
|
||||
|
||||
/* limit size of log */
|
||||
if(self->iCount > MAXLOG)
|
||||
{
|
||||
|
||||
VarlogClear(self);
|
||||
WriteToCommandLog("SYS>","WARNING: variable log cleared in order to prevent memory overflow");
|
||||
}
|
||||
|
||||
/* log always if tFrequncy is 0 */
|
||||
if(self->tFrequency == 0)
|
||||
{
|
||||
sItem.tTime = tCurrent;
|
||||
sItem.fVal = fVal;
|
||||
LLDnodeAppendFrom(self->iList, &sItem);
|
||||
self->iCount++;
|
||||
}
|
||||
|
||||
|
||||
/* if not initialised, do it */
|
||||
if(self->tNext < 1)
|
||||
{
|
||||
sItem.tTime = tCurrent;
|
||||
sItem.fVal = fVal;
|
||||
if(iFile)
|
||||
{
|
||||
VLFormatTime(tCurrent,pBuffer,79);
|
||||
fprintf(self->fd," %s %f \n", pBuffer,fVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLDnodeAppendFrom(self->iList, &sItem);
|
||||
self->iCount++;
|
||||
}
|
||||
self->tNext = tCurrent + self->tFrequency;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if, log time passed, do it */
|
||||
if(tCurrent > self->tNext)
|
||||
{
|
||||
sItem.tTime = tCurrent;
|
||||
sItem.fVal = fVal;
|
||||
if(iFile)
|
||||
{
|
||||
VLFormatTime(tCurrent,pBuffer,79);
|
||||
fprintf(self->fd," %s %f \n", pBuffer,fVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLDnodeAppendFrom(self->iList, &sItem);
|
||||
self->iCount++;
|
||||
}
|
||||
self->tNext = tCurrent + self->tFrequency;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int VarlogLength(pVarLog self, int *iLength)
|
||||
{
|
||||
int iLang, iRet, iList;
|
||||
|
||||
iList = self->iList;
|
||||
assert(iList >= 0);
|
||||
|
||||
iLang = 0;
|
||||
iRet = LLDnodePtr2First(iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
iLang++;
|
||||
iRet = LLDnodePtr2Next(iList);
|
||||
}
|
||||
*iLength = iLang;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int VarlogGetTime(pVarLog self, time_t *tTime)
|
||||
{
|
||||
int iRet, i, iList;
|
||||
LogItem sItem;
|
||||
|
||||
iList = self->iList;
|
||||
assert(iList >= 0);
|
||||
|
||||
i = 0;
|
||||
iRet = LLDnodePtr2First(iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(iList,&sItem);
|
||||
tTime[i] = sItem.tTime;
|
||||
i++;
|
||||
iRet = LLDnodePtr2Next(iList);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int VarlogGetVal(pVarLog self, float *fValue)
|
||||
{
|
||||
int iRet, i, iList;
|
||||
LogItem sItem;
|
||||
|
||||
iList = self->iList;
|
||||
assert(iList >= 0);
|
||||
|
||||
i = 0;
|
||||
iRet = LLDnodePtr2First(iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(iList,&sItem);
|
||||
fValue[i] = sItem.fVal;
|
||||
i++;
|
||||
iRet = LLDnodePtr2Next(iList);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int VarlogGetMean(pVarLog self, float *fMean, float *fStdDev)
|
||||
{
|
||||
int i, iLength = 0, iList;
|
||||
float fM, fStd, fSum,fD, *fVal = NULL;
|
||||
|
||||
iList = self->iList;
|
||||
assert(iList >= 0);
|
||||
|
||||
VarlogLength(self,&iLength);
|
||||
if(iLength < 1) /* nothing to do */
|
||||
{
|
||||
*fMean = 0.;
|
||||
*fStdDev = 0.;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get some memory for values */
|
||||
fVal = (float *)malloc(iLength*sizeof(float));
|
||||
if(!fVal)
|
||||
{
|
||||
*fMean = 0.;
|
||||
*fStdDev = 0.;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get values */
|
||||
VarlogGetVal(self, fVal);
|
||||
|
||||
/* calculate mean first */
|
||||
fSum = 0.;
|
||||
for(i = 0; i < iLength; i++)
|
||||
{
|
||||
fSum += fVal[i];
|
||||
}
|
||||
fM = fSum/(float)iLength;
|
||||
|
||||
/* do standard deviation */
|
||||
fSum = 0.;
|
||||
for(i = 0; i < iLength; i++)
|
||||
{
|
||||
fD = fM - fVal[i];
|
||||
fSum += fD*fD;
|
||||
}
|
||||
fStd = sqrt(fSum/(float)iLength);
|
||||
|
||||
*fMean = fM;
|
||||
*fStdDev = fStd;
|
||||
free(fVal);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int VarlogWrapper(pVarLog self, int *iSwitch, SConnection *pCon,
|
||||
char *subcommand, char *sub2, char *pVarName)
|
||||
{
|
||||
float fMean, fStdDev, *fData = NULL;
|
||||
time_t *pTArray = NULL;
|
||||
int iLength, iRet, i, iList;
|
||||
char pBueffel[256];
|
||||
char *pData = NULL;
|
||||
long lNew;
|
||||
|
||||
|
||||
iList = self->iList;
|
||||
strtolower(subcommand);
|
||||
/*------------ on */
|
||||
if(strcmp(subcommand,"on") == 0)
|
||||
{
|
||||
*iSwitch = 1;
|
||||
return 1;
|
||||
}
|
||||
/*----------- off */
|
||||
else if(strcmp(subcommand,"off") == 0)
|
||||
{
|
||||
*iSwitch = 0;
|
||||
return 1;
|
||||
}
|
||||
/*--------- file */
|
||||
else if(strcmp(subcommand,"file") == 0)
|
||||
{
|
||||
if(self->fd != NULL)
|
||||
{
|
||||
fclose(self->fd);
|
||||
self->fd = NULL;
|
||||
}
|
||||
self->fd = fopen(sub2,"w");
|
||||
if(!self->fd)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: failed to open temperature log file: %s",
|
||||
sub2);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
if(self->tFrequency < 20)
|
||||
{
|
||||
self->tFrequency = 300;
|
||||
}
|
||||
*iSwitch = 1;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*----- close */
|
||||
else if(strcmp(subcommand,"close") == 0)
|
||||
{
|
||||
if(self->fd != NULL)
|
||||
{
|
||||
fclose(self->fd);
|
||||
self->fd = NULL;
|
||||
}
|
||||
*iSwitch = 0;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/* ------------ gettime */
|
||||
else if(strcmp(subcommand,"gettime") == 0)
|
||||
{
|
||||
iRet = VarlogLength(self, &iLength);
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Invalid logging list",eError);
|
||||
return 0;
|
||||
}
|
||||
pTArray = (time_t *)malloc(iLength * sizeof(time_t));
|
||||
if(!pTArray)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in varlog",eError);
|
||||
return 0;
|
||||
}
|
||||
VarlogGetTime(self,pTArray);
|
||||
/* format into a string */
|
||||
pData = (char *)malloc((iLength*35+100)*sizeof(char));
|
||||
if(!pData)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in varlog",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pData,0,(iLength*35+100)*sizeof(char));
|
||||
sprintf(pData,"%s.TimeStaamps = {",pVarName);
|
||||
for(i = 0; i < iLength; i++)
|
||||
{
|
||||
strcat(pData,",");
|
||||
VLFormatTime(pTArray[i],pBueffel,80);
|
||||
strcat(pData,pBueffel);
|
||||
}
|
||||
strcat(pData,"}");
|
||||
SCWrite(pCon,pData,eValue);
|
||||
free(pTArray);
|
||||
free(pData);
|
||||
return 1;
|
||||
}
|
||||
/*------------ getval */
|
||||
else if(strcmp(subcommand,"getval") == 0)
|
||||
{
|
||||
iRet = VarlogLength(self, &iLength);
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Invalid logging list",eError);
|
||||
return 0;
|
||||
}
|
||||
fData = (float *)malloc(iLength * sizeof(float));
|
||||
if(!fData)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in varlog",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(fData,0,iLength *sizeof(float));
|
||||
VarlogGetVal(self,fData);
|
||||
/* format a reply */
|
||||
pData = (char *)malloc((iLength*11+50)*sizeof(char));
|
||||
if(!pData)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in varlog",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pData,0,(iLength*11+50)*sizeof(char));
|
||||
sprintf(pData,"%s.Values = {",pVarName);
|
||||
for(i = 0; i < iLength; i++)
|
||||
{
|
||||
strcat(pData,",");
|
||||
sprintf(pBueffel,"%8.2f",fData[i]);
|
||||
strcat(pData,pBueffel);
|
||||
}
|
||||
SCWrite(pCon,pData,eValue);
|
||||
free(fData);
|
||||
free(pData);
|
||||
return 1;
|
||||
}
|
||||
/*--------- getmean */
|
||||
else if(strcmp(subcommand,"getmean") == 0)
|
||||
{
|
||||
iRet = VarlogGetMean(self,&fMean,&fStdDev);
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Invalid logging list",eError);
|
||||
return 0;
|
||||
}
|
||||
sprintf(pBueffel,"%s.Mean = %8.2f %s.StdDev = %8.2f",
|
||||
pVarName,fMean,pVarName,fStdDev);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
/*------------ clear */
|
||||
else if(strcmp(subcommand,"clear") == 0)
|
||||
{
|
||||
*iSwitch = 0;
|
||||
return VarlogClear(self);
|
||||
}
|
||||
/*------------- frequency */
|
||||
else if(strcmp(subcommand,"frequency") == 0)
|
||||
{
|
||||
if(sub2)
|
||||
{
|
||||
iRet = sscanf(sub2,"%d",&lNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
iRet = 0;
|
||||
}
|
||||
if(iRet == 1) /* new value */
|
||||
{
|
||||
self->tFrequency = lNew;
|
||||
return 1;
|
||||
}
|
||||
else /* print */
|
||||
{
|
||||
sprintf(pBueffel,"%s.frequency = %d",pVarName,self->tFrequency);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* command not recognized */
|
||||
else
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: %s no valid command to varlog",subcommand);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user