mrfioc2  2.3.0
drvem.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * Copyright (c) 2015 Paul Scherrer Institute (PSI), Villigen, Switzerland
5 * mrfioc2 is distributed subject to a Software License Agreement found
6 * in file LICENSE that is included with this distribution.
7 \*************************************************************************/
8 /*
9  * Author: Michael Davidsaver <mdavidsaver@gmail.com>
10  */
11 
12 #include <cstdio>
13 #include <cstring>
14 #include <cmath>
15 #include <stdexcept>
16 #include <algorithm>
17 #include <sstream>
18 
19 #include <epicsMath.h>
20 #include <errlog.h>
21 #include <epicsMath.h>
22 #include <dbDefs.h>
23 #include <dbScan.h>
24 #include <epicsInterrupt.h>
25 
26 #include "mrmDataBufTx.h"
27 #include "sfp.h"
28 
29 #include "evrRegMap.h"
30 
31 #include "mrfFracSynth.h"
32 
33 #include <mrfCommon.h>
34 #include <mrfCommonIO.h>
35 #include <mrfBitOps.h>
36 
37 #include "drvemIocsh.h"
38 
39 #include <evr/evr.h>
40 #include <evr/pulser.h>
41 #include <evr/cml.h>
42 #include <evr/prescaler.h>
43 #include <evr/input.h>
44 #include <evr/delay.h>
45 
46 #if defined(__linux__) || defined(_WIN32)
47 # include "devLibPCI.h"
48 #endif
49 
50 #include "drvem.h"
51 
52 #include <epicsExport.h>
53 
54 /* whether to use features introduced to support
55  * parallel handling of shared callback queues.
56  */
57 #if EPICS_VERSION_INT>=VERSION_INT(3,15,0,2)
58 # define HAVE_PARALLEL_CB
59 #endif
60 
67 extern "C" {
71 }
72 
73 using namespace std;
74 
75 #define CBINIT(ptr, prio, fn, valptr) \
76 do { \
77  callbackSetPriority(prio, ptr); \
78  callbackSetCallback(fn, ptr); \
79  callbackSetUser(valptr, ptr); \
80  (ptr)->timer=NULL; \
81 } while(0)
82 
83 /*Note: All locking involving the ISR done by disabling interrupts
84  * since the OSI library doesn't provide more efficient
85  * constructs like a ISR safe spinlock.
86  */
87 
88 extern "C" {
89  /* Arbitrary throttleing of FIFO thread.
90  * The FIFO thread has to run at a high priority
91  * so the callbacks have low latency. At the same
92  * time we want to prevent starvation of lower
93  * priority tasks if too many events are received.
94  * This would cause the CA server to be starved
95  * preventing remote correction of the problem.
96  *
97  * This should be less than the time between
98  * the highest frequency event needed for
99  * database processing.
100  *
101  * Note that the actual rate will be limited by the
102  * time needed for database processing.
103  *
104  * Set to 0.0 to disable
105  *
106  * No point in making this shorter than the system tick
107  */
108  double mrmEvrFIFOPeriod = 1.0/ 1000.0; /* 1/rate in Hz */
109 
110  epicsExportAddress(double,mrmEvrFIFOPeriod);
111 }
112 
113 /* Number of good updates before the time is considered valid */
114 #define TSValidThreshold 5
115 
116 // Fractional synthesizer reference clock frequency
117 static
118 const double fracref=24.0; // MHz
119 
120 EVRMRM::EVRMRM(const std::string& n,
121  bus_configuration& busConfig, const Config *c,
122  volatile unsigned char* b,
123  epicsUInt32 bl)
124  :base_t(n,busConfig)
125  ,MRMSPI(b+U32_SPIDData)
126  ,TimeStampSource(1.0)
127  ,evrLock()
128  ,conf(c)
129  ,base(b)
130  ,baselen(bl)
131  ,buftx(n+":BUFTX", b+U32_DataTxCtrl, b+U32_DataTx_base)
132  ,bufrx(n+":BUFRX", b, 10) // Sets depth of Rx queue
133  ,count_recv_error(0)
134  ,count_hardware_irq(0)
135  ,count_heartbeat(0)
136  ,shadowIRQEna(0)
137  ,count_FIFO_overflow(0)
138  ,outputs()
139  ,prescalers()
140  ,pulsers()
141  ,shortcmls()
142  ,gpio_(*this)
143  ,drain_fifo_method(*this)
144  ,drain_fifo_task(drain_fifo_method, "EVRFIFO",
145  epicsThreadGetStackSize(epicsThreadStackBig),
146  epicsThreadPriorityHigh )
147  // 3 because 2 IRQ events, and 1 shutdown event
148  ,drain_fifo_wakeup(3,sizeof(int))
149  ,count_FIFO_sw_overrate(0)
150  ,timeSrcMode(Disable)
151  ,stampClock(0.0)
152  ,shadowSourceTS(TSSourceInternal)
153  ,shadowCounterPS(0)
154  ,timestampValid(0)
155  ,lastInvalidTimestamp(0)
156  ,lastValidTimestamp(0)
157 {
158 try{
159  const epicsUInt32 rawver = fpgaFirmware();
160  const epicsUInt32 boardtype = (rawver&FWVersion_type_mask)>>FWVersion_type_shift;
161  const epicsUInt32 formfactor = (rawver&FWVersion_form_mask)>>FWVersion_form_shift;
162  const MRFVersion ver(rawver);
163 
164  if(boardtype!=0x1)
165  throw std::runtime_error("Address does not correspond to an EVR");
166 
167  if(ver<MRFVersion(0,3))
168  throw std::runtime_error("Firmware 0 version < 3 not supported");
169  else if(ver.firmware()==2 && ver<MRFVersion(2,7))
170  throw std::runtime_error("Firmware 2 version < 207 not supported");
171 
172  if(ver.firmware()==2 && ver<MRFVersion(2,7,6))
173  printf("Warning: Recommended minimum firmware 2 version is 207.6, found %s\n", ver.str().c_str());
174 
175  if(ver.firmware()!=0 && ver.firmware()!=2)
176  printf("Warning: Unknown firmware series %u. Your milage may vary\n", ver.firmware());
177 
178  scanIoInit(&IRQmappedEvent);
179  scanIoInit(&IRQheartbeat);
180  scanIoInit(&IRQrxError);
181  scanIoInit(&IRQfifofull);
182  scanIoInit(&timestampValidChange);
183 
184  CBINIT(&data_rx_cb , priorityHigh, &mrmBufRx::drainbuf, &this->bufrx);
185  CBINIT(&poll_link_cb , priorityMedium, &EVRMRM::poll_link , this);
186 
187  if(ver>=MRFVersion(0, 5)) {
188  std::ostringstream name;
189  name<<n<<":SFP";
190  sfp.reset(new SFP(name.str(), base + U32_SFPEEPROM_base));
191  }
192 
193  if(ver>=MRFVersion(2,7)) {
194  printf("Sequencer capability detected\n");
195  seq.reset(new EvrSeqManager(this));
196  }
197 
198  /*
199  * Create subunit instances
200  */
201 
202  formFactor form = getFormFactor();
203 
204  printf("%s: ", formFactorStr().c_str());
205  printf("Out FP:%u FPUNIV:%u RB:%u IFP:%u GPIO:%u\n",
206  (unsigned int)conf->nOFP,(unsigned int)conf->nOFPUV,
207  (unsigned int)conf->nORB,(unsigned int)conf->nIFP,
208  (unsigned int)conf->nOFPDly);
209 
210  inputs.resize(conf->nIFP);
211  for(size_t i=0; i<conf->nIFP; i++){
212  std::ostringstream name;
213  name<<n<<":FPIn"<<i;
214  inputs[i]=new MRMInput(name.str(), base,i);
215  }
216 
217  // Special output for mapping bus interrupt
218  outputs[std::make_pair(OutputInt,0)]=new MRMOutput(n+":Int", this, OutputInt, 0);
219 
220  for(unsigned int i=0; i<conf->nOFP; i++){
221  std::ostringstream name;
222  name<<n<<":FrontOut"<<i;
223  outputs[std::make_pair(OutputFP,i)]=new MRMOutput(name.str(), this, OutputFP, i);
224  }
225 
226  for(unsigned int i=0; i<conf->nOFPUV; i++){
227  std::ostringstream name;
228  name<<n<<":FrontUnivOut"<<i;
229  outputs[std::make_pair(OutputFPUniv,i)]=new MRMOutput(name.str(), this, OutputFPUniv, i);
230  }
231 
232  delays.resize(conf->nOFPDly);
233  for(unsigned int i=0; i<conf->nOFPDly; i++){
234  std::ostringstream name;
235  name<<n<<":UnivDlyModule"<<i;
236  delays[i]=new DelayModule(name.str(), this, i);
237  }
238 
239  for(unsigned int i=0; i<conf->nORB; i++){
240  std::ostringstream name;
241  name<<n<<":RearUniv"<<i;
242  outputs[std::make_pair(OutputRB,i)]=new MRMOutput(name.str(), this, OutputRB, i);
243  }
244 
245  for(unsigned int i=0; i<conf->nOBack; i++){
246  std::ostringstream name;
247  name<<n<<":Backplane"<<i;
248  outputs[std::make_pair(OutputRB,i)]=new MRMOutput(name.str(), this, OutputBackplane, i);
249  }
250 
251  prescalers.resize(conf->nPS);
252  for(size_t i=0; i<conf->nPS; i++){
253  std::ostringstream name;
254  name<<n<<":PS"<<i;
255  prescalers[i]=new MRMPreScaler(name.str(), *this,base+U32_Scaler(i));
256  }
257 
258  pulsers.resize(32);
259  for(epicsUInt32 i=0; i<conf->nPul; i++){
260  std::ostringstream name;
261  name<<n<<":Pul"<<i;
262  pulsers[i]=new MRMPulser(name.str(), i,*this);
263  }
264  if(ver>=MRFVersion(2,0)) {
265  // masking pulsers
266  for(epicsUInt32 i=28; i<=31; i++){
267  std::ostringstream name;
268  name<<n<<":Pul"<<i;
269  pulsers[i]=new MRMPulser(name.str(), i,*this);
270  }
271 
272  }
273 
274  if(formfactor==formFactor_CPCIFULL) {
275  for(unsigned int i=4; i<8; i++) {
276  std::ostringstream name;
277  name<<n<<":FrontOut"<<i;
278  outputs[std::make_pair(OutputFP,i)]=new MRMOutput(name.str(), this, OutputFP, i);
279  }
280  shortcmls.resize(8, 0);
281  shortcmls[4]=new MRMCML(n+":CML4", 4,*this,MRMCML::typeCML,form);
282  shortcmls[5]=new MRMCML(n+":CML5", 5,*this,MRMCML::typeCML,form);
283  shortcmls[6]=new MRMCML(n+":CML6", 6,*this,MRMCML::typeTG300,form);
284  shortcmls[7]=new MRMCML(n+":CML7", 7,*this,MRMCML::typeTG300,form);
285 
286  } else if(formfactor==formFactor_mTCA) {
287 
288  // mapping to TCLKA and TCLKB as UNIV16, 17
289  // we move down to UNIV0, 1
290  outputs[std::make_pair(OutputFPUniv,0)]=new MRMOutput(SB()<<n<<":FrontUnivOut0", this, OutputFPUniv, 16);
291  outputs[std::make_pair(OutputFPUniv,1)]=new MRMOutput(SB()<<n<<":FrontUnivOut1", this, OutputFPUniv, 17);
292 
293  shortcmls.resize(2);
294  shortcmls[0]=new MRMCML(n+":CML0", 0,*this,MRMCML::typeCML,form);
295  shortcmls[1]=new MRMCML(n+":CML1", 1,*this,MRMCML::typeCML,form);
296 
297  } else if(conf->nCML && ver>=MRFVersion(0,4)){
298  shortcmls.resize(conf->nCML);
299  for(size_t i=0; i<conf->nCML; i++){
300  std::ostringstream name;
301  name<<n<<":CML"<<i;
302  shortcmls[i]=new MRMCML(name.str(), (unsigned char)i,*this,conf->kind,form);
303  }
304 
305  }else if(conf->nCML){
306  printf("CML outputs not supported with this firmware\n");
307  }
308 
309  for(epicsUInt32 i=0; i<NELEMENTS(this->events); i++) {
310  events[i].code=i;
311  events[i].owner=this;
312  CBINIT(&events[i].done_cb, priorityLow, &EVRMRM::sentinel_done , &events[i]);
313  }
314 
315  SCOPED_LOCK(evrLock);
316 
317  memset(_mapped, 0, sizeof(_mapped));
318  // restore mapping ram to a clean state
319  // needed when the IOC is started w/o a device reset (ie Linux)
320  //TODO: find a way to do this that doesn't require clearing
321  // mapping which will shortly be set again...
322  for(size_t i=0; i<255; i++) {
323  WRITE32(base, MappingRam(0, i, Internal), 0);
324  WRITE32(base, MappingRam(0, i, Trigger), 0);
325  WRITE32(base, MappingRam(0, i, Set), 0);
326  WRITE32(base, MappingRam(0, i, Reset), 0);
327  }
328 
329  // restore default special mappings
330  // These may be replaced later
336 
337  // Except for Prescaler reset, which is set with a record
339 
340  eventClock=FracSynthAnalyze(READ32(base, FracDiv),
341  fracref,0)*1e6;
342 
343  shadowCounterPS=READ32(base, CounterPS);
344 
345  if(tsDiv()!=0) {
346  shadowSourceTS=TSSourceInternal;
347  } else {
348  bool usedbus4=(READ32(base, Control) & Control_tsdbus) != 0;
349 
350  if(usedbus4)
351  shadowSourceTS=TSSourceDBus4;
352  else
353  shadowSourceTS=TSSourceEvent;
354  }
355 
356  eventNotifyAdd(MRF_EVENT_TS_COUNTER_RST, &seconds_tick, (void*)this);
357 
358  drain_fifo_task.start();
359 
360  if(busConfig.busType==busType_pci)
361  mrf::SPIDevice::registerDev(n+":FLASH", mrf::SPIDevice(this, 1));
362 
363 } catch (std::exception& e) {
364  printf("Aborting EVR initializtion: %s\n", e.what());
365  cleanup();
366  throw;
367 }
368 }
369 
371 {
374  cleanup();
375 }
376 
377 void
378 EVRMRM::cleanup()
379 {
380  printf("%s shuting down... ", name().c_str());
381  int wakeup=1;
382  drain_fifo_wakeup.send(&wakeup, sizeof(wakeup));
383  drain_fifo_task.exitWait();
384 
385  for(outputs_t::iterator it=outputs.begin();
386  it!=outputs.end(); ++it)
387  {
388  delete it->second;
389  }
390  outputs.clear();
391 #define CLEANVEC(TYPE, VAR) \
392  for(TYPE::iterator it=VAR.begin(); it!=VAR.end(); ++it) \
393  { delete (*it); } \
394  VAR.clear();
395 
396  CLEANVEC(inputs_t, inputs);
397  CLEANVEC(prescalers_t, prescalers);
398  CLEANVEC(pulsers_t, pulsers);
399  CLEANVEC(shortcmls_t, shortcmls);
400 
401 #undef CLEANVEC
402  printf("complete\n");
403 }
404 
405 string EVRMRM::model() const
406 {
407  return conf->model;
408 }
409 
410 epicsUInt32
412  return READ32(base, FWVersion);
413 }
414 
415 MRFVersion EVRMRM::version() const
416 {
417  return MRFVersion(READ32(base, FWVersion));
418 }
419 
422  epicsUInt32 v = READ32(base, FWVersion);
423  epicsUInt32 form = (v&FWVersion_form_mask)>>FWVersion_form_shift;
424 
425  if(form <= formFactor_mTCA) return (formFactor)form;
426  else return formFactor_unknown;
427 }
428 
429 std::string
431  std::string text;
432  formFactor form;
433 
434  form = getFormFactor();
435  switch(form){
436  case formFactor_CPCI:
437  text = "CompactPCI 3U";
438  break;
439 
440  case formFactor_CPCIFULL:
441  text = "CompactPCI 6U";
442  break;
443 
444  case formFactor_CRIO:
445  text = "CompactRIO";
446  break;
447 
448  case formFactor_PCIe:
449  text = "PCIe";
450  break;
451 
452  case formFactor_mTCA:
453  text = "mTCA";
454  break;
455 
456  case formFactor_PXIe:
457  text = "PXIe";
458  break;
459 
460  case formFactor_PMC:
461  text = "PMC";
462  break;
463 
464  case formFactor_VME64:
465  text = "VME 64";
466  break;
467 
468  default:
469  text = "Unknown form factor";
470  }
471 
472  return text;
473 }
474 
475 bool
477 {
478  epicsUInt32 v = READ32(base, Control);
479  return (v&Control_enable) != 0;
480 }
481 
482 void
484 {
485  SCOPED_LOCK(evrLock);
486  if(v)
488  else
490 }
491 
492 bool
494 {
496  return NAT_READ32(base, IRQFlag) & IRQ_HWMapped;
497 }
498 
499 MRMGpio*
501  return &gpio_;
502 }
503 
504 bool
505 EVRMRM::specialMapped(epicsUInt32 code, epicsUInt32 func) const
506 {
507  if(code>255)
508  throw std::out_of_range("Event code is out of range (0-255)");
509  if(func>127 || func<96 ||
510  (func<=121 && func>=102) )
511  {
512  throw std::out_of_range("Special function code is out of range. Valid ranges: 96-101 and 122-127");
513  }
514 
515  if(code==0)
516  return false;
517 
518  SCOPED_LOCK(evrLock);
519 
520  return _ismap(code,func-96);
521 }
522 
523 void
524 EVRMRM::specialSetMap(epicsUInt32 code, epicsUInt32 func,bool v)
525 {
526  if(code>255)
527  throw std::out_of_range("Event code is out of range");
528  /* The special function codes are the range 96 to 127, excluding 102 to 121
529  */
530  if(func>127 || func<96 ||
531  (func<=121 && func>=102) )
532  {
533  errlogPrintf("EVR %s code %02x func %3d out of range. Code range is 0-255, where function rangs are 96-101 and 122-127\n",
534  name().c_str(), code, func);
535  throw std::out_of_range("Special function code is out of range. Valid ranges: 96-101 and 122-127");
536  }
537 
538  if(code==0)
539  return;
540 
541  /* The way the latch timestamp is implimented in hardware (no status bit)
542  * makes it impossible to use the latch mapping and the latch control register
543  * bits at the same time. We use the control register bits.
544  * However, there is not much loss of functionality since all events
545  * can be timestamped in the FIFO.
546  */
547  if(func==126)
548  throw std::out_of_range("Use of latch timestamp special function code is not allowed");
549 
550  epicsUInt32 bit =func%32;
551  epicsUInt32 mask=1<<bit;
552 
553  SCOPED_LOCK(evrLock);
554 
555  epicsUInt32 val=READ32(base, MappingRam(0, code, Internal));
556 
557  if (v == _ismap(code,func-96)) {
558  // mapping already set defined
559 
560  } else if(v) {
561  _map(code,func-96);
562  WRITE32(base, MappingRam(0, code, Internal), val|mask);
563  } else {
564  _unmap(code,func-96);
565  WRITE32(base, MappingRam(0, code, Internal), val&~mask);
566  }
567 }
568 
569 void
570 EVRMRM::clockSet(double freq)
571 {
572  double err;
573  // Set both the fractional synthesiser and microsecond
574  // divider.
575  printf("Set EVR clock %f\n",freq);
576 
577  freq/=1e6;
578 
579  epicsUInt32 newfrac=FracSynthControlWord(
580  freq, fracref, 0, &err);
581 
582  if(newfrac==0)
583  throw std::out_of_range("New frequency can't be used");
584 
585  SCOPED_LOCK(evrLock);
586 
587  epicsUInt32 oldfrac=READ32(base, FracDiv);
588 
589  if(newfrac!=oldfrac){
590  // Changing the control word disturbes the phase
591  // of the synthesiser which will cause a glitch.
592  // Don't change the control word unless needed.
593 
594  WRITE32(base, FracDiv, newfrac);
595 
596  eventClock=FracSynthAnalyze(READ32(base, FracDiv),
597  fracref,0)*1e6;
598  }
599 
600  // USecDiv is accessed as a 32 bit register, but
601  // only 16 are used.
602  epicsUInt16 oldudiv=READ32(base, USecDiv);
603  epicsUInt16 newudiv=(epicsUInt16)freq;
604 
605  if(newudiv!=oldudiv){
606  WRITE32(base, USecDiv, newudiv);
607  }
608 }
609 
610 epicsUInt16
612 {
614 }
615 
616 void
617 EVRMRM::clockModeSet(epicsUInt16 mode)
618 {
619  epicsUInt32 cur = READ32(base, ClkCtrl);
620  cur &= ~ClkCtrl_clkmd_MASK;
621  cur |= (epicsUInt32(mode)<<ClkCtrl_clkmd_SHIFT)&ClkCtrl_clkmd_MASK;
622  WRITE32(base, ClkCtrl, cur);
623 }
624 
625 epicsUInt32
627 {
628  return READ32(base, USecDiv);
629 }
630 
631 bool
633 {
634  epicsUInt32 v = READ32(base, Control);
635  return (v&Control_GTXio) != 0;
636 }
637 
638 void
640 {
641  SCOPED_LOCK(evrLock);
642  if(v)
643  BITSET(NAT,32,base, Control, Control_GTXio);
644  else
645  BITCLR(NAT,32,base, Control, Control_GTXio);
646 }
647 
648 bool
650 {
651  epicsUInt32 cur = READ32(base, ClkCtrl);
652  epicsUInt32 mask = ClkCtrl_cglock;
653  if(version()>=MRFVersion(2, 7, 0))
654  mask |= ClkCtrl_plllock;
655  return (cur&mask)==mask;
656 }
657 
658 bool
660 {
661  return !(READ32(base, Status) & Status_legvio);
662 }
663 
664 void
666 {
667  double clk=clockTS(), eclk=clock();
668  epicsUInt16 div=0;
669 
670  if(clk<=0 || !isfinite(clk))
671  throw std::out_of_range("TS Clock rate invalid");
672 
673  switch(src){
674  case TSSourceInternal:
675  case TSSourceEvent:
676  case TSSourceDBus4:
677  break;
678  default:
679  throw std::out_of_range("TS source invalid");
680  }
681 
682  SCOPED_LOCK(evrLock);
683 
684  switch(src){
685  case TSSourceInternal:
686  // div!=0 selects src internal
687  div=(epicsUInt16)(eclk/clk);
688  break;
689  case TSSourceEvent:
690  BITCLR(NAT,32, base, Control, Control_tsdbus);
691  // div=0
692  break;
693  case TSSourceDBus4:
694  BITSET(NAT,32, base, Control, Control_tsdbus);
695  // div=0
696  break;
697  }
698  WRITE32(base, CounterPS, div);
699  shadowCounterPS=div;
700  shadowSourceTS=src;
701 }
702 
703 double
705 {
706  //Note: acquires evrLock 3 times.
707 
708  TSSource src=SourceTS();
709  double eclk=clock();
710 
711  if( (src!=TSSourceInternal) ||
712  ((src==TSSourceInternal) && (stampClock>eclk)))
713  return stampClock;
714 
715  epicsUInt16 div=tsDiv();
716 
717  return eclk/div;
718 }
719 
720 void
722 {
723  if(clk<0.0 || !isfinite(clk))
724  throw std::out_of_range("TS Clock rate invalid");
725 
726  TSSource src=SourceTS();
727  double eclk=clock();
728 
729  if(clk>eclk*1.01 || clk==0.0)
730  clk=eclk;
731 
732  SCOPED_LOCK(evrLock);
733 
734  if(src==TSSourceInternal){
735  epicsUInt16 div=roundToUInt(eclk/clk, 0xffff);
736  WRITE32(base, CounterPS, div);
737 
738  shadowCounterPS=div;
739  }
740 
741  stampClock=clk;
742 }
743 
744 bool
745 EVRMRM::interestedInEvent(epicsUInt32 event,bool set)
746 {
747  if (!event || event>255) return false;
748 
749  eventCode *entry=&events[event];
750 
751  SCOPED_LOCK(evrLock);
752 
753  if ( (set && entry->interested==0) // first interested
754  || (!set && entry->interested==1) // or last un-interested
755  ) {
756  specialSetMap(event, ActionFIFOSave, set);
757  }
758 
759  if (set)
760  entry->interested++;
761  else
762  entry->interested--;
763 
764  return true;
765 }
766 
767 bool
769 {
770  SCOPED_LOCK(evrLock);
771  return timestampValid>=TSValidThreshold;
772 }
773 
774 bool
775 EVRMRM::getTimeStamp(epicsTimeStamp *ret,epicsUInt32 event)
776 {
777  if(!ret) throw std::runtime_error("Invalid argument");
778  epicsTimeStamp ts;
779 
780  SCOPED_LOCK(evrLock);
781  if(timestampValid<TSValidThreshold) return false;
782 
783  if(event>0 && event<=255) {
784  // Get time of last event code #
785 
786  eventCode *entry=&events[event];
787 
788  // Fail if event is not mapped
789  if (!entry->interested ||
790  ( entry->last_sec==0 &&
791  entry->last_evt==0) )
792  {
793  return false;
794  }
795 
796  ts.secPastEpoch=entry->last_sec;
797  ts.nsec=entry->last_evt;
798 
799 
800  } else {
801  // Get current absolute time
802 
803  epicsUInt32 ctrl=READ32(base, Control);
804 
805  // Latch timestamp
806  WRITE32(base, Control, ctrl|Control_tsltch);
807 
808  ts.secPastEpoch=READ32(base, TSSecLatch);
809  ts.nsec=READ32(base, TSEvtLatch);
810 
811  /* BUG: There was a firmware bug which occasionally
812  * causes the previous write to fail with a VME bus
813  * error, and 0 the Control register.
814  *
815  * This issues has been fixed in VME firmwares EVRv 5
816  * pre2 and EVG v3 pre2. Feb 2011
817  */
818  epicsUInt32 ctrl2=READ32(base, Control);
819  if (ctrl2!=ctrl) { // tsltch bit is write-only
820  printf("Get timestamp: control register write fault. Written: %08x, readback: %08x\n",ctrl,ctrl2);
821  WRITE32(base, Control, ctrl);
822  }
823 
824  }
825 
826  if(!convertTS(&ts))
827  return false;
828 
829  *ret = ts;
830  return true;
831 }
832 
836 bool
837 EVRMRM::convertTS(epicsTimeStamp* ts)
838 {
839  // First validate the input
840 
841  //Has it been initialized?
842  if(ts->secPastEpoch==0 || ts->nsec==0){
843  return false;
844  }
845 
846  // recurrence of an invalid time
847  if(ts->secPastEpoch==lastInvalidTimestamp) {
848  timestampValid=0;
849  scanIoRequest(timestampValidChange);
850  if(evrMrmTimeDebug>0)
851  errlogPrintf("TS convert repeats known bad value new %08x bad %08x\n",
852  (unsigned)ts->secPastEpoch, (unsigned)lastInvalidTimestamp);
853  return false;
854  }
855 
856  /* Reported seconds timestamp should be no more
857  * then 1sec in the future.
858  * reporting values in the past should be caught by
859  * generalTime
860  */
861  if(ts->secPastEpoch > lastValidTimestamp+1)
862  {
863  errlogPrintf("EVR ignoring invalid TS %08x %08x (expect %08x)\n",
864  ts->secPastEpoch, ts->nsec, lastValidTimestamp);
865  timestampValid=0;
866  scanIoRequest(timestampValidChange);
867  return false;
868  }
869 
870  // Convert ticks to nanoseconds
871  double period=1e9/clockTS(); // in nanoseconds
872 
873  if(period<=0 || !isfinite(period))
874  return false;
875 
876  ts->nsec=(epicsUInt32)(ts->nsec*period);
877 
878  // 1 sec. reset is late
879  if(ts->nsec>=1000000000u) {
880  if(evrMrmTimeDebug>0)
881  errlogPrintf("TS convert NS overflow %08x %08x oflow=%u\n",
882  (unsigned)ts->secPastEpoch, (unsigned)ts->nsec,
883  unsigned(ts->nsec-1000000000u));
884 
885  // out of bounds
886  if(int(ts->nsec-1000000000u)>=evrMrmTimeNSOverflowThreshold) {
887  timestampValid=0;
888  lastInvalidTimestamp=ts->secPastEpoch;
889  scanIoRequest(timestampValidChange);
890 
891  return false;
892  }
893  // otherwise, truncate
894  ts->nsec = 999999999u;
895  }
896 
897  //Link seconds counter is POSIX time
898  ts->secPastEpoch-=POSIX_TIME_AT_EPICS_EPOCH;
899 
900  return true;
901 }
902 
903 bool
904 EVRMRM::getTicks(epicsUInt32 *tks)
905 {
906  *tks=READ32(base, TSEvt);
907  return true;
908 }
909 
910 IOSCANPVT
911 EVRMRM::eventOccurred(epicsUInt32 event) const
912 {
913  if (event>0 && event<=255)
914  return events[event].occured;
915  else
916  return NULL;
917 }
918 
919 void
920 EVRMRM::eventNotifyAdd(epicsUInt32 event, eventCallback cb, void* arg)
921 {
922  if (event==0 || event>255)
923  throw std::out_of_range("Invalid event number");
924 
925  SCOPED_LOCK2(evrLock, guard);
926 
927  events[event].notifiees.push_back( std::make_pair(cb,arg));
928 
929  interestedInEvent(event, true);
930 }
931 
932 void
933 EVRMRM::eventNotifyDel(epicsUInt32 event, eventCallback cb, void* arg)
934 {
935  if (event==0 || event>255)
936  throw std::out_of_range("Invalid event number");
937 
938  SCOPED_LOCK2(evrLock, guard);
939 
940  events[event].notifiees.remove(std::make_pair(cb,arg));
941 
942  interestedInEvent(event, false);
943 }
944 
945 epicsUInt16
947 {
948  return (READ32(base, Status) & Status_dbus_mask) >> Status_dbus_shift;
949 }
950 
951 bool
953 {
954  return READ32(base, Control) & Control_DCEna;
955 }
956 
957 void
959 {
960  if(v)
961  BITSET32(base, Control, Control_DCEna);
962  else
963  BITCLR32(base, Control, Control_DCEna);
964 }
965 
966 double
968 {
969  double period=1e9/clock(); // in nanoseconds
970  return double(READ32(base, DCTarget))/65536.0*period;
971 }
972 
973 void
975 {
976  double period=1e9/clock(); // in nanoseconds
977 
978  val /= period;
979  val *= 65536.0;
980  WRITE32(base, DCTarget, val);
981 }
982 
983 double
985 {
986  double period=1e9/clock(); // in nanoseconds
987  return double(READ32(base, DCRxVal))/65536.0*period;
988 }
989 
990 double
992 {
993  double period=1e9/clock(); // in nanoseconds
994  return double(READ32(base, DCIntVal))/65536.0*period;
995 }
996 
997 epicsUInt32
999 {
1000  return READ32(base, DCStatus);
1001 }
1002 
1003 epicsUInt32
1005 {
1006  return READ32(base, TOPID);
1007 }
1008 
1009 void
1011 {
1012  if(code==0) return;
1013  else if(code>255) throw std::runtime_error("Event code out of range");
1014  SCOPED_LOCK(evrLock);
1015 
1016  unsigned i;
1017 
1018  // spin fast
1019  for(i=0; i<100 && READ32(base, SwEvent) & SwEvent_Pend; i++) {}
1020 
1021  if(i==100) {
1022  // spin slow for <= 50ms
1023  for(i=0; i<5 && READ32(base, SwEvent) & SwEvent_Pend; i++)
1024  epicsThreadSleep(0.01);
1025 
1026  if(i==5)
1027  throw std::runtime_error("SwEvent timeout");
1028  }
1029 
1030  WRITE32(base, SwEvent, (code<<SwEvent_Code_SHIFT)|SwEvent_Ena);
1031 }
1032 
1033 epicsUInt32 EVRMRM::timeSrc() const
1034 {
1035  SCOPED_LOCK(evrLock);
1036  return timeSrcMode;
1037 }
1038 
1039 void EVRMRM::setTimeSrc(epicsUInt32 raw)
1040 {
1041  switch((timeSrcMode_t)raw) {
1042  case Disable:
1043  case External:
1044  case SysClk:
1045  break;
1046  default:
1047  throw std::runtime_error("Unsupported time source mode");
1048  }
1049  timeSrcMode_t mode((timeSrcMode_t)raw);
1050 
1051  bool changed;
1052  {
1053  SCOPED_LOCK(evrLock);
1054 
1055  changed = timeSrcMode!=mode;
1056 
1057  timeSrcMode = mode;
1058  }
1059 
1060  if(changed)
1061  softSecondsSrc(mode==SysClk);
1062 }
1063 
1068  OBJECT_PROP1("DCRx", &EVRMRM::dcRx);
1069  OBJECT_PROP1("DCInt", &EVRMRM::dcInternal);
1070  OBJECT_PROP1("DCStatusRaw", &EVRMRM::dcStatusRaw);
1071  OBJECT_PROP1("DCTOPID", &EVRMRM::topId);
1074  {
1075  std::string (EVRMRM::*getter)() const = &EVRMRM::nextSecond;
1076  OBJECT_PROP1("NextSecond", getter);
1077  }
1078  {
1079  double (EVRMRM::*getter)() const = &EVRMRM::deltaSeconds;
1080  OBJECT_PROP1("Time Error", getter);
1081  }
1082  {
1083  void (EVRMRM::*cmd)() = &EVRMRM::resyncSecond;
1084  OBJECT_PROP1("Sync TS", cmd);
1085  }
1087 
1088 
1089 void
1091 {
1092  interruptLock I;
1093 
1094  shadowIRQEna = IRQ_Enable
1096  |IRQ_Heartbeat
1098  |IRQ_SoS |IRQ_EoS;
1099 
1100  // IRQ PCIe enable flag should not be changed. Possible RACER here
1101  shadowIRQEna |= (IRQ_PCIee & (READ32(base, IRQEnable)));
1102 
1103  WRITE32(base, IRQEnable, shadowIRQEna);
1104 }
1105 
1106 void
1107 EVRMRM::isr_pci(void *arg) {
1108  EVRMRM *evr=static_cast<EVRMRM*>(arg);
1109 
1110  // Calling the default platform-independent interrupt routine
1111  evr->isr(evr, true);
1112 
1113 #if defined(__linux__) || defined(_WIN32)
1114  if(devPCIEnableInterrupt((const epicsPCIDevice*)evr->isrLinuxPvt)) {
1115  printf("Failed to re-enable interrupt. Stuck...\n");
1116  }
1117 #endif
1118 }
1119 
1120 void
1121 EVRMRM::isr_vme(void *arg) {
1122  EVRMRM *evr=static_cast<EVRMRM*>(arg);
1123 
1124  // Calling the default platform-independent interrupt routine
1125  evr->isr(evr, false);
1126 }
1127 
1128 void
1129 EVRMRM::isr_poll(void *arg) {
1130  EVRMRM *evr=static_cast<EVRMRM*>(arg);
1131 
1132  // Calling the default platform-independent interrupt routine
1133  evr->isr(evr, true);
1134 }
1135 
1136 // A place to write to which will keep the read
1137 // at the end of the ISR from being optimized out.
1138 // This value should never be used anywhere else.
1139 volatile epicsUInt32 evrMrmIsrFlagsTrashCan;
1140 
1141 void
1142 EVRMRM::isr(EVRMRM *evr, bool pci)
1143 {
1144 
1145  epicsUInt32 flags=READ32(evr->base, IRQFlag);
1146 
1147  epicsUInt32 active=flags&evr->shadowIRQEna;
1148 
1149 #if defined(vxWorks) || defined(__rtems__)
1150  if(!active) {
1151 # ifdef __rtems__
1152  if(!pci)
1153  printk("EVRMRM::isr with no active VME IRQ 0x%08x 0x%08x\n", flags, evr->shadowIRQEna);
1154 #else
1155  (void)pci;
1156 # endif
1157  // this is a shared interrupt
1158  return;
1159  }
1160  // Note that VME devices do not normally shared interrupts
1161 #else
1162  // for Linux, shared interrupts are detected by the kernel module
1163  // so any notifications to userspace are real interrupts by this device
1164  (void)pci;
1165 #endif
1166 
1167  if(active&IRQ_RXErr){
1168  evr->count_recv_error++;
1169  scanIoRequest(evr->IRQrxError);
1170 
1171  evr->shadowIRQEna &= ~IRQ_RXErr;
1172  callbackRequest(&evr->poll_link_cb);
1173  }
1174  if(active&IRQ_BufFull){
1175  // Silence interrupt
1176  BITSET(NAT,32,evr->base, DataBufCtrl, DataBufCtrl_stop);
1177 
1178  callbackRequest(&evr->data_rx_cb);
1179  }
1180  if(active&IRQ_HWMapped){
1181  evr->shadowIRQEna &= ~IRQ_HWMapped;
1182  //TODO: think of a way to use this feature...
1183  }
1184  if(active&IRQ_Event){
1185  //FIFO not-empty
1186  evr->shadowIRQEna &= ~IRQ_Event;
1187  int wakeup=0;
1188  evr->drain_fifo_wakeup.trySend(&wakeup, sizeof(wakeup));
1189  }
1190  if(active&IRQ_Heartbeat){
1191  evr->count_heartbeat++;
1192  scanIoRequest(evr->IRQheartbeat);
1193  }
1194  if(active&IRQ_FIFOFull){
1195  evr->shadowIRQEna &= ~IRQ_FIFOFull;
1196  int wakeup=0;
1197  evr->drain_fifo_wakeup.trySend(&wakeup, sizeof(wakeup));
1198 
1199  scanIoRequest(evr->IRQfifofull);
1200  }
1201  if(active&IRQ_SoS && evr->seq.get()){
1202  evr->seq->doStartOfSequence(0);
1203  }
1204  if(active&IRQ_EoS && evr->seq.get()){
1205  evr->seq->doEndOfSequence(0);
1206  }
1207  evr->count_hardware_irq++;
1208 
1209  // IRQ PCIe enable flag should not be changed. Possible RACER here
1210  evr->shadowIRQEna |= (IRQ_PCIee & (READ32(evr->base, IRQEnable)));
1211 
1212  WRITE32(evr->base, IRQFlag, flags);
1213  WRITE32(evr->base, IRQEnable, evr->shadowIRQEna);
1214  // Ensure IRQFlags is written before returning.
1216 }
1217 
1218 // Caller must hold evrLock
1219 static
1220 void
1221 eventInvoke(eventCode& event)
1222 {
1223 #ifdef HAVE_PARALLEL_CB
1224  // bit mask of priorities for which scans have been queued
1225  unsigned prio_queued =
1226 #endif
1227  scanIoRequest(event.occured);
1228 
1229  for(eventCode::notifiees_t::const_iterator it=event.notifiees.begin();
1230  it!=event.notifiees.end();
1231  ++it)
1232  {
1233  (*it->first)(it->second, event.code);
1234  }
1235 
1236  event.waitingfor=0; // assume caller handles waitingfor>0
1237  for(unsigned p=0; p<NUM_CALLBACK_PRIORITIES; p++) {
1238 #ifdef HAVE_PARALLEL_CB
1239  // only sync priorities where work is queued
1240  if((prio_queued&(1u<<p))==0) continue;
1241 #endif
1242  event.waitingfor++;
1243  event.done_cb.priority=p;
1244  callbackRequest(&event.done_cb);
1245  }
1246 }
1247 
1248 void
1249 EVRMRM::drain_fifo()
1250 {
1251  size_t i;
1252  printf("EVR FIFO task start\n");
1253 
1254  SCOPED_LOCK2(evrLock, guard);
1255 
1256  while(true) {
1257  int msg, err;
1258 
1259  guard.unlock();
1260 
1261  err=drain_fifo_wakeup.receive(&msg, sizeof(msg));
1262 
1263  if (err<0) {
1264  errlogPrintf("FIFO wakeup error %d\n",err);
1265  epicsThreadSleep(0.1); // avoid message flood
1266  guard.lock();
1267  continue;
1268 
1269  } else if(msg==1) {
1270  // Request thread stop
1271  guard.lock();
1272  break;
1273  }
1274 
1275  guard.lock();
1276 
1277  count_fifo_loops++;
1278 
1279  epicsUInt32 status;
1280 
1281  // Bound the number of events taken from the FIFO
1282  // at one time.
1283  for(i=0; i<512; i++) {
1284 
1285  status=READ32(base, IRQFlag);
1286  if (!(status&IRQ_Event))
1287  break;
1288  if (status&IRQ_RXErr)
1289  break;
1290 
1291  epicsUInt32 code=READ32(base, EvtFIFOCode);
1292  if (!code)
1293  break;
1294 
1295  if (code>NELEMENTS(events)) {
1296  // BUG: we get occasional corrupt VME reads of this register
1297  // Fixed in firmware. Feb 2011
1298  epicsUInt32 code2=READ32(base, EvtFIFOCode);
1299  if (code2>NELEMENTS(events)) {
1300  printf("Really weird event 0x%08x 0x%08x\n", code, code2);
1301  break;
1302  } else
1303  code=code2;
1304  }
1305  code &= 0xff; // (in)santity check
1306 
1307  count_fifo_events++;
1308 
1309  eventCode& evt = events[code];
1310 
1311  // cache of last time
1312  evt.last_sec=READ32(base, EvtFIFOSec);
1313  evt.last_evt=READ32(base, EvtFIFOEvt);
1314 
1315  // update any timestamp buffers
1316  for(eventCode::tbufs_t::const_iterator it(evt.tbufs.begin()), end(evt.tbufs.end());
1317  it!=end; ++it)
1318  {
1319  EVRMRMTSBuffer* tbuf = *it;
1320 
1321  if(tbuf->timeEvt==code) {
1322  EVRMRMTSBuffer::ebuf_t& buf = tbuf->ebufs[tbuf->active];
1323  // add code to buffer
1324  if(buf.pos < buf.buf.size()) {
1325  // append raw time to buffer
1326  buf.buf[buf.pos].secPastEpoch = evt.last_sec;
1327  buf.buf[buf.pos].nsec = evt.last_evt;
1328  buf.pos++;
1329 
1330  } else {
1331  buf.drop = true;
1332  tbuf->dropped++;
1333  }
1334  }
1335 
1336  if(tbuf->flushEvt==code) {
1337  // flush
1338  EVRMRMTSBuffer::ebuf_t& active = tbuf->ebufs[tbuf->active];
1339  active.flushtime.secPastEpoch = evt.last_sec;
1340  active.flushtime.nsec = evt.last_evt;
1341 
1342  active.ok &= convertTS(&active.flushtime);
1343 
1344  tbuf->doFlush();
1345  }
1346  }
1347 
1348  if (evt.again) {
1349  // ignore extra events in buffer.
1350  } else if (evt.waitingfor>0) {
1351  // already queued, but received again before all
1352  // callbacks finished. Un-map event until complete
1353  evt.again=true;
1354  specialSetMap(code, ActionFIFOSave, false);
1355  count_FIFO_sw_overrate++;
1356  } else {
1357  // needs to be queued
1358  eventInvoke(evt);
1359  }
1360 
1361  }
1362 
1363  if (status&IRQ_FIFOFull) {
1364  count_FIFO_overflow++;
1365  }
1366 
1367  if (status&(IRQ_FIFOFull|IRQ_RXErr)) {
1368  // clear fifo if link lost or buffer overflow
1369  BITSET(NAT,32, base, Control, Control_fiforst);
1370  }
1371 
1372  int iflags=epicsInterruptLock();
1373 
1374  //*
1375  shadowIRQEna |= IRQ_Event | IRQ_FIFOFull;
1376  // IRQ PCIe enable flag should not be changed. Possible RACER here
1377  shadowIRQEna |= (IRQ_PCIee & (READ32(base, IRQEnable)));
1378 
1379  WRITE32(base, IRQEnable, shadowIRQEna);
1380 
1381  epicsInterruptUnlock(iflags);
1382 
1383  // wait a fixed interval before checking again
1384  // Prevents this thread from starving others
1385  // if a high frequency event is accidentally
1386  // mapped into the FIFO.
1387  if(mrmEvrFIFOPeriod>0.0) {
1388  guard.unlock();
1389  epicsThreadSleep(mrmEvrFIFOPeriod);
1390  guard.lock();
1391  }
1392  }
1393 
1394  printf("FIFO task exiting\n");
1395 }
1396 
1397 void
1398 EVRMRM::sentinel_done(CALLBACK* cb)
1399 {
1400 try {
1401  void *vptr;
1402  callbackGetUser(vptr,cb);
1403  eventCode *sent=static_cast<eventCode*>(vptr);
1404 
1405  SCOPED_LOCK2(sent->owner->evrLock, guard);
1406 
1407  // Is this the last callback queue?
1408  if (--sent->waitingfor)
1409  return;
1410 
1411  bool run=sent->again;
1412  sent->again=false;
1413 
1414  // Re-enable mapping if disabled
1415  if (run && sent->interested) {
1416  sent->owner->specialSetMap(sent->code, ActionFIFOSave, true);
1417  }
1418 } catch(std::exception& e) {
1419  epicsPrintf("exception in sentinel_done callback: %s\n", e.what());
1420 }
1421 }
1422 
1423 void
1424 EVRMRM::poll_link(CALLBACK* cb)
1425 {
1426 try {
1427  void *vptr;
1428  callbackGetUser(vptr,cb);
1429  EVRMRM *evr=static_cast<EVRMRM*>(vptr);
1430 
1431  epicsUInt32 flags=READ32(evr->base, IRQFlag);
1432 
1433  if(flags&IRQ_RXErr){
1434  // Still down
1435  callbackRequestDelayed(&evr->poll_link_cb, 0.1); // poll again in 100ms
1436  {
1437  SCOPED_LOCK2(evr->evrLock, guard);
1438  if(evr->timestampValid && evrMrmTimeDebug>0)
1439  errlogPrintf("TS invalid as link goes down\n");
1440  evr->timestampValid=0;
1441 
1442  evr->lastInvalidTimestamp=evr->lastValidTimestamp;
1443  scanIoRequest(evr->timestampValidChange);
1444  }
1445  WRITE32(evr->base, IRQFlag, IRQ_RXErr);
1446  }else{
1447  scanIoRequest(evr->IRQrxError);
1448  int iflags=epicsInterruptLock();
1449  evr->shadowIRQEna |= IRQ_RXErr;
1450  // IRQ PCIe enable flag should not be changed. Possible RACER here
1451  evr->shadowIRQEna |= (IRQ_PCIee & (READ32(evr->base, IRQEnable)));
1452  WRITE32(evr->base, IRQEnable, evr->shadowIRQEna);
1453  epicsInterruptUnlock(iflags);
1454  }
1455 } catch(std::exception& e) {
1456  epicsPrintf("exception in poll_link callback: %s\n", e.what());
1457 }
1458 }
1459 
1460 static
1461 void send_timestamp(CALLBACK *cb)
1462 {
1463  void *raw;
1464  callbackGetUser(raw, cb);
1465  EVRMRM *evr=static_cast<EVRMRM*>(raw);
1466 
1467  evr->tickSecond();
1468 }
1469 
1470 void
1471 EVRMRM::seconds_tick(void *raw, epicsUInt32)
1472 {
1473  EVRMRM *evr=static_cast<EVRMRM*>(raw);
1474 
1475  SCOPED_LOCK2(evr->evrLock, guard);
1476 
1477  // Don't bother to latch since we are only reading the seconds
1478  epicsUInt32 newSec=READ32(evr->base, TSSec);
1479 
1480  bool valid=true;
1481 
1482  /* Received a known bad value */
1483  if(evr->lastInvalidTimestamp==newSec) {
1484  valid=false;
1485  if(evrMrmTimeDebug>0)
1486  errlogPrintf("TS reset repeats known bad value new %08x bad %08x\n",
1487  (unsigned)newSec, (unsigned)evr->lastInvalidTimestamp);
1488  }
1489 
1490  /* Received a value which is inconsistent with a previous value */
1491  if(evr->timestampValid>0
1492  && evr->lastValidTimestamp!=(newSec-1) ) {
1493  valid=false;
1494  if(evrMrmTimeDebug>0)
1495  errlogPrintf("TS reset with inconsistent value new %08x\n",
1496  (unsigned)newSec);
1497  }
1498 
1499  /* received the previous value again */
1500  else if(evr->lastValidTimestamp==newSec) {
1501  valid=false;
1502  if(evrMrmTimeDebug>0)
1503  errlogPrintf("TS reset repeats previous value new %08x last %08x\n",
1504  (unsigned)newSec, (unsigned)evr->lastValidTimestamp);
1505  }
1506 
1507 
1508  if (!valid)
1509  {
1510  if (evr->timestampValid>0) {
1511  if(evrMrmTimeDebug>0)
1512  errlogPrintf("TS reset w/ old or invalid seconds %08x (%08x %08x)\n",
1513  newSec, evr->lastValidTimestamp, evr->lastInvalidTimestamp);
1514  scanIoRequest(evr->timestampValidChange);
1515  }
1516  evr->timestampValid=0;
1517  evr->lastInvalidTimestamp=newSec;
1518  if(evrMrmTimeDebug>2)
1519  errlogPrintf("TS reset invalid new %08x\n", (unsigned)newSec);
1520 
1521  } else {
1522  if(evr->timestampValid<=TSValidThreshold) evr->timestampValid++;
1523  evr->lastValidTimestamp=newSec;
1524 
1525  if (evr->timestampValid == TSValidThreshold) {
1526  if(evrMrmTimeDebug>0)
1527  errlogPrintf("TS becomes valid after fault %08x\n",newSec);
1528  scanIoRequest(evr->timestampValidChange);
1529 
1530  } else if(evrMrmTimeDebug>2) {
1531  errlogPrintf("TS reset valid new %08x %u\n",
1532  (unsigned)newSec, (unsigned)evr->timestampValid);
1533  }
1534  }
1535 
1536  if(evr->timeSrcMode==External) {
1537  // avoid lock ordering problem with EVR lock and generalTime locks
1538  callbackSetCallback(&send_timestamp, &evr->timeSrc_cb);
1539  callbackSetUser(evr, &evr->timeSrc_cb);
1540  callbackSetPriority(priorityMedium, &evr->timeSrc_cb);
1541  callbackRequest(&evr->timeSrc_cb);
1542  }
1543 }
static void drainbuf(CALLBACK *)
Definition: drvemRxBuf.cpp:74
enum busType busType
#define BITSET32(base, offset, mask)
Definition: mrfCommonIO.h:124
virtual bool specialMapped(epicsUInt32 code, epicsUInt32 func) const OVERRIDE FINAL
Definition: drvem.cpp:505
#define FWVersion_type_mask
Definition: evrRegMap.h:137
epicsShareExtern epicsUInt32 FracSynthControlWord(epicsFloat64 DesiredFreq, epicsFloat64 ReferenceFreq, epicsInt32 debugFlag, epicsFloat64 *Error)
Definition: mrfFracSynth.c:552
#define BITCLR(ord, len, base, offset, mask)
Definition: mrfBitOps.h:26
#define ClkCtrl_cglock
Definition: evrRegMap.h:152
size_t nPS
Definition: drvem.h:101
#define Status_dbus_mask
Definition: evrRegMap.h:45
#define IRQ_SoS
Definition: evrRegMap.h:89
epicsUInt8 flushEvt
Definition: drvemTSBuffer.h:52
virtual void setExtInhib(bool) OVERRIDE FINAL
Definition: drvem.cpp:639
epicsUInt32 dummy() const
Definition: drvem.h:208
#define IRQ_Heartbeat
Definition: mrf.h:111
epicsUInt32 dropped
Definition: drvemTSBuffer.h:47
virtual ~EVRMRM()
Definition: drvem.cpp:370
double dcRx() const
Measured delay.
Definition: drvem.cpp:984
#define IRQ_FIFOFull
Definition: mrf.h:112
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
size_t nCML
Definition: drvem.h:106
size_t interested
Definition: drvem.h:57
static void registerDev(const std::string &name, const SPIDevice &)
Definition: spi.cpp:86
virtual double clock() const OVERRIDE FINAL
Definition: drvem.h:141
#define Control_tsdbus
Definition: evrRegMap.h:73
epicsTimeStamp flushtime
Definition: drvemTSBuffer.h:57
volatile unsigned char *const base
Definition: drvem.h:223
#define IRQ_PCIee
Definition: mrf.h:119
TSSource
Definition: evr.h:31
#define ClkCtrl_clkmd_SHIFT
Definition: evrRegMap.h:151
virtual bool interestedInEvent(epicsUInt32 event, bool set) OVERRIDE FINAL
Definition: drvem.cpp:745
virtual void clockTSSet(double) OVERRIDE FINAL
Definition: drvem.cpp:721
#define Control_outena
Definition: evrRegMap.h:62
#define isfinite
Definition: mrfCommon.h:326
formFactor getFormFactor()
Definition: drvem.cpp:421
bool convertTS(epicsTimeStamp *ts)
In place conversion between raw posix sec+ticks to EPICS sec+nsec.
Definition: drvem.cpp:837
virtual epicsUInt32 uSecDiv() const OVERRIDE FINAL
Approximate divider from event clock period to 1us.
Definition: drvem.cpp:626
#define IRQEnable
Definition: mrf.h:115
static void isr_pci(void *)
Definition: drvem.cpp:1107
#define SwEvent_Code_SHIFT
Definition: evgRegMap.h:91
size_t nOFPDly
Definition: drvem.h:104
#define SwEvent_Ena
Definition: evgRegMap.h:88
#define MRF_EVENT_HEARTBEAT
Definition: mrfCommon.h:116
Internal.
Definition: output.h:19
#define FWVersion_form_shift
Definition: evrRegMap.h:140
const char * model
Definition: drvem.h:99
static void isr_vme(void *)
Definition: drvem.cpp:1121
#define OBJECT_BEGIN2(klass, Base)
Definition: object.h:507
epicsUInt32 last_evt
Definition: drvem.h:60
std::vector< epicsTimeStamp > buf
Definition: drvemTSBuffer.h:56
Modular Register Map Event Receivers.
Definition: drvem.h:86
#define MRF_EVENT_RST_PRESCALERS
Definition: mrfCommon.h:118
size_t nIFP
Definition: drvem.h:109
IOSCANPVT occured
Definition: drvem.h:65
#define IRQ_RXErr
Definition: mrf.h:113
notifiees_t notifiees
Definition: drvem.h:68
std::string nextSecond() const
Definition: mrmtimesrc.cpp:273
formFactor
void clockModeSet(epicsUInt16 mode)
Definition: drvem.cpp:617
virtual bool pllLocked() const OVERRIDE FINAL
Internal PLL Status.
Definition: drvem.cpp:649
void softSecondsSrc(bool enable)
enable sending of event 125 by software timer. Simulation of external HW clock
Definition: mrmtimesrc.cpp:231
virtual TSSource SourceTS() const OVERRIDE FINAL
Definition: drvem.h:166
#define Control_mapena
Definition: evrRegMap.h:77
volatile epicsUInt32 evrMrmIsrFlagsTrashCan
Definition: drvem.cpp:1139
#define U32_DataTxCtrl
Definition: evrRegMap.h:128
size_t nORB
Definition: drvem.h:103
virtual void enable(bool v) OVERRIDE FINAL
Definition: drvem.cpp:483
virtual bool getTicks(epicsUInt32 *tks) OVERRIDE FINAL
Definition: drvem.cpp:904
static void isr(EVRMRM *evr, bool pci)
Definition: drvem.cpp:1142
virtual void specialSetMap(epicsUInt32 code, epicsUInt32 func, bool) OVERRIDE FINAL
Definition: drvem.cpp:524
void enableIRQ(void)
Definition: drvem.cpp:1090
#define IRQ_Event
Definition: mrf.h:110
double dcInternal() const
Delay compensation applied.
Definition: drvem.cpp:991
virtual epicsUInt32 tsDiv() const OVERRIDE FINAL
When using internal TS source gives the divider from event clock period to TS period.
Definition: drvem.h:162
EVRMRM * owner
Definition: drvem.h:52
size_t waitingfor
Definition: drvem.h:71
virtual void setSourceTS(TSSource) OVERRIDE FINAL
Select source which increments TS counter.
Definition: drvem.cpp:665
#define ActionFIFOSave
Definition: evrRegMap.h:362
#define DataBufCtrl_stop
Definition: evrRegMap.h:123
virtual epicsUInt16 dbus() const OVERRIDE FINAL
Definition: drvem.cpp:946
#define IRQ_Enable
Definition: mrf.h:117
double dcTarget() const
Definition: drvem.cpp:967
virtual IOSCANPVT eventOccurred(epicsUInt32 event) const OVERRIDE FINAL
Definition: drvem.cpp:911
epicsUInt32 dcStatusRaw() const
Definition: drvem.cpp:998
#define Control_fiforst
Definition: evrRegMap.h:85
int evrMrmTimeDebug
Definition: drvem.cpp:61
Rear Breakout.
Definition: output.h:22
#define ClkCtrl_clkmd_MASK
Definition: evrRegMap.h:150
OBJECT_PROP1("DCRx", &EVRMRM::dcRx)
void dcEnable(bool v)
Definition: drvem.cpp:958
#define BITCLR32(base, offset, mask)
Definition: mrfCommonIO.h:129
#define FWVersion_form_mask
Definition: evrRegMap.h:139
#define Control_enable
Definition: evrRegMap.h:53
void tickSecond()
Call just after the start of each second.
Definition: mrmtimesrc.cpp:160
virtual void clockSet(double) OVERRIDE FINAL
Definition: drvem.cpp:570
epicsUInt16 clockMode() const
Definition: drvem.cpp:611
Definition: mrmspi.h:20
virtual bool enabled() const OVERRIDE FINAL
Definition: drvem.cpp:476
#define CBINIT(ptr, prio, fn, valptr)
Definition: drvem.cpp:75
virtual bool mappedOutputState() const OVERRIDE FINAL
Definition: drvem.cpp:493
#define ClkCtrl_plllock
Definition: evrRegMap.h:149
#define NAT_READ32(base, offset)
Definition: mrfCommonIO.h:145
#define Control_evtfwd
Definition: evrRegMap.h:55
#define OBJECT_END(klass)
Definition: object.h:523
#define U32_SFPEEPROM_base
Definition: evrRegMap.h:375
size_t nOFP
Definition: drvem.h:103
#define MRF_EVENT_TS_SHIFT_0
Definition: mrfCommon.h:113
#define CLEANVEC(TYPE, VAR)
size_t nOFPUV
Definition: drvem.h:103
double mrmEvrFIFOPeriod
Definition: drvem.cpp:108
#define Control_tsltch
Definition: evrRegMap.h:75
size_t nOBack
Definition: drvem.h:103
#define IRQFlag
Definition: mrf.h:106
MRMGpio * gpio()
Definition: drvem.cpp:500
#define SwEvent_Pend
Definition: evgRegMap.h:89
epicsUInt32 topId() const
Definition: drvem.cpp:1004
void resyncSecond()
Call to re-initialize timestamp counter from system time.
Definition: mrmtimesrc.cpp:154
Front Panel.
Definition: output.h:20
epicsUInt8 timeEvt
Definition: drvemTSBuffer.h:51
MRMCML::outkind kind
Definition: drvem.h:107
#define Status_dbus_shift
Definition: evrRegMap.h:46
virtual bool linkStatus() const OVERRIDE FINAL
Definition: drvem.cpp:659
#define MRF_EVENT_TS_SHIFT_1
Definition: mrfCommon.h:114
int evrMrmSeqRxDebug
Definition: drvem.cpp:62
#define FWVersion_type_shift
Definition: evrRegMap.h:138
virtual std::string model() const OVERRIDE FINAL
Hardware model.
Definition: drvem.cpp:405
mrmBufRx bufrx
Definition: drvem.h:226
#define U32_DataTx_base
Definition: evrRegMap.h:335
virtual double clockTS() const OVERRIDE FINAL
Definition: drvem.cpp:704
unsigned char active
Definition: drvemTSBuffer.h:70
static void unregisterDev(const std::string &name)
Definition: spi.cpp:93
const std::string & name() const
Definition: object.h:393
size_t nPul
Definition: drvem.h:100
#define IRQ_EoS
Definition: evrRegMap.h:88
void setTimeSrc(epicsUInt32 mode)
Definition: drvem.cpp:1039
bus_configuration * getBusConfiguration()
Definition: evr.cpp:49
#define Status_legvio
Definition: evrRegMap.h:47
tbufs_t tbufs
Definition: drvem.h:63
FP Universal.
Definition: output.h:21
Base interface for EVRs.
Definition: evr.h:45
void dcTargetSet(double)
Definition: drvem.cpp:974
#define Control_GTXio
Definition: evrRegMap.h:68
std::string formFactorStr()
Definition: drvem.cpp:430
bool again
Definition: drvem.h:72
bool dcEnabled() const
Definition: drvem.cpp:952
virtual bool TimeStampValid() const OVERRIDE FINAL
Definition: drvem.cpp:768
#define MRF_EVENT_TS_COUNTER_RST
Definition: mrfCommon.h:124
#define NAT_WRITE32(base, offset, value)
Definition: mrfCommonIO.h:148
Backplane lines.
Definition: output.h:23
#define IRQ_BufFull
Definition: mrf.h:108
Definition: sfp.h:16
int evrMrmTimeNSOverflowThreshold
Definition: drvem.cpp:66
virtual MRFVersion version() const OVERRIDE FINAL
Firmware Version.
Definition: drvem.cpp:415
epicsUInt32 roundToUInt(double val, epicsUInt32 max)
Definition: mrfCommon.cpp:43
#define IRQ_HWMapped
Definition: mrf.h:109
#define MRF_EVENT_TS_COUNTER_INC
Definition: mrfCommon.h:120
epicsExportAddress(int, evrMrmSeqRxDebug)
#define BITSET(ord, len, base, offset, mask)
Definition: mrfBitOps.h:21
epicsUInt32 last_sec
Definition: drvem.h:59
epicsUInt32 timeSrc() const
Definition: drvem.cpp:1033
static void isr_poll(void *)
Definition: drvem.cpp:1129
#define Control_DCEna
Definition: evrRegMap.h:70
virtual bool getTimeStamp(epicsTimeStamp *ts, epicsUInt32 event) OVERRIDE FINAL
Definition: drvem.cpp:775
virtual void eventNotifyAdd(epicsUInt32, eventCallback, void *) OVERRIDE FINAL
Definition: drvem.cpp:920
epicsShareExtern epicsFloat64 FracSynthAnalyze(epicsUInt32 ControlWord, epicsFloat64 ReferenceFreq, epicsInt32 PrintFlag)
Definition: mrfFracSynth.c:844
const Config *const conf
Definition: drvem.h:222
epicsUInt8 code
Definition: drvem.h:51
void(* eventCallback)(void *userarg, epicsUInt32 event)
Definition: evr.h:158
epicsUInt32 fpgaFirmware()
Definition: drvem.cpp:411
#define WRITE32(base, offset, value)
Definition: mrfCommonIO.h:119
OBJECT_PROP2("Clock Mode", &EVRMRM::clockMode, &EVRMRM::clockModeSet)
#define U32_SPIDData
Definition: mrmspi.cpp:23
epicsMutex evrLock
Guards access to instance All callers must take this lock before any operations on this object...
Definition: drvem.h:96
void setEvtCode(epicsUInt32 code) OVERRIDE FINAL
Definition: drvem.cpp:1010
virtual bool extInhib() const OVERRIDE FINAL
Using external hardware input for inhibit?
Definition: drvem.cpp:632
mrf::auto_ptr< SFP > sfp
Definition: drvem.h:227
EVRMRM(const std::string &n, bus_configuration &busConfig, const Config *c, volatile unsigned char *, epicsUInt32)
Definition: drvem.cpp:120
CALLBACK done_cb
Definition: drvem.h:70
#define U32_Scaler(N)
Definition: evrRegMap.h:192
struct EVRMRMTSBuffer::ebuf_t ebufs[2]
#define TSValidThreshold
Definition: drvem.cpp:114
virtual void eventNotifyDel(epicsUInt32, eventCallback, void *) OVERRIDE FINAL
Definition: drvem.cpp:933
double deltaSeconds() const
last difference between
Definition: mrmtimesrc.cpp:224