Skip to content

Commit f06d999

Browse files
dstoccoaphecetche
authored andcommitted
Fix delay between the MID local clock and the CTP clock
1 parent 09fdfed commit f06d999

9 files changed

Lines changed: 103 additions & 72 deletions

File tree

Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,11 @@ InteractionRecord GBTRawDataChecker::getRawIR(uint8_t id, bool isTrigger, Intera
244244
if (isTrigger) {
245245
return ir;
246246
}
247-
ir.bc += mElectronicsDelay.BCToLocal;
247+
auto delay = mElectronicsDelay.localToBC;
248248
if (id >= crateparams::sMaxNBoardsInLink) {
249-
ir.bc += mElectronicsDelay.regToLocal;
250-
}
251-
if (ir.bc >= mResetVal) {
252-
ir.bc = ir.bc % mResetVal;
253-
++ir.orbit;
249+
delay -= mElectronicsDelay.localToReg;
254250
}
251+
applyElectronicsDelay(ir.orbit, ir.bc, -delay, mResetVal);
255252
return ir;
256253
}
257254

Detectors/MUON/MID/Raw/include/MIDRaw/ELinkDataShaper.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ class ELinkDataShaper
3838
void set(uint32_t orbit);
3939

4040
private:
41-
uint8_t mUniqueId{0}; /// UniqueId
41+
uint8_t mUniqueId = 0; /// UniqueId
4242
ElectronicsDelay mElectronicsDelay{}; /// Delays in the electronics
43-
uint32_t mRDHOrbit{0}; /// RDH orbit
44-
bool mReceivedCalibration{false}; /// Flag to indicate if the calibration trigger was received
43+
uint32_t mRDHOrbit = 0; /// RDH orbit
4544

46-
InteractionRecord mIR{}; /// Interaction record
47-
uint16_t mExpectedFETClock{}; /// Expected FET clock
48-
uint16_t mLastClock{}; /// Last clock
45+
InteractionRecord mIR; /// Interaction record
46+
InteractionRecord mExpectedFET; /// Expected FET clock
47+
int16_t mLocalToBCSelfTrig = 0; /// Local to BC for self-triggered events
48+
uint16_t mMaxBunches = 0; /// Maximum number of bunches between orbits
4949

5050
typedef void (ELinkDataShaper::*OnDoneFunction)(const ELinkDecoder&, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs);
5151
OnDoneFunction mOnDone{&ELinkDataShaper::onDoneLoc}; ///! Processes the board
@@ -57,9 +57,9 @@ class ELinkDataShaper
5757

5858
void addLoc(const ELinkDecoder& decoder, EventType eventType, InteractionRecord ir, std::vector<ROBoard>& data, std::vector<ROFRecord>& rofs);
5959
bool checkLoc(const ELinkDecoder& decoder);
60-
EventType processCalibrationTrigger(uint16_t localClock);
60+
EventType processCalibrationTrigger(const InteractionRecord& ir);
6161
void processOrbitTrigger(uint16_t localClock, uint8_t triggerWord);
62-
EventType processSelfTriggered(uint16_t localClock, InteractionRecord& ir);
62+
EventType processSelfTriggered(InteractionRecord& ir);
6363
bool processTrigger(const ELinkDecoder& decoder, EventType& eventType, InteractionRecord& ir);
6464
};
6565
} // namespace mid

Detectors/MUON/MID/Raw/include/MIDRaw/ElectronicsDelay.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <cstdint>
2020
#include <iostream>
21+
#include "CommonConstants/LHCConstants.h"
2122

2223
namespace o2
2324
{
@@ -28,9 +29,9 @@ namespace mid
2829
///
2930
/// The delays are in local clocks, and correspond to the LHC clocks (aka BCs)
3031
struct ElectronicsDelay {
31-
uint16_t calibToFET{20}; ///< Delay between calibration and FET
32-
uint16_t BCToLocal{93}; ///< Delay between collision BC and local clock
33-
uint16_t regToLocal{6}; ///< Delay between regional board and local board answers
32+
int16_t calibToFET{20}; ///< Delay between FET and calibration event
33+
int16_t localToBC{92}; ///< Delay between collision BC and local clock
34+
int16_t localToReg{6}; ///< Delay between regional board and local board answers
3435
};
3536

3637
/// Output streamer for ElectronicsDelay
@@ -45,14 +46,21 @@ std::ostream& operator<<(std::ostream& os, const ElectronicsDelay& delay);
4546
/// - keyword2 value2
4647
/// The available keywords are:
4748
/// - calibToFET
48-
/// - BCToLocal
49-
/// - regToLocal
49+
/// - localToBC
50+
/// - localToReg
5051
/// with the same meaning as the corresponding data member of the ElectronicsDelay structure.
5152
/// If the keyword is not present in the file, the default value is used.
5253
/// \param filename Path to file with delays
5354
/// \return ElectronicDelay structure
5455
ElectronicsDelay readElectronicsDelay(const char* filename);
5556

57+
/// Applies the electronics delay
58+
/// \param orbit Orbit ID
59+
/// \param bc Bunch-crossing ID
60+
/// \param delay Electronics delay to be applied
61+
/// \param maxBunches Maximum number of BCs before changing orbit
62+
void applyElectronicsDelay(uint32_t& orbit, uint16_t& bc, int16_t delay, uint16_t maxBunches = constants::lhc::LHCMaxBunches);
63+
5664
} // namespace mid
5765
} // namespace o2
5866

Detectors/MUON/MID/Raw/include/MIDRaw/Encoder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "DataFormatsMID/ROBoard.h"
2929
#include "MIDRaw/ColumnDataToLocalBoard.h"
3030
#include "MIDRaw/CrateParameters.h"
31+
#include "MIDRaw/ElectronicsDelay.h"
3132
#include "MIDRaw/FEEIdConfig.h"
3233
#include "MIDRaw/GBTUserLogicEncoder.h"
3334

@@ -41,7 +42,7 @@ class Encoder
4142
{
4243
public:
4344
void init(std::string_view outDir = ".", std::string_view fileFor = "all", int verbosity = 0, std::vector<ROBoardConfig> configurations = makeDefaultROBoardConfig());
44-
void process(gsl::span<const ColumnData> data, const InteractionRecord& ir, EventType eventType = EventType::Standard);
45+
void process(gsl::span<const ColumnData> data, InteractionRecord ir, EventType eventType = EventType::Standard);
4546
/// Sets the maximum size of the superpage
4647
void setSuperpageSize(int maxSize) { mRawWriter.setSuperPageSize(maxSize); }
4748

@@ -65,6 +66,7 @@ class Encoder
6566
std::unordered_map<uint16_t, std::vector<ROBoard>> mGBTMap; /// ROBoard per GBT link
6667
FEEIdConfig mFEEIdConfig; /// Crate FEEId mapper
6768
InteractionRecord mLastIR; /// Last interaction record
69+
ElectronicsDelay mElectronicsDelay; /// Delays in the electronics
6870

6971
std::array<GBTUserLogicEncoder, crateparams::sNGBTs> mGBTEncoders{}; /// Array of encoders per link
7072
std::array<std::vector<char>, 4> mOrbitResponse{}; /// Response to orbit trigger

Detectors/MUON/MID/Raw/src/ELinkDataShaper.cxx

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "MIDRaw/ELinkDataShaper.h"
1818

1919
#include "CommonConstants/LHCConstants.h"
20+
// #define ORBITFROMMIDRO
2021

2122
namespace o2
2223
{
@@ -39,9 +40,10 @@ ELinkDataShaper::ELinkDataShaper(bool isDebugMode, bool isLoc, uint8_t uniqueId,
3940
mOnDone = &ELinkDataShaper::onDoneReg;
4041
}
4142
}
43+
mLocalToBCSelfTrig = mElectronicsDelay.localToBC;
4244
if (!isLoc) {
43-
mElectronicsDelay.BCToLocal += electronicsDelay.regToLocal;
44-
mElectronicsDelay.calibToFET += electronicsDelay.regToLocal;
45+
mLocalToBCSelfTrig -= electronicsDelay.localToReg;
46+
mElectronicsDelay.calibToFET += electronicsDelay.localToReg;
4547
}
4648
}
4749

@@ -52,12 +54,15 @@ void ELinkDataShaper::set(uint32_t orbit)
5254

5355
if (mIR.isDummy()) {
5456
mIR.bc = 0;
55-
// The reset changes depending on the way we synch with the orbit
56-
// (see processOrbitTrigger for details)
57-
// FIXME: pick one of the two
58-
// mIR.orbit = orbit - 1; // with orbit increase
59-
mIR.orbit = orbit; // with reset to RDH
60-
mLastClock = constants::lhc::LHCMaxBunches;
57+
// The reset changes depending on the way we synch with the orbit
58+
// (see processOrbitTrigger for details)
59+
// FIXME: pick one of the two
60+
#ifdef ORBITFROMMIDRO
61+
mIR.orbit = orbit - 1; // with orbit increase
62+
#else
63+
mIR.orbit = orbit; // with reset to RDH
64+
#endif
65+
mMaxBunches = constants::lhc::LHCMaxBunches;
6166
}
6267
}
6368

@@ -67,42 +72,30 @@ bool ELinkDataShaper::checkLoc(const ELinkDecoder& decoder)
6772
return (decoder.getId() == (mUniqueId & 0xF));
6873
}
6974

70-
EventType ELinkDataShaper::processSelfTriggered(uint16_t localClock, InteractionRecord& ir)
75+
EventType ELinkDataShaper::processSelfTriggered(InteractionRecord& ir)
7176
{
7277
/// Processes the self-triggered event
7378

74-
// This is a self-triggered events.
79+
// This is a self-triggered event.
7580
// The physics data arrives with a delay compared to the BC,
7681
// which is due to the travel time of muons up to the MID chambers
7782
// plus the travel time of the signal to the readout electronics.
7883
// In the case of regional cards, a further delay is expected
7984
// since this card needs to wait for the tracklet decision of each local card.
80-
// For simplicity, this delay is added to the BCToLocal in the constructor.
85+
// For simplicity, this delay is added to the localToBC in the constructor.
8186
// In both cases, we need to correct for the delay in order to go back to the real BC.
82-
if (ir.bc < mElectronicsDelay.BCToLocal) {
83-
// If the bc is smaller than the delay, it means that the local clock was reset
84-
// This events therefore belongs to the previous orbit.
85-
// We therefore add the value of the last BC (+1 to account for the reset)
86-
// and we decrease the orbit by 1.
87-
ir.bc += mLastClock + 1;
88-
--ir.orbit;
89-
}
90-
// We can now safely subtract the delay, which, thanks to the above protection,
91-
// will not result in a negative number
92-
ir.bc -= mElectronicsDelay.BCToLocal;
93-
if (mReceivedCalibration && (localClock == mExpectedFETClock)) {
94-
// Reset the calibration flag for this e-link
95-
mReceivedCalibration = false;
87+
applyElectronicsDelay(ir.orbit, ir.bc, mLocalToBCSelfTrig, mMaxBunches);
88+
if (ir == mExpectedFET) {
9689
return EventType::FET;
9790
}
9891
return EventType::Standard;
9992
}
10093

101-
EventType ELinkDataShaper::processCalibrationTrigger(uint16_t localClock)
94+
EventType ELinkDataShaper::processCalibrationTrigger(const InteractionRecord& ir)
10295
{
10396
/// Processes the calibration event
104-
mExpectedFETClock = localClock + mElectronicsDelay.calibToFET;
105-
mReceivedCalibration = true;
97+
mExpectedFET = ir;
98+
applyElectronicsDelay(mExpectedFET.orbit, mExpectedFET.bc, mElectronicsDelay.calibToFET, mMaxBunches);
10699
return EventType::Calib;
107100
}
108101

@@ -117,15 +110,15 @@ void ELinkDataShaper::processOrbitTrigger(uint16_t localClock, uint8_t triggerWo
117110
// - set the orbit to the one found in RDH
118111
// (CAVEAT: synch is lost if we have lot of data, spanning over two orbits)
119112
// FIXME: pick one of the two
120-
// ++mIR.orbit; // orbit increase
113+
#ifdef ORBITFROMMIDRO
114+
++mIR.orbit; // orbit increase
115+
#else
121116
mIR.orbit = mRDHOrbit; // reset to RDH
117+
#endif
122118
if ((triggerWord & raw::sSOX) == 0) {
123-
mLastClock = localClock;
124-
}
125-
// The orbit trigger resets the clock.
126-
// If we received a calibration trigger, we need to change the value of the expected clock accordingly
127-
if (mReceivedCalibration) {
128-
mExpectedFETClock -= (localClock + 1);
119+
// The clock counter starts from 0, so the total number of bunches
120+
// between two orbit triggers is the last clock value + 1
121+
mMaxBunches = localClock + 1;
129122
}
130123
}
131124

@@ -147,23 +140,25 @@ bool ELinkDataShaper::processTrigger(const ELinkDecoder& decoder, EventType& eve
147140

148141
if (decoder.getTriggerWord() == 0) {
149142
// This is a self-triggered event
150-
eventType = processSelfTriggered(localClock, ir);
143+
eventType = processSelfTriggered(ir);
151144
return true;
152145
}
153146

154147
// From here we treat triggered events
155148
bool goOn = false;
156149
eventType = EventType::Standard;
157-
if (decoder.getTriggerWord() & raw::sCALIBRATE) {
158-
// This is an answer to a calibration trigger
159-
eventType = processCalibrationTrigger(localClock);
160-
goOn = true;
161-
}
162150

163151
if (decoder.getTriggerWord() & raw::sORB) {
164152
// This is the answer to an orbit trigger
165153
processOrbitTrigger(localClock, decoder.getTriggerWord());
166154
}
155+
applyElectronicsDelay(ir.orbit, ir.bc, mElectronicsDelay.localToBC, mMaxBunches);
156+
157+
if (decoder.getTriggerWord() & raw::sCALIBRATE) {
158+
// This is an answer to a calibration trigger
159+
eventType = processCalibrationTrigger(ir);
160+
goOn = true;
161+
}
167162

168163
return goOn;
169164
}

Detectors/MUON/MID/Raw/src/ElectronicsDelay.cxx

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ namespace mid
2828
std::ostream& operator<<(std::ostream& os, const ElectronicsDelay& delay)
2929
{
3030
os << "calibToFET: " << delay.calibToFET << "\n";
31-
os << "BCToLocal: " << delay.BCToLocal << "\n";
32-
os << "regToLocal: " << delay.regToLocal << "\n";
31+
os << "localToBC: " << delay.localToBC << "\n";
32+
os << "localToReg: " << delay.localToReg << "\n";
3333
return os;
3434
}
3535

@@ -44,13 +44,13 @@ ElectronicsDelay readElectronicsDelay(const char* filename)
4444
auto pos = line.find(":");
4545
if (pos != std::string::npos) {
4646
std::string key = line.substr(0, pos);
47-
uint16_t val = std::atoi(line.substr(pos + 1).c_str());
47+
int16_t val = std::atoi(line.substr(pos + 1).c_str());
4848
if (key == "calibToFET") {
4949
electronicsDelay.calibToFET = val;
50-
} else if (key == "BCToLocal") {
51-
electronicsDelay.BCToLocal = val;
52-
} else if (key == "regToLocal") {
53-
electronicsDelay.regToLocal = val;
50+
} else if (key == "localToBC") {
51+
electronicsDelay.localToBC = val;
52+
} else if (key == "localToReg") {
53+
electronicsDelay.localToReg = val;
5454
}
5555
}
5656
}
@@ -60,5 +60,26 @@ ElectronicsDelay readElectronicsDelay(const char* filename)
6060
return electronicsDelay;
6161
}
6262

63+
void applyElectronicsDelay(uint32_t& orbit, uint16_t& bc, int16_t delay, uint16_t maxBunches)
64+
{
65+
int16_t val = static_cast<int16_t>(bc) + delay;
66+
int16_t resetPeriod = static_cast<int16_t>(maxBunches);
67+
if (val < 0) {
68+
// If corrected clock is smaller than 0 it means that the local clock was reset
69+
// This event therefore belongs to the previous orbit.
70+
// We therefore add the value of the last BC (+1 to account for the reset)
71+
// and we decrease the orbit by 1.
72+
--orbit;
73+
val += resetPeriod;
74+
} else if (val >= resetPeriod) {
75+
// If the corrected clock is larger than the maximum clock (corresponding to the reset)
76+
// it means that this event belongs to the next orbit
77+
++orbit;
78+
val -= resetPeriod;
79+
}
80+
// The previous line ensure that 0<val<maxBunches, so we can safely convert the int in unit16_t
81+
bc = static_cast<uint16_t>(val);
82+
}
83+
6384
} // namespace mid
6485
} // namespace o2

Detectors/MUON/MID/Raw/src/Encoder.cxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,13 @@ void Encoder::finalize(bool closeFile)
152152
}
153153
}
154154

155-
void Encoder::process(gsl::span<const ColumnData> data, const InteractionRecord& ir, EventType eventType)
155+
void Encoder::process(gsl::span<const ColumnData> data, InteractionRecord ir, EventType eventType)
156156
{
157157
/// Encodes data
158158

159+
// The CTP trigger arrives to the electronics with a delay
160+
applyElectronicsDelay(ir.orbit, ir.bc, -mElectronicsDelay.localToBC);
161+
159162
if (ir.orbit != mLastIR.orbit) {
160163
onOrbitChange(mLastIR.orbit);
161164
}

Detectors/MUON/MID/Raw/src/GBTUserLogicEncoder.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ void GBTUserLogicEncoder::processTrigger(const InteractionRecord& ir, uint8_t tr
4949
void GBTUserLogicEncoder::process(gsl::span<const ROBoard> data, InteractionRecord ir)
5050
{
5151
/// Encode data
52-
ir += mElectronicsDelay.BCToLocal;
5352

5453
// Apply zero suppression
5554
std::vector<ROBoard> zsLocs;
@@ -63,7 +62,8 @@ void GBTUserLogicEncoder::process(gsl::span<const ROBoard> data, InteractionReco
6362
vec.insert(vec.end(), zsLocs.begin(), zsLocs.end());
6463

6564
// Get regional response
66-
auto irReg = ir + mElectronicsDelay.regToLocal;
65+
auto irReg = ir;
66+
applyElectronicsDelay(irReg.orbit, irReg.bc, mElectronicsDelay.localToReg);
6767
auto regs = mResponse.getRegionalResponse(zsLocs);
6868
auto& vecReg = mBoards[irReg];
6969
vecReg.insert(vecReg.end(), regs.begin(), regs.end());

Detectors/MUON/MID/Raw/test/testRaw.cxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,19 @@ BOOST_AUTO_TEST_CASE(GBTUserLogicDecoder)
206206
loc.patternsNBP[2] = 0x5;
207207
inData[bc].emplace_back(loc);
208208

209+
o2::mid::ElectronicsDelay electronicsDelay;
210+
209211
o2::mid::FEEIdConfig feeIdConfig;
210212
uint8_t crateId = 5;
211213
uint8_t linkInCrate = 0;
212214
uint16_t gbtUniqueId = o2::mid::crateparams::makeGBTUniqueId(crateId, linkInCrate);
213215
o2::mid::GBTUserLogicEncoder encoder;
214216
encoder.setConfig(gbtUniqueId, o2::mid::makeNoZSROBoardConfig(gbtUniqueId));
217+
215218
for (auto& item : inData) {
216-
encoder.process(item.second, o2::InteractionRecord(item.first, 0));
219+
o2::InteractionRecord ir(item.first, 0);
220+
o2::mid::applyElectronicsDelay(ir.orbit, ir.bc, -electronicsDelay.localToBC);
221+
encoder.process(item.second, ir);
217222
}
218223
std::vector<char> buf;
219224
encoder.flush(buf, o2::InteractionRecord());

0 commit comments

Comments
 (0)