~info-martin-konrad/epics-gateway/putlog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron-
* Strahlung mbH (BESSY).
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* This file is distributed subject to a Software License Agreement found
* in the file LICENSE that is included with this distribution. 
\*************************************************************************/
// Author: Jim Kowalkowski
// Date: 7/96

// gateStat: Contains data and CAS interface for one bit of gate
// status info.  Update is done via a gate server's method (setStat)
// calling gateStat::post_data.

// serv       points to the parent gate server of this status bit
// post_data  is a flag that switches posting updates on/off

#define DEBUG_UMR 0
#define DEBUG_POST_DATA 0
#define DEBUG_ACCESS 0

#define USE_OSI_TIME 1

#define STAT_DOUBLE

#if !USE_OSI_TIME
#include <time.h>
#endif

#include <gdd.h>
#include <gddApps.h>
#include "gateResources.h"
#include "gateServer.h"
#include "gateAs.h"
#include "gateStat.h"

static struct timespec *timeSpec(void)
	// Gets current time and puts it in a static timespec struct
	// For use by gdd::setTimeStamp, which will copy it
{
#if USE_OSI_TIME
	static struct timespec ts;
        epicsTime osit(epicsTime::getCurrent());
	// EPICS is 20 years ahead of its time
	ts=osit;
#else
	struct timespec ts;
	clock_gettime(CLOCK_REALTIME, &ts);
	ts.tv_sec-=631152000ul;	// EPICS ts start 20 years later ...
#endif
	return &ts;
}

#if statCount

//////// gateStatChan (derived from gate chan derived from casChannel)

gateStatChan::gateStatChan(const casCtx &ctx, casPV *casPvIn, gateAsEntry *asentry,
  const char * const user, const char * const host) :
	gateChan(ctx,casPvIn,asentry,user,host)
{
	gateStat *pStat=(gateStat *)casPv;
	if(pStat) pStat->addChan(this);
}

gateStatChan::~gateStatChan(void)
{
	gateStat *pStat=(gateStat *)casPv;
	if(pStat) pStat->removeChan(this);
}

// This is a new virtual write in CAS that knows the casChannel.  The
// casPV::write() is not called if this one is implemented.  This
// write calls a new, overloaded gateStat::write() that has the
// gateChan as an argument to do what used to be done in the virtual
// gateStat::write().
caStatus gateStatChan::write(const casCtx &ctx, const gdd &value)
{
	gateStat *pStat=(gateStat *)casPv;

	// Trap writes
	if(asclient && asclient->clientPvt()->trapMask) {
		FILE *fp=global_resources->getPutlogFp();
		if(fp) {
			fprintf(fp,"%s %s@%s %s\n",
			  timeStamp(),
			  asclient->user()?asclient->user():"Unknown",
			  asclient->host()?asclient->host():"Unknown",
			  pStat && pStat->getName()?pStat->getName():"Unknown");
			fflush(fp);
		}
	}
	
	// Call the non-virtual-function write() in the gateStat
	if(pStat) return pStat->write(ctx,value,*this);
	else return S_casApp_noSupport;
}

bool gateStatChan::readAccess(void) const
{
#if DEBUG_ACCESS && 0
	gateStat *pStat=(gateStat *)getCasPv();
	printf("gateStatChan::readAccess: %s asclient=%p ret=%d\n",
	  pStat?pStat->getName():"NULL casPV",
	  asclient,(asclient->readAccess())?1:0);
#endif

	return (asclient && asclient->readAccess())?true:false;
}

bool gateStatChan::writeAccess(void) const
{
#if DEBUG_ACCESS && 0
	gateStat *pStat=(gateStat *)getCasPv();
	printf("gateStatChan::writeAccess: %s asclient=%p ret=%d\n",
	  pStat?pStat->getName():"NULL casPV",
	  asclient,(asclient->writeAccess())?1:0);
#endif
	return (asclient && asclient->writeAccess())?true:false;
}

//////// gateStat (derived from casPV)

gateStat::gateStat(gateServer *s, gateAsEntry *e, const char *n, int t) :
	casPV(*s),
	value(NULL),
	attr(NULL),
	post_data(0),
	type(t),
	statType(GATE_STAT_TYPE_PV),
	serv(s),
	name(strDup(n)),
	asentry(e)
{

// Define the value gdd;
#ifdef STAT_DOUBLE
	value=new gdd(global_resources->appValue,aitEnumFloat64);
	if(!value) {
		fprintf(stderr,"gateStat::gateStat: Failed to create GDD for %s\n",
		  n?n:"Unknown name");
		return;
	}
	value->put((aitFloat64)*serv->getStatTable(type)->init_value);
#else
	value=new gdd(global_resources->appValue,aitEnumInt32);
	if(!value) {
		fprintf(stderr,"gateStat::gateStat: Failed to create GDD for %s\n",
		  n?n:"Unknown name");
		return;
	}
	value->put((aitInt32)*serv->getStatTable(type)->init_value);
#endif
	value->setTimeStamp(timeSpec());
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStat::gateStat: name=%s\n",name);
	fflush(stdout);
	value->dump();
	fflush(stderr);
#endif

	// Define the attributes gdd
	attr=new gdd(global_resources->appValue,aitEnumFloat64);
	attr = gddApplicationTypeTable::AppTable().getDD(gddAppType_attributes);
	if(attr) {
		attr[gddAppTypeIndex_attributes_units].
		  put(serv->getStatTable(type)->units);
		attr[gddAppTypeIndex_attributes_maxElements]=1;
		attr[gddAppTypeIndex_attributes_precision]=
		  serv->getStatTable(type)->precision;
		attr[gddAppTypeIndex_attributes_graphicLow]=0.0;
		attr[gddAppTypeIndex_attributes_graphicHigh]=0.0;
		attr[gddAppTypeIndex_attributes_controlLow]=0.0;
		attr[gddAppTypeIndex_attributes_controlHigh]=0.0;
		attr[gddAppTypeIndex_attributes_alarmLow]=0.0;
		attr[gddAppTypeIndex_attributes_alarmHigh]=0.0;
		attr[gddAppTypeIndex_attributes_alarmLowWarning]=0.0;
		attr[gddAppTypeIndex_attributes_alarmHighWarning]=0.0;
		attr->setTimeStamp(timeSpec());
	}
}

gateStat::~gateStat(void)
{
	serv->clearStat(type,statType);
	if(value) value->unreference();
	if(attr) attr->unreference();
	if(name) delete [] name;

	// Clear the chan_list to insure the gateChan's do not call the
	// gateStat to remove them after the gateStat is gone. removeChan
	// also sets the pChan->vc to NULL, the only really necessary
	// thing to do.
	gateStatChan *pChan;
	while((pChan=chan_list.first()))	{
		removeChan(pChan);
		pChan->deleteAsClient();
	}
}

const char *gateStat::getName() const
{
	return name; 
}

casChannel* gateStat::createChannel(const casCtx &ctx,
  const char * const user, const char * const host)
{
	gateStatChan *pChan=new gateStatChan(ctx,this,asentry,user,host);
	return pChan;
}

caStatus gateStat::interestRegister(void)
{
	post_data=1;
	return S_casApp_success;
}

void gateStat::interestDelete(void) { post_data=0; }
unsigned gateStat::maxSimultAsyncOps(void) const { return 5000u; }

aitEnum gateStat::bestExternalType(void) const
{
#ifdef STAT_DOUBLE
	return aitEnumFloat64;
#else
	return aitEnumInt32;
#endif
}

// This is the virtual write function defined in casPV.  It should no
// longer be called if casChannel::write is implemented.
caStatus gateStat::write(const casCtx& ctx, const gdd& dd)
{
	fprintf(stderr,"Virtual gateStat::write called for %s.\n"
	  "  This is an error!\n",getName());
	return S_casApp_noSupport;
}

// This is a non-virtual-function write that allows passing a pointer
// to the gateChannel.  Currently chan is not used.
caStatus gateStat::write(const casCtx& ctx, const gdd& dd, gateChan &/*chan*/)
{
    gddApplicationTypeTable& table=gddApplicationTypeTable::AppTable();
	caStatus retVal=S_casApp_noSupport;
    
    if(value) {
		table.smartCopy(value,&dd);
		double val;
		value->getConvert(val);
		serv->setStat(type,val);
		retVal=serv->processStat(type,val);
    } else {
		retVal=S_casApp_noMemory;
    }
#if DEBUG_UMR
    fflush(stderr);
    print("gateStat::write: name=%s\n",name);
    fflush(stdout);
    dd.dump();
    fflush(stderr);
#endif
    return retVal;
}

caStatus gateStat::read(const casCtx & /*ctx*/, gdd &dd)
{
	static const aitString str = "Gateway Statistics PV";
	gddApplicationTypeTable& table=gddApplicationTypeTable::AppTable();
	caStatus retVal=S_casApp_noSupport;

	// Branch on application type
	unsigned at=dd.applicationType();
	switch(at) {
	case gddAppType_ackt:
	case gddAppType_acks:
	case gddAppType_dbr_stsack_string:
		fprintf(stderr,"%s gateStat::read: "
		  "Got unsupported app type %d for %s\n",
		  timeStamp(),
		  at,name?name:"Unknown Stat PV");
		fflush(stderr);
		retVal=S_casApp_noSupport;
		break;
	case gddAppType_class:
		dd.put(str);
		retVal=S_casApp_success;
		break;
	default:
		// Copy the current state
		if(attr) table.smartCopy(&dd,attr);
		if(value) table.smartCopy(&dd,value);
		retVal=S_casApp_success;
		break;
	}
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStat::read: name=%s\n",name);
	fflush(stdout);
	dd.dump();
	fflush(stderr);
#endif
	return retVal;
}

void gateStat::removeEntry(void)
{
#if DEBUG_ACCESS
	printf("gateStat::removeEntry %s asentry=%p\n",
	  getName(),asentry);
#endif
	// Replace the pointer in the gateVcData
	asentry=NULL;

	// Loop over gateChan's
	tsDLIter<gateStatChan> iter=chan_list.firstIter();
	while(iter.valid()) {
		iter->deleteAsClient();
		iter++;
	}
}

void gateStat::resetEntry(gateAsEntry *asentryIn)
{
#if DEBUG_ACCESS
	printf("gateStat::resetEntry %s asentry=%p asentryIn=%p\n",
	  getName(),asentry,asentryIn);
#endif
	// Replace the pointer in the gateVcData
	asentry=asentryIn;

	// Loop over gateChan's
	tsDLIter<gateStatChan> iter=chan_list.firstIter();
	while(iter.valid()) {
		iter->resetAsClient(asentry);
		iter++;
	}
}

void gateStat::report(FILE *fp)
{
	fprintf(fp,"%-30s\n",getName());

	tsDLIter<gateStatChan> iter=chan_list.firstIter();
	while(iter.valid()) {
		iter->report(fp);
		iter++;
	}
}

void gateStat::postData(long val)
{
#ifdef STAT_DOUBLE
	value->put((aitFloat64)val);
#else
	value->put((aitInt32)val);
#endif
	value->setTimeStamp(timeSpec());
	if(post_data) postEvent(serv->select_mask,*value);
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStat::postData(l): name=%s\n",name);
	fflush(stdout);
	value->dump();
	fflush(stderr);
#endif
}

// KE: Could have these next two just call postData((aitFloat64)val)

void gateStat::postData(unsigned long val)
{
#if DEBUG_POST_DATA
	fflush(stdout);
	printf("gateStat::postData(ul): name=%s val=%ld\n",
	  name,val);
	fflush(stdout);
#endif
#ifdef STAT_DOUBLE
	value->put((aitFloat64)val);
#else
	value->put((aitInt32)val);
#endif
	value->setTimeStamp(timeSpec());
	if(post_data) postEvent(serv->select_mask,*value);
#if DEBUG_UMR || DEBUG_POST_DATA
	fflush(stderr);
	printf("gateStat::postData(ul): name=%s\n",name);
	fflush(stdout);
	value->dump();
	fflush(stderr);
#endif
}

void gateStat::postData(double val)
{
#ifdef STAT_DOUBLE
	value->put(val);
#else
	value->put(val);
#endif
	value->setTimeStamp(timeSpec());
	if(post_data) postEvent(serv->select_mask,*value);
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStat::postData(dbl): name=%s\n",name);
	fflush(stdout);
	value->dump();
	fflush(stderr);
#endif
}

//////// gateStatDesc (derived from gateStat)

gateStatDesc::gateStatDesc(gateServer *s, gateAsEntry *e, const char *n, int t) :
	gateStat(s,e,n,t)
{

	statType=GATE_STAT_TYPE_DESC;

// Define the value gdd;
	value=new gdd(global_resources->appValue,aitEnumString);
	if(value)
	  value->put(serv->getStatTable(type)->desc);
	value->setTimeStamp(timeSpec());
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStatDesc::gateStatDesc: name=%s\n",name);
	fflush(stdout);
	value->dump();
	fflush(stderr);
#endif

	// Define the attributes gdd
	attr=new gdd(global_resources->appValue,aitEnumFloat64);
	attr = gddApplicationTypeTable::AppTable().getDD(gddAppType_attributes);
	if(attr) {
		attr[gddAppTypeIndex_attributes_units].put("");
		attr[gddAppTypeIndex_attributes_maxElements]=1;
		attr[gddAppTypeIndex_attributes_precision]=0;
		attr[gddAppTypeIndex_attributes_graphicLow]=0.0;
		attr[gddAppTypeIndex_attributes_graphicHigh]=0.0;
		attr[gddAppTypeIndex_attributes_controlLow]=0.0;
		attr[gddAppTypeIndex_attributes_controlHigh]=0.0;
		attr[gddAppTypeIndex_attributes_alarmLow]=0.0;
		attr[gddAppTypeIndex_attributes_alarmHigh]=0.0;
		attr[gddAppTypeIndex_attributes_alarmLowWarning]=0.0;
		attr[gddAppTypeIndex_attributes_alarmHighWarning]=0.0;
		attr->setTimeStamp(timeSpec());
	}
}

gateStatDesc::~gateStatDesc(void)
{
#ifdef TEMP
	serv->clearStat(type);
	if(value) value->unreference();
	if(attr) attr->unreference();
	if(name) delete [] name;

	// Clear the chan_list to insure the gateChan's do not call the
	// gateStatDesc to remove them after the gateStatDesc is gone. removeChan
	// also sets the pChan->vc to NULL, the only really necessary
	// thing to do.
	gateStatChan *pChan;
	while((pChan=chan_list.first()))	{
		removeChan(pChan);
		pChan->deleteAsClient();
	}
#endif
}

caStatus gateStatDesc::read(const casCtx & /*ctx*/, gdd &dd)
{
	static const aitString str = "Gateway Statistics PV";
	gddApplicationTypeTable& table=gddApplicationTypeTable::AppTable();
	caStatus retVal=S_casApp_noSupport;

	// Branch on application type
	unsigned at=dd.applicationType();
	switch(at) {
	case gddAppType_ackt:
	case gddAppType_acks:
	case gddAppType_dbr_stsack_string:
		fprintf(stderr,"%s gateStatDesc::read: "
		  "Got unsupported app type %d for %s\n",
		  timeStamp(),
		  at,name?name:"Unknown Stat PV");
		fflush(stderr);
		retVal=S_casApp_noSupport;
		break;
	case gddAppType_class:
		dd.put(str);
		retVal=S_casApp_success;
		break;
	default:
		// Copy the current state
		if(attr) table.smartCopy(&dd,attr);
		if(value) table.smartCopy(&dd,value);
		retVal=S_casApp_success;
		break;
	}
#if DEBUG_UMR
	fflush(stderr);
	printf("gateStatDesc::read: name=%s\n",name);
	fflush(stdout);
	dd.dump();
	fflush(stderr);
#endif
	return retVal;
}

#endif    // statCount

/* **************************** Emacs Editing Sequences ***************** */
/* Local Variables: */
/* tab-width: 4 */
/* c-basic-offset: 4 */
/* c-comment-only-line-offset: 0 */
/* c-file-offsets: ((substatement-open . 0) (label . 0)) */
/* End: */