From 0a07c88ce23709d8b3832315ac4cf47c196246cb Mon Sep 17 00:00:00 2001 From: rhong Date: Wed, 29 May 2024 13:27:38 -0500 Subject: [PATCH] Adding more options of time stamp generator --- evgMrmApp/Db/evgMrm.db | 59 +++++++++++++++++++++++++++- evgMrmApp/src/evg.cpp | 2 + evgMrmApp/src/evgMrm.cpp | 75 +++++++++++++++++++++++++++++++++++- evgMrmApp/src/evgMrm.h | 7 ++++ evgMrmApp/src/evgRegMap.h | 14 +++++++ mrmShared/src/mrmtimesrc.cpp | 59 ++++++++++++++++++++++++++++ mrmShared/src/mrmtimesrc.h | 4 ++ 7 files changed, 218 insertions(+), 2 deletions(-) diff --git a/evgMrmApp/Db/evgMrm.db b/evgMrmApp/Db/evgMrm.db index c1723448..28838001 100644 --- a/evgMrmApp/Db/evgMrm.db +++ b/evgMrmApp/Db/evgMrm.db @@ -86,6 +86,15 @@ record(bo, "$(P)SimTimestamp-Sel") { field(ONAM, "Simulate") } +record(bo, "$(P)SoftTickSecond-Cmd") { + field(DTYP, "Obj Prop command") + field(DESC, "Tick second via EPICS scan") + field(OUT , "@OBJ=$(OBJ), PROP=SoftTick") + field(DISV, 0) + field(SDIS, "$(P)PpsInp1-MbbiDir_.BF") + field(SCAN, "1 second") +} + record(ai, "$(P)TimeErr-I") { field(DTYP, "Obj Prop double") field(INP , "@OBJ=$(OBJ), PROP=Time Error") @@ -160,13 +169,14 @@ record(mbbo, "$(P)PpsInp1-Sel") { field(THST, "UnivInp13") field(FRST, "UnivInp14") field(FVST, "UnivInp15") + field(SXST, "EPICS Scan") field(ZRVL, "0x0") field(ONVL, "0x1") field(TWVL, "0x2") field(THVL, "0x4") field(FRVL, "0x8") field(FVVL, "0x10") - field(SXSV, "INVALID") + field(SXVL, "0x8000") field(SVSV, "INVALID") field(EISV, "INVALID") field(NISV, "INVALID") @@ -197,3 +207,50 @@ record(longin, "$(P)DbusStatus-RB" ) { field(INP , "@OBJ=$(OBJ), PROP=DbusStatus") info(autosaveFields_pass0, "SCAN") } + +# +# Timestamp Generator Select +# +record(mbbo, "$(P)TSGen-SP") { + field(DESC, "EVG TS Generator") + field(DTYP, "Obj Prop uint16") + field(OUT, "@OBJ=$(OBJ), PROP=TS Generator") + field(PINI, "YES") + field(UDF, "0") + field(VAL, "0") + field(ZRST, "Software") + field(ONST, "Internal") + field(TWST, "External") + field(ZRVL, "0x0") + field(ONVL, "0x1") + field(TWVL, "0x2") + field(THSV, "INVALID") + field(FRSV, "INVALID") + field(FVSV, "INVALID") + field(SXSV, "INVALID") + field(SVSV, "INVALID") + field(EISV, "INVALID") + field(NISV, "INVALID") + field(TESV, "INVALID") + field(ELSV, "INVALID") + field(TVSV, "INVALID") + field(TTSV, "INVALID") + field(FTSV, "INVALID") + field(FFSV, "INVALID") + field(UNSV, "INVALID") + field(IVOA, "Don't drive outputs") + field(FLNK, "$(P)TSGen-RB") + info(autosaveFields_pass0, "VAL") +} + +record(mbbi, "$(P)TSGen-RB") { + field(DESC, "EVG TS Generator") + field(DTYP, "Obj Prop uint16") + field(INP, "@OBJ=$(OBJ), PROP=TS Generator") + field(ZRST, "Software") + field(ONST, "Internal") + field(TWST, "External") + field(ZRVL, "0x0") + field(ONVL, "0x1") + field(TWVL, "0x2") +} diff --git a/evgMrmApp/src/evg.cpp b/evgMrmApp/src/evg.cpp index 0ff44cda..313c73c9 100644 --- a/evgMrmApp/src/evg.cpp +++ b/evgMrmApp/src/evg.cpp @@ -56,6 +56,7 @@ OBJECT_BEGIN(evgMrm) { OBJECT_PROP1("Sw Version", &evgMrm::getSwVersion); OBJECT_PROP1("CommitHash", &evgMrm::getCommitHash); OBJECT_PROP2("EvtCode", &evgMrm::writeonly, &evgMrm::setEvtCode); + OBJECT_PROP2("TS Generator", &evgMrm::getTSGenerator, &evgMrm::setTSGenerator); { bool (evgMrm::*getter)() const = &evgMrm::isSoftSeconds; void (evgMrm::*setter)(bool) = &evgMrm::softSecondsSrc; @@ -65,6 +66,7 @@ OBJECT_BEGIN(evgMrm) { std::string (evgMrm::*getter)() const = &evgMrm::nextSecond; OBJECT_PROP1("NextSecond", getter); } + OBJECT_PROP1("SoftTick", &evgMrm::postSoftSecondsSrc); { double (evgMrm::*getter)() const = &evgMrm::deltaSeconds; OBJECT_PROP1("Time Error", getter); diff --git a/evgMrmApp/src/evgMrm.cpp b/evgMrmApp/src/evgMrm.cpp index eba9ad6a..fb295060 100644 --- a/evgMrmApp/src/evgMrm.cpp +++ b/evgMrmApp/src/evgMrm.cpp @@ -107,6 +107,7 @@ evgMrm::evgMrm(const std::string& id, m_fracSynFreq(0), m_RFDiv(1u), m_ClkSrc(ClkSrcInternal), + m_TSGenerator(0), m_seq(this, pReg), m_acTrig(id+":AcTrig", pReg), shadowIrqEnable(READ32(m_pReg, IrqEnable)) @@ -202,6 +203,10 @@ evgMrm::evgMrm(const std::string& id, evrd.reset(new EVRMRM(id+":EVRD", busConfig, &evm_evrd_conf, pReg+0x20000, 0x10000)); evru.reset(new EVRMRM(id+":EVRU", busConfig, &evm_evru_conf, pReg+0x30000, 0x10000)); } + + //Use software generator as default + BITCLR32(m_pReg,DBusTSEvt,TSDBusEvt_MASK); + BITCLR32(m_pReg,TSControl,TSGenerator_ena_MASK); } evgMrm::~evgMrm() { @@ -425,17 +430,85 @@ evgMrm::process_inp_cb(CALLBACK *pCallback) { evg->irqExtInp_queued=0; } - evg->tickSecond(); + evg->tsHandler(); scanIoRequest(evg->ioScanTimestamp); } void evgMrm::postSoftSecondsSrc() { + setEvtCode(0x7d); tickSecond(); scanIoRequest(ioScanTimestamp); } +void +evgMrm::tsHandler() +{ + epicsUInt32 tsInternal = 0; + epicsUInt32 tsUpdated = 0; + switch(m_TSGenerator) { + case 0: + tickSecond(); + break; + case 1: + tsInternal = READ32(m_pReg,TSValue); + tsUpdated = 0; + + tsUpdated = updateSecond(tsInternal); + if ( tsInternal != tsUpdated){ + WRITE32(m_pReg,TSValue,tsUpdated); + BITSET32(m_pReg,TSControl,TSValuse_load_MASK); + } + break; + case 2: + //TODO: In the External mode, the EVM may not be able to catch the TS set by the DBus 6 and 7. For now, we may not able to show the TS + //of the EVM in this mode. + break; + default: + throw std::runtime_error("Invalid TS Generator. Valid range: 0 - 2."); + break; + } +} + +/** TS Generator **/ +/* 0 - Software: Upon the 1PPS interrupt, 0x70 and 0x71 events are generated by the tickSecond fuction. Event 0x7d must be configured as a + * trigger Event with the same 1PPS source + * 1 - Internal: DBus5 generates the event 0x7d synchronized to DBus4. EVM increments its internal second counter and sends events 0x70 and + * 0x71 automatically. DBus5 must be triggered by the same 1PPS source. + * 2 - External: DBus5 generates the event 0x7d synchronized to DBus4. Events 0x70 and 0x71 are generated by an external source via DBus6 and 7 **/ + +void +evgMrm::setTSGenerator(epicsUInt16 TSGen) +{ + m_TSGenerator = TSGen; + + switch(m_TSGenerator) { + case 0: + BITCLR32(m_pReg,DBusTSEvt,TSDBusEvt_MASK); + BITCLR32(m_pReg,TSControl,TSGenerator_ena_MASK); + break; + case 1: + BITCLR32(m_pReg,DBusTSEvt,TSDBusEvt_MASK); + BITSET32(m_pReg,DBusTSEvt,(0x01 << TSDBusEvt_SHIFT) & TSDBusEvt_MASK); + BITSET32(m_pReg,TSControl,TSGenerator_ena_MASK); + break; + case 2: + BITSET32(m_pReg,DBusTSEvt,(0x07 << TSDBusEvt_SHIFT) & TSDBusEvt_MASK); + BITCLR32(m_pReg,TSControl,TSGenerator_ena_MASK); + break; + default: + throw std::runtime_error("Invalid TS Generator. Valid range: 0 - 2."); + break; + } +} + +epicsUInt16 +evgMrm::getTSGenerator() const +{ + return m_TSGenerator; +} + void evgMrm::setEvtCode(epicsUInt32 evtCode) { if(evtCode > 255) diff --git a/evgMrmApp/src/evgMrm.h b/evgMrmApp/src/evgMrm.h index 2e49bfa2..71dae38d 100644 --- a/evgMrmApp/src/evgMrm.h +++ b/evgMrmApp/src/evgMrm.h @@ -136,6 +136,12 @@ class evgMrm : public mrf::ObjectInst, static void init_cb(CALLBACK*, int, void(*)(CALLBACK*), void*); static void process_inp_cb(CALLBACK*); + /** Timestamp Source Select **/ + void tsHandler(); + epicsUInt16 getTSGenerator() const; + void setTSGenerator(epicsUInt16 TSGen); + + /** Soft Event Set **/ void setEvtCode(epicsUInt32); // use w/ Object properties for which no getter is necessary @@ -167,6 +173,7 @@ class evgMrm : public mrf::ObjectInst, epicsFloat64 m_fracSynFreq; // In MHz unsigned m_RFDiv; ClkSrc m_ClkSrc; + epicsUInt16 m_TSGenerator; //Timestamp Generator void recalcRFDiv(); EvgSeqManager m_seq; diff --git a/evgMrmApp/src/evgRegMap.h b/evgMrmApp/src/evgRegMap.h index 95213c57..3289b57f 100644 --- a/evgMrmApp/src/evgRegMap.h +++ b/evgMrmApp/src/evgRegMap.h @@ -96,6 +96,10 @@ // #define U32_DataBufferControl 0x0020 // Data Buffer Control Register #define U32_DBusSrc 0x0024 // Distributed Data Bus Mapping Register +#define U32_DBusTSEvt 0x0028 // Timestamp events configure for the distributed Data BusD + +#define TSDBusEvt_MASK 0x000000E0 +#define TSDBusEvt_SHIFT 5 //===================== // FPGA Firmware Version @@ -108,6 +112,16 @@ #define FPGAVersion_TYPE_SHIFT 28 #define FPGAVersion_VER_MASK 0x000000FF +//===================== +// Timestamp Control +// +#define U32_TSControl 0x0034 // TS Control register +#define TSGenerator_ena_MASK 0x01 +#define TSGenerator_ena_SHIFT 0 +#define TSValuse_load_MASK 0x02 +#define TSValuse_load_SHIFT 1 +#define U32_TSValue 0x0038 // TS Value to transmit + //===================== // Event Clock Control // diff --git a/mrmShared/src/mrmtimesrc.cpp b/mrmShared/src/mrmtimesrc.cpp index 2f535617..7abfb56a 100644 --- a/mrmShared/src/mrmtimesrc.cpp +++ b/mrmShared/src/mrmtimesrc.cpp @@ -215,6 +215,47 @@ void TimeStampSource::tickSecond() } } +epicsUInt32 TimeStampSource::updateSecond(epicsUInt32 ts_in) +{ + epicsUInt32 toUpdate = ts_in; + bool ok; + + epicsTimeStamp ts; + bool valid = epicsTimeOK == generalTimeGetExceptPriority(&ts, 0, ER_PROVIDER_PRIORITY); + + { + Guard G(impl->mutex); + + ok = impl->okCnt>=5; + + /* delay re-sync request until 1Hz is stable, valid system time is available */ + if(ok && valid && impl->resync) { + toUpdate = ts.secPastEpoch+POSIX_TIME_AT_EPICS_EPOCH+1; + impl->resync = false; + } + + impl->next = toUpdate; + + if(ok && valid) { + impl->lastError = double(toUpdate) - (ts.secPastEpoch+POSIX_TIME_AT_EPICS_EPOCH); + } else { + impl->lastError = -1.0; + } + + if(!impl->timeout.get()) { + // lazy start of timestamp timeout thread + impl->timeout.reset(new epicsThread(impl->timeoutRun, + "TimeStampTimeout", + epicsThreadGetStackSize(epicsThreadStackSmall))); + impl->timeout->start(); + } + } + + impl->wakeup.signal(); + + return toUpdate; +} + bool TimeStampSource::validSeconds() const { Guard G(impl->mutex); @@ -287,3 +328,21 @@ std::string TimeStampSource::nextSecond() const return std::string(&buf[0], buf.size()); } + +std::string TimeStampSource::currentSecond() const +{ + epicsTimeStamp raw; + { + Guard G(impl->mutex); + raw.secPastEpoch = impl->next - POSIX_TIME_AT_EPICS_EPOCH -1; + raw.nsec = 0; + } + epicsTime time(raw); + + std::vector buf(40); + + buf.resize(time.strftime(&buf[0], buf.size(), "%a, %d %b %Y %H:%M:%S")); + // buf.size() doesn't include trailing nil + + return std::string(&buf[0], buf.size()); +} diff --git a/mrmShared/src/mrmtimesrc.h b/mrmShared/src/mrmtimesrc.h index 202b9f29..5ddec631 100644 --- a/mrmShared/src/mrmtimesrc.h +++ b/mrmShared/src/mrmtimesrc.h @@ -30,6 +30,9 @@ class epicsShareClass TimeStampSource //! Whether tickSecond() has been called for the past 5 seconds bool validSeconds() const; + //! Update the second counter and return the same value or the resynchronized second + epicsUInt32 updateSecond(epicsUInt32 ts_in); + //! last difference between double deltaSeconds() const; @@ -38,6 +41,7 @@ class epicsShareClass TimeStampSource bool isSoftSeconds() const; std::string nextSecond() const; + std::string currentSecond() const; protected: virtual void setEvtCode(epicsUInt32 evtCode) =0;