19 #include <epicsMath.h> 21 #include <epicsMath.h> 24 #include <epicsInterrupt.h> 46 #if defined(__linux__) || defined(_WIN32) 47 # include "devLibPCI.h" 52 #include <epicsExport.h> 57 #if EPICS_VERSION_INT>=VERSION_INT(3,15,0,2) 58 # define HAVE_PARALLEL_CB 75 #define CBINIT(ptr, prio, fn, valptr) \ 77 callbackSetPriority(prio, ptr); \ 78 callbackSetCallback(fn, ptr); \ 79 callbackSetUser(valptr, ptr); \ 114 #define TSValidThreshold 5 118 const double fracref=24.0;
122 volatile unsigned char* b,
132 ,bufrx(n+
":BUFRX", b, 10)
134 ,count_hardware_irq(0)
137 ,count_FIFO_overflow(0)
143 ,drain_fifo_method(*this)
144 ,drain_fifo_task(drain_fifo_method,
"EVRFIFO",
145 epicsThreadGetStackSize(epicsThreadStackBig),
146 epicsThreadPriorityHigh )
148 ,drain_fifo_wakeup(3,sizeof(int))
149 ,count_FIFO_sw_overrate(0)
150 ,timeSrcMode(Disable)
155 ,lastInvalidTimestamp(0)
156 ,lastValidTimestamp(0)
162 const MRFVersion ver(rawver);
165 throw std::runtime_error(
"Address does not correspond to an EVR");
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");
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());
175 if(ver.firmware()!=0 && ver.firmware()!=2)
176 printf(
"Warning: Unknown firmware series %u. Your milage may vary\n", ver.firmware());
178 scanIoInit(&IRQmappedEvent);
179 scanIoInit(&IRQheartbeat);
180 scanIoInit(&IRQrxError);
181 scanIoInit(&IRQfifofull);
182 scanIoInit(×tampValidChange);
185 CBINIT(&poll_link_cb , priorityMedium, &EVRMRM::poll_link ,
this);
187 if(ver>=MRFVersion(0, 5)) {
188 std::ostringstream
name;
193 if(ver>=MRFVersion(2,7)) {
194 printf(
"Sequencer capability detected\n");
205 printf(
"Out FP:%u FPUNIV:%u RB:%u IFP:%u GPIO:%u\n",
212 std::ostringstream
name;
220 for(
unsigned int i=0; i<
conf->
nOFP; i++){
221 std::ostringstream
name;
222 name<<n<<
":FrontOut"<<i;
227 std::ostringstream
name;
228 name<<n<<
":FrontUnivOut"<<i;
234 std::ostringstream
name;
235 name<<n<<
":UnivDlyModule"<<i;
239 for(
unsigned int i=0; i<
conf->
nORB; i++){
240 std::ostringstream
name;
241 name<<n<<
":RearUniv"<<i;
246 std::ostringstream
name;
247 name<<n<<
":Backplane"<<i;
252 for(
size_t i=0; i<
conf->
nPS; i++){
253 std::ostringstream
name;
259 for(epicsUInt32 i=0; i<
conf->
nPul; i++){
260 std::ostringstream
name;
262 pulsers[i]=
new MRMPulser(name.str(), i,*
this);
264 if(ver>=MRFVersion(2,0)) {
266 for(epicsUInt32 i=28; i<=31; i++){
267 std::ostringstream
name;
269 pulsers[i]=
new MRMPulser(name.str(), i,*
this);
275 for(
unsigned int i=4; i<8; i++) {
276 std::ostringstream
name;
277 name<<n<<
":FrontOut"<<i;
280 shortcmls.resize(8, 0);
297 }
else if(
conf->
nCML && ver>=MRFVersion(0,4)){
300 std::ostringstream
name;
302 shortcmls[i]=
new MRMCML(name.str(), (
unsigned char)i,*
this,
conf->
kind,form);
306 printf(
"CML outputs not supported with this firmware\n");
309 for(epicsUInt32 i=0; i<NELEMENTS(this->events); i++) {
311 events[i].
owner=
this;
312 CBINIT(&events[i].done_cb, priorityLow, &EVRMRM::sentinel_done , &events[i]);
317 memset(_mapped, 0,
sizeof(_mapped));
322 for(
size_t i=0; i<255; i++) {
358 drain_fifo_task.start();
363 }
catch (std::exception& e) {
364 printf(
"Aborting EVR initializtion: %s\n", e.what());
380 printf(
"%s shuting down... ",
name().c_str());
382 drain_fifo_wakeup.send(&wakeup,
sizeof(wakeup));
383 drain_fifo_task.exitWait();
385 for(outputs_t::iterator it=outputs.begin();
386 it!=outputs.end(); ++it)
391 #define CLEANVEC(TYPE, VAR) \ 392 for(TYPE::iterator it=VAR.begin(); it!=VAR.end(); ++it) \ 402 printf(
"complete\n");
437 text =
"CompactPCI 3U";
441 text =
"CompactPCI 6U";
469 text =
"Unknown form factor";
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) )
512 throw std::out_of_range(
"Special function code is out of range. Valid ranges: 96-101 and 122-127");
520 return _ismap(code,func-96);
527 throw std::out_of_range(
"Event code is out of range");
530 if(func>127 || func<96 ||
531 (func<=121 && func>=102) )
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");
548 throw std::out_of_range(
"Use of latch timestamp special function code is not allowed");
550 epicsUInt32 bit =func%32;
551 epicsUInt32 mask=1<<bit;
555 epicsUInt32 val=
READ32(
base, MappingRam(0, code, Internal));
557 if (v == _ismap(code,func-96)) {
562 WRITE32(
base, MappingRam(0, code, Internal), val|mask);
564 _unmap(code,func-96);
565 WRITE32(
base, MappingRam(0, code, Internal), val&~mask);
575 printf(
"Set EVR clock %f\n",freq);
580 freq, fracref, 0, &err);
583 throw std::out_of_range(
"New frequency can't be used");
589 if(newfrac!=oldfrac){
603 epicsUInt16 newudiv=(epicsUInt16)freq;
605 if(newudiv!=oldudiv){
653 if(
version()>=MRFVersion(2, 7, 0))
655 return (cur&mask)==mask;
671 throw std::out_of_range(
"TS Clock rate invalid");
679 throw std::out_of_range(
"TS source invalid");
687 div=(epicsUInt16)(eclk/clk);
715 epicsUInt16 div=
tsDiv();
724 throw std::out_of_range(
"TS Clock rate invalid");
729 if(clk>eclk*1.01 || clk==0.0)
747 if (!event || event>255)
return false;
777 if(!ret)
throw std::runtime_error(
"Invalid argument");
783 if(event>0 && event<=255) {
820 printf(
"Get timestamp: control register write fault. Written: %08x, readback: %08x\n",ctrl,ctrl2);
842 if(ts->secPastEpoch==0 || ts->nsec==0){
847 if(ts->secPastEpoch==lastInvalidTimestamp) {
849 scanIoRequest(timestampValidChange);
851 errlogPrintf(
"TS convert repeats known bad value new %08x bad %08x\n",
852 (
unsigned)ts->secPastEpoch, (
unsigned)lastInvalidTimestamp);
861 if(ts->secPastEpoch > lastValidTimestamp+1)
863 errlogPrintf(
"EVR ignoring invalid TS %08x %08x (expect %08x)\n",
864 ts->secPastEpoch, ts->nsec, lastValidTimestamp);
866 scanIoRequest(timestampValidChange);
876 ts->nsec=(epicsUInt32)(ts->nsec*period);
879 if(ts->nsec>=1000000000u) {
881 errlogPrintf(
"TS convert NS overflow %08x %08x oflow=%u\n",
882 (
unsigned)ts->secPastEpoch, (
unsigned)ts->nsec,
883 unsigned(ts->nsec-1000000000u));
888 lastInvalidTimestamp=ts->secPastEpoch;
889 scanIoRequest(timestampValidChange);
894 ts->nsec = 999999999u;
898 ts->secPastEpoch-=POSIX_TIME_AT_EPICS_EPOCH;
913 if (event>0 && event<=255)
922 if (event==0 || event>255)
923 throw std::out_of_range(
"Invalid event number");
927 events[event].
notifiees.push_back( std::make_pair(cb,arg));
935 if (event==0 || event>255)
936 throw std::out_of_range(
"Invalid event number");
940 events[event].
notifiees.remove(std::make_pair(cb,arg));
969 double period=1e9/
clock();
970 return double(
READ32(
base, DCTarget))/65536.0*period;
976 double period=1e9/
clock();
986 double period=1e9/
clock();
987 return double(
READ32(
base, DCRxVal))/65536.0*period;
993 double period=1e9/
clock();
994 return double(
READ32(
base, DCIntVal))/65536.0*period;
1013 else if(code>255)
throw std::runtime_error(
"Event code out of range");
1024 epicsThreadSleep(0.01);
1027 throw std::runtime_error(
"SwEvent timeout");
1041 switch((timeSrcMode_t)raw) {
1047 throw std::runtime_error(
"Unsupported time source mode");
1049 timeSrcMode_t mode((timeSrcMode_t)raw);
1055 changed = timeSrcMode!=mode;
1111 evr->
isr(evr,
true);
1113 #if defined(__linux__) || defined(_WIN32) 1114 if(devPCIEnableInterrupt((
const epicsPCIDevice*)evr->isrLinuxPvt)) {
1115 printf(
"Failed to re-enable interrupt. Stuck...\n");
1125 evr->
isr(evr,
false);
1133 evr->
isr(evr,
true);
1147 epicsUInt32 active=flags&evr->shadowIRQEna;
1149 #if defined(vxWorks) || defined(__rtems__) 1153 printk(
"EVRMRM::isr with no active VME IRQ 0x%08x 0x%08x\n", flags, evr->shadowIRQEna);
1168 evr->count_recv_error++;
1169 scanIoRequest(evr->IRQrxError);
1171 evr->shadowIRQEna &= ~IRQ_RXErr;
1172 callbackRequest(&evr->poll_link_cb);
1178 callbackRequest(&evr->data_rx_cb);
1181 evr->shadowIRQEna &= ~IRQ_HWMapped;
1186 evr->shadowIRQEna &= ~IRQ_Event;
1188 evr->drain_fifo_wakeup.trySend(&wakeup,
sizeof(wakeup));
1191 evr->count_heartbeat++;
1192 scanIoRequest(evr->IRQheartbeat);
1195 evr->shadowIRQEna &= ~IRQ_FIFOFull;
1197 evr->drain_fifo_wakeup.trySend(&wakeup,
sizeof(wakeup));
1199 scanIoRequest(evr->IRQfifofull);
1201 if(active&
IRQ_SoS && evr->seq.get()){
1202 evr->seq->doStartOfSequence(0);
1204 if(active&
IRQ_EoS && evr->seq.get()){
1205 evr->seq->doEndOfSequence(0);
1207 evr->count_hardware_irq++;
1223 #ifdef HAVE_PARALLEL_CB 1225 unsigned prio_queued =
1229 for(eventCode::notifiees_t::const_iterator it=event.
notifiees.begin();
1230 it!=
event.notifiees.end();
1233 (*it->first)(it->second, event.
code);
1237 for(
unsigned p=0; p<NUM_CALLBACK_PRIORITIES; p++) {
1238 #ifdef HAVE_PARALLEL_CB 1240 if((prio_queued&(1u<<p))==0)
continue;
1243 event.done_cb.priority=p;
1244 callbackRequest(&event.
done_cb);
1249 EVRMRM::drain_fifo()
1252 printf(
"EVR FIFO task start\n");
1261 err=drain_fifo_wakeup.receive(&msg,
sizeof(msg));
1264 errlogPrintf(
"FIFO wakeup error %d\n",err);
1265 epicsThreadSleep(0.1);
1283 for(i=0; i<512; i++) {
1295 if (code>NELEMENTS(events)) {
1299 if (code2>NELEMENTS(events)) {
1300 printf(
"Really weird event 0x%08x 0x%08x\n", code, code2);
1307 count_fifo_events++;
1316 for(eventCode::tbufs_t::const_iterator it(evt.
tbufs.begin()), end(evt.
tbufs.end());
1324 if(buf.
pos < buf.
buf.size()) {
1355 count_FIFO_sw_overrate++;
1364 count_FIFO_overflow++;
1372 int iflags=epicsInterruptLock();
1381 epicsInterruptUnlock(iflags);
1394 printf(
"FIFO task exiting\n");
1398 EVRMRM::sentinel_done(CALLBACK* cb)
1402 callbackGetUser(vptr,cb);
1411 bool run=sent->
again;
1418 }
catch(std::exception& e) {
1419 epicsPrintf(
"exception in sentinel_done callback: %s\n", e.what());
1424 EVRMRM::poll_link(CALLBACK* cb)
1428 callbackGetUser(vptr,cb);
1435 callbackRequestDelayed(&evr->poll_link_cb, 0.1);
1437 SCOPED_LOCK2(evr->
evrLock, guard);
1439 errlogPrintf(
"TS invalid as link goes down\n");
1440 evr->timestampValid=0;
1442 evr->lastInvalidTimestamp=evr->lastValidTimestamp;
1443 scanIoRequest(evr->timestampValidChange);
1447 scanIoRequest(evr->IRQrxError);
1448 int iflags=epicsInterruptLock();
1453 epicsInterruptUnlock(iflags);
1455 }
catch(std::exception& e) {
1456 epicsPrintf(
"exception in poll_link callback: %s\n", e.what());
1461 void send_timestamp(CALLBACK *cb)
1464 callbackGetUser(raw, cb);
1471 EVRMRM::seconds_tick(
void *raw, epicsUInt32)
1475 SCOPED_LOCK2(evr->
evrLock, guard);
1483 if(evr->lastInvalidTimestamp==newSec) {
1486 errlogPrintf(
"TS reset repeats known bad value new %08x bad %08x\n",
1487 (
unsigned)newSec, (
unsigned)evr->lastInvalidTimestamp);
1491 if(evr->timestampValid>0
1492 && evr->lastValidTimestamp!=(newSec-1) ) {
1495 errlogPrintf(
"TS reset with inconsistent value new %08x\n",
1500 else if(evr->lastValidTimestamp==newSec) {
1503 errlogPrintf(
"TS reset repeats previous value new %08x last %08x\n",
1504 (
unsigned)newSec, (
unsigned)evr->lastValidTimestamp);
1510 if (evr->timestampValid>0) {
1512 errlogPrintf(
"TS reset w/ old or invalid seconds %08x (%08x %08x)\n",
1513 newSec, evr->lastValidTimestamp, evr->lastInvalidTimestamp);
1514 scanIoRequest(evr->timestampValidChange);
1516 evr->timestampValid=0;
1517 evr->lastInvalidTimestamp=newSec;
1519 errlogPrintf(
"TS reset invalid new %08x\n", (
unsigned)newSec);
1523 evr->lastValidTimestamp=newSec;
1527 errlogPrintf(
"TS becomes valid after fault %08x\n",newSec);
1528 scanIoRequest(evr->timestampValidChange);
1531 errlogPrintf(
"TS reset valid new %08x %u\n",
1532 (
unsigned)newSec, (
unsigned)evr->timestampValid);
1536 if(evr->timeSrcMode==External) {
1538 callbackSetCallback(&send_timestamp, &evr->timeSrc_cb);
1539 callbackSetUser(evr, &evr->timeSrc_cb);
1540 callbackSetPriority(priorityMedium, &evr->timeSrc_cb);
1541 callbackRequest(&evr->timeSrc_cb);
static void drainbuf(CALLBACK *)
#define BITSET32(base, offset, mask)
virtual bool specialMapped(epicsUInt32 code, epicsUInt32 func) const OVERRIDE FINAL
#define FWVersion_type_mask
epicsShareExtern epicsUInt32 FracSynthControlWord(epicsFloat64 DesiredFreq, epicsFloat64 ReferenceFreq, epicsInt32 debugFlag, epicsFloat64 *Error)
#define BITCLR(ord, len, base, offset, mask)
virtual void setExtInhib(bool) OVERRIDE FINAL
epicsUInt32 dummy() const
double dcRx() const
Measured delay.
#define READ32(base, offset)
static void registerDev(const std::string &name, const SPIDevice &)
virtual double clock() const OVERRIDE FINAL
volatile unsigned char *const base
#define ClkCtrl_clkmd_SHIFT
virtual bool interestedInEvent(epicsUInt32 event, bool set) OVERRIDE FINAL
virtual void clockTSSet(double) OVERRIDE FINAL
formFactor getFormFactor()
bool convertTS(epicsTimeStamp *ts)
In place conversion between raw posix sec+ticks to EPICS sec+nsec.
virtual epicsUInt32 uSecDiv() const OVERRIDE FINAL
Approximate divider from event clock period to 1us.
static void isr_pci(void *)
#define SwEvent_Code_SHIFT
#define MRF_EVENT_HEARTBEAT
#define FWVersion_form_shift
static void isr_vme(void *)
#define OBJECT_BEGIN2(klass, Base)
std::vector< epicsTimeStamp > buf
Modular Register Map Event Receivers.
#define MRF_EVENT_RST_PRESCALERS
std::string nextSecond() const
void clockModeSet(epicsUInt16 mode)
virtual bool pllLocked() const OVERRIDE FINAL
Internal PLL Status.
void softSecondsSrc(bool enable)
enable sending of event 125 by software timer. Simulation of external HW clock
virtual TSSource SourceTS() const OVERRIDE FINAL
volatile epicsUInt32 evrMrmIsrFlagsTrashCan
virtual void enable(bool v) OVERRIDE FINAL
virtual bool getTicks(epicsUInt32 *tks) OVERRIDE FINAL
static void isr(EVRMRM *evr, bool pci)
virtual void specialSetMap(epicsUInt32 code, epicsUInt32 func, bool) OVERRIDE FINAL
double dcInternal() const
Delay compensation applied.
virtual epicsUInt32 tsDiv() const OVERRIDE FINAL
When using internal TS source gives the divider from event clock period to TS period.
virtual void setSourceTS(TSSource) OVERRIDE FINAL
Select source which increments TS counter.
virtual epicsUInt16 dbus() const OVERRIDE FINAL
virtual IOSCANPVT eventOccurred(epicsUInt32 event) const OVERRIDE FINAL
epicsUInt32 dcStatusRaw() const
#define ClkCtrl_clkmd_MASK
OBJECT_PROP1("DCRx", &EVRMRM::dcRx)
#define BITCLR32(base, offset, mask)
#define FWVersion_form_mask
void tickSecond()
Call just after the start of each second.
virtual void clockSet(double) OVERRIDE FINAL
epicsUInt16 clockMode() const
virtual bool enabled() const OVERRIDE FINAL
#define CBINIT(ptr, prio, fn, valptr)
virtual bool mappedOutputState() const OVERRIDE FINAL
#define NAT_READ32(base, offset)
#define OBJECT_END(klass)
#define U32_SFPEEPROM_base
#define MRF_EVENT_TS_SHIFT_0
#define CLEANVEC(TYPE, VAR)
epicsUInt32 topId() const
void resyncSecond()
Call to re-initialize timestamp counter from system time.
#define Status_dbus_shift
virtual bool linkStatus() const OVERRIDE FINAL
#define MRF_EVENT_TS_SHIFT_1
#define FWVersion_type_shift
virtual std::string model() const OVERRIDE FINAL
Hardware model.
virtual double clockTS() const OVERRIDE FINAL
static void unregisterDev(const std::string &name)
const std::string & name() const
void setTimeSrc(epicsUInt32 mode)
bus_configuration * getBusConfiguration()
std::string formFactorStr()
virtual bool TimeStampValid() const OVERRIDE FINAL
#define MRF_EVENT_TS_COUNTER_RST
#define NAT_WRITE32(base, offset, value)
int evrMrmTimeNSOverflowThreshold
virtual MRFVersion version() const OVERRIDE FINAL
Firmware Version.
epicsUInt32 roundToUInt(double val, epicsUInt32 max)
#define MRF_EVENT_TS_COUNTER_INC
epicsExportAddress(int, evrMrmSeqRxDebug)
#define BITSET(ord, len, base, offset, mask)
epicsUInt32 timeSrc() const
static void isr_poll(void *)
virtual bool getTimeStamp(epicsTimeStamp *ts, epicsUInt32 event) OVERRIDE FINAL
virtual void eventNotifyAdd(epicsUInt32, eventCallback, void *) OVERRIDE FINAL
epicsShareExtern epicsFloat64 FracSynthAnalyze(epicsUInt32 ControlWord, epicsFloat64 ReferenceFreq, epicsInt32 PrintFlag)
void(* eventCallback)(void *userarg, epicsUInt32 event)
epicsUInt32 fpgaFirmware()
#define WRITE32(base, offset, value)
OBJECT_PROP2("Clock Mode", &EVRMRM::clockMode, &EVRMRM::clockModeSet)
epicsMutex evrLock
Guards access to instance All callers must take this lock before any operations on this object...
void setEvtCode(epicsUInt32 code) OVERRIDE FINAL
virtual bool extInhib() const OVERRIDE FINAL
Using external hardware input for inhibit?
EVRMRM(const std::string &n, bus_configuration &busConfig, const Config *c, volatile unsigned char *, epicsUInt32)
struct EVRMRMTSBuffer::ebuf_t ebufs[2]
virtual void eventNotifyDel(epicsUInt32, eventCallback, void *) OVERRIDE FINAL
double deltaSeconds() const
last difference between