mrfioc2  2.3.0
drvemTSBuffer.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2020 Michael Davidsaver
3 * mrfioc2 is distributed subject to a Software License Agreement found
4 * in file LICENSE that is included with this distribution.
5 \*************************************************************************/
6 
7 #include "drvem.h"
8 #include "drvemTSBuffer.h"
9 #include "devObj.h"
10 
11 EVRMRMTSBuffer::EVRMRMTSBuffer(const std::string &n, EVRMRM *evr)
12  :base_t(n)
13  ,evr(evr)
14  ,dropped(0u)
15  ,timeEvt(0u)
16  ,flushEvt(0u)
17  ,active(0u)
18 {
19  scanIoInit(&scan);
20 }
21 
23 {
24 
25 }
26 
28 {
29  evr->lock();
30 }
31 
33 {
34  evr->unlock();
35 }
36 
37 void EVRMRMTSBuffer::flushTimeSet(epicsUInt16 v)
38 {
39  if(v==timeEvt)
40  return;
41  if(v==flushEvent() || v>0xff)
42  throw std::invalid_argument("Can't capture with flush code or >255");
43 
44  if(timeEvt) {
45  evr->events[timeEvt].tbufs.erase(this);
46  evr->interestedInEvent(timeEvt, false);
47  }
48  if(v) {
49  evr->interestedInEvent(v, true);
50  evr->events[v].tbufs.insert(this);
51  }
52  timeEvt = v;
53 }
54 
55 void EVRMRMTSBuffer::flushEventSet(epicsUInt16 v)
56 {
57  if(v==flushEvt)
58  return;
59  if(v==timeEvt || v>0xff)
60  throw std::invalid_argument("Can't flush with capture code or >255");
61 
62  if(flushEvt) {
63  evr->events[flushEvt].tbufs.erase(this);
65  }
66  if(v) {
67  evr->interestedInEvent(v, true);
68  evr->events[v].tbufs.insert(this);
69  }
70  flushEvt = v;
71 }
72 
73 // caller must hold evrLock
75 {
76  if(epicsTimeGetCurrent(&ebufs[active].flushtime)) {
77  ebufs[active].flushtime.secPastEpoch = 0u;
78  ebufs[active].flushtime.nsec = 0u;
79  ebufs[active].ok = false;
80  ebufs[active].drop = false;
81  }
82 
83  doFlush();
84 }
85 
87 {
88  bool prevok = ebufs[active].ok;
89  epicsTimeStamp prevflushtime = ebufs[active].flushtime;
90 
91  active ^= 1u;
92 
93  ebufs[active].pos = 0u;
94  // a valid buffer requires timestamp validity at start and end flush
96  ebufs[active].drop = false;
97 
98  ebufs[active].prevok = prevok;
99  ebufs[active].prevflushtime = prevflushtime;
100 
101  scanIoRequest(scan);
102 }
103 
104 enum TimesRef {
108 };
109 
110 static
111 epicsUInt32 getTimes(const EVRMRMTSBuffer* self, epicsInt32 *arr, epicsUInt32 count, TimesRef ref)
112 {
113  const EVRMRMTSBuffer::ebuf_t& readout = self->ebufs[self->active^1u];
114  dbCommon* prec = CurrentRecord::get();
115 
116  if(prec && !readout.ok) {
117  recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
118  } else if(prec && ref==TimesRefPrevFlush && !readout.prevok) {
119  recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
120  } else if(prec && readout.drop) {
121  recGblSetSevr(prec, READ_ALARM, MAJOR_ALARM);
122  }
123 
124  double period=1e9/self->evr->clockTS(); // in nanoseconds
125 
126  size_t len = std::min(readout.pos, size_t(count));
127 
128  if(readout.buf.size() < count) {
129  const_cast<EVRMRMTSBuffer::ebuf_t&>(readout).buf.resize(count);
130  }
131 
132  if(period<=0 || !isfinite(period)) {
133  if(count>0u) {
134  arr[0] = 0;
135  count = 1u;
136  }
137  recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
138  return count;
139  }
140 
141  epicsTimeStamp tref;
142  if(ref==TimesRefFlush) {
143  tref = readout.flushtime;
144  } else if(ref==TimesRefPrevFlush) {
145  tref = readout.prevflushtime;
146  }
147 
148  for(size_t i=0; i<len; i++) {
149  epicsTimeStamp ts = readout.buf[i];
150 
151  // readout.ok captures validity of timestamp at start and end of interval.
152  // skip validation of timestamps in between.
153  ts.secPastEpoch -= POSIX_TIME_AT_EPICS_EPOCH;
154  ts.nsec = epicsUInt32(ts.nsec*period);
155 
156  if(i==0 && ref==TimesRefEvt0) {
157  tref = ts;
158  }
159 
160  double diff = epicsTimeDiffInSeconds(&ts, &tref);
161  arr[i] = epicsInt32(diff*1e9); // ns
162  }
163 
164  if(prec) {
165  prec->time = tref;
166  }
167 
168  return len;
169 }
170 
171 epicsUInt32 EVRMRMTSBuffer::getTimesRelFirst(epicsInt32 *arr, epicsUInt32 count) const
172 {
173  return getTimes(this, arr, count, TimesRefEvt0);
174 }
175 
176 epicsUInt32 EVRMRMTSBuffer::getTimesRelFlush(epicsInt32 *arr, epicsUInt32 count) const
177 {
178  return getTimes(this, arr, count, TimesRefFlush);
179 }
180 
181 epicsUInt32 EVRMRMTSBuffer::getTimesRelPrevFlush(epicsInt32 *arr, epicsUInt32 count) const
182 {
183  return getTimes(this, arr, count, TimesRefPrevFlush);
184 }
185 
186 static
188 buildInstance(const std::string& name, const std::string& klass, const mrf::Object::create_args_t& args)
189 {
190  (void)klass;
191  mrf::Object::create_args_t::const_iterator it;
192 
193  if((it=args.find("PARENT"))==args.end())
194  throw std::runtime_error("No PARENT= (EVR) specified");
195 
196  mrf::Object *evrobj = mrf::Object::getObject(it->second);
197  if(!evrobj)
198  throw std::runtime_error("No such PARENT object");
199 
200  EVRMRM *evr = dynamic_cast<EVRMRM*>(evrobj);
201  if(!evr)
202  throw std::runtime_error("PARENT is not a MRMEVR");
203 
204  mrf::auto_ptr<EVRMRMTSBuffer> ret(new EVRMRMTSBuffer(name, evr));
205 
206  return ret.release();
207 }
208 
211  OBJECT_PROP1("DropCnt", &EVRMRMTSBuffer::dropCount);
214  OBJECT_PROP1("FlushManual", &EVRMRMTSBuffer::flushNow);
215  OBJECT_PROP1("TimesRelFirst", &EVRMRMTSBuffer::getTimesRelFirst);
216  OBJECT_PROP1("TimesRelFirst", &EVRMRMTSBuffer::flushed);
217  OBJECT_PROP1("TimesRelFlush", &EVRMRMTSBuffer::getTimesRelFlush);
218  OBJECT_PROP1("TimesRelFlush", &EVRMRMTSBuffer::flushed);
219  OBJECT_PROP1("TimesRelPrevFlush", &EVRMRMTSBuffer::getTimesRelPrevFlush);
220  OBJECT_PROP1("TimesRelPrevFlush", &EVRMRMTSBuffer::flushed);
std::map< std::string, std::string > create_args_t
Definition: object.h:422
epicsUInt8 flushEvt
Definition: drvemTSBuffer.h:52
epicsUInt32 getTimesRelFirst(epicsInt32 *arr, epicsUInt32 count) const
epicsTimeStamp flushtime
Definition: drvemTSBuffer.h:57
virtual bool interestedInEvent(epicsUInt32 event, bool set) OVERRIDE FINAL
Definition: drvem.cpp:745
OBJECT_FACTORY & buildInstance
#define isfinite
Definition: mrfCommon.h:326
OBJECT_PROP1("DropCnt", &EVRMRMTSBuffer::dropCount)
Definition: evrdump.c:37
std::vector< epicsTimeStamp > buf
Definition: drvemTSBuffer.h:56
Modular Register Map Event Receivers.
Definition: drvem.h:86
virtual ~EVRMRMTSBuffer()
epicsUInt32 getTimesRelFlush(epicsInt32 *arr, epicsUInt32 count) const
void flushTimeSet(epicsUInt16 v)
static dbCommon * get()
Definition: devObj.cpp:49
Base object inspection.
Definition: object.h:378
EVRMRMTSBuffer(const std::string &n, EVRMRM *evr)
EVRMRM *const evr
Definition: drvemTSBuffer.h:45
static Object * getObject(const std::string &name)
Definition: object.cpp:107
#define OBJECT_BEGIN(klass)
Definition: object.h:513
epicsUInt32 getTimesRelPrevFlush(epicsInt32 *arr, epicsUInt32 count) const
virtual void lock() const OVERRIDE FINAL
Definition: drvem.h:121
TimesRef
void flushEventSet(epicsUInt16 v)
#define OBJECT_END(klass)
Definition: object.h:523
epicsUInt8 timeEvt
Definition: drvemTSBuffer.h:51
epicsUInt16 flushEvent() const
Definition: drvemTSBuffer.h:33
epicsTimeStamp prevflushtime
Definition: drvemTSBuffer.h:57
unsigned char active
Definition: drvemTSBuffer.h:70
const std::string & name() const
Definition: object.h:393
IOSCANPVT flushed() const
Definition: drvemTSBuffer.h:43
tbufs_t tbufs
Definition: drvem.h:63
virtual bool TimeStampValid() const OVERRIDE FINAL
Definition: drvem.cpp:768
#define OBJECT_FACTORY(FN)
Definition: object.h:521
virtual void lock() const OVERRIDE FINAL
epicsUInt32 dropCount() const
Definition: drvemTSBuffer.h:28
OBJECT_PROP2("TimeEvent", &EVRMRMTSBuffer::timeEvent, &EVRMRMTSBuffer::flushTimeSet)
IOSCANPVT scan
Definition: drvemTSBuffer.h:49
epicsUInt16 timeEvent() const
Definition: drvemTSBuffer.h:30
struct EVRMRMTSBuffer::ebuf_t ebufs[2]
virtual void unlock() const OVERRIDE FINAL
virtual void unlock() const OVERRIDE FINAL
Definition: drvem.h:122