Commit bd6a7f6e authored by Volker Friese's avatar Volker Friese
Browse files

Modifications following the suggestions of P.-A. Loizeau and J. de Cuveland...

Modifications following the suggestions of P.-A. Loizeau and J. de Cuveland (see #2268). Refs #2268.
parent abcf5cde
......@@ -5,62 +5,70 @@
#include "UnpackSts.h"
#include <cassert>
#include <utility>
#include <vector>
#include <cmath>
#include "StsXyterMessage.h"
using std::unique_ptr;
using std::vector;
namespace cbm::algo
{
// ---- Algorithm execution ---------------------------------------------
vector<CbmStsDigi> UnpackSts::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
const uint64_t tTimeslice)
UnpackSts::resultType UnpackSts::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
const uint64_t tTimeslice)
{
// --- Assert that parameters are set
assert(fParams);
fCurrentTsTime = tTimeslice;
// --- Output vector
vector<CbmStsDigi> digiVec;
// --- Output data
vector<CbmStsDigi> digiVec = {};
UnpackStsMonitorData moni = {};
// --- Current Timeslice time and TS_MSB epoch cycle
fCurrentTsTime = tTimeslice;
auto msTime = msDescr.idx; // Unix time of MS in ns
fCurrentCycle = std::ldiv(msTime, fkCycleLength).quot;
// --- Current TS_MSB epoch cycle
auto msTime = msDescr.idx; // Unix time of MS in ns
fCurrentCycle = std::ldiv(msTime, fCycleLength).quot;
// --- Interpret MS content as sequence of SMX messages
auto message = reinterpret_cast<const stsxyter::Message*>(msContent);
// --- Get first TS_MSB (first message in microslice must be of type ts_msb)
const stsxyter::Message firstMessage(msContent[0]);
assert(firstMessage.GetMessType() == stsxyter::MessType::TsMsb);
ProcessTsmsbMessage(firstMessage);
if (message[0].GetMessType() != stsxyter::MessType::TsMsb) {
moni.fNumErrInvalidFirstMessage++;
return std::make_pair(digiVec, moni);
}
ProcessTsmsbMessage(message[0]);
// --- Number of messages in microslice
auto msSize = msDescr.size;
assert(msSize % sizeof(stsxyter::Message) == 0);
if (msSize % sizeof(stsxyter::Message) != 0) {
moni.fNumErrInvalidMsSize++;
return std::make_pair(digiVec, moni);
}
const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
// --- Message loop
for (uint32_t messageNr = 1; messageNr < numMessages; messageNr++) {
// --- Cast MS content to STSXYTER message
const stsxyter::Message message(msContent[messageNr]);
const stsxyter::MessType type = message.GetMessType();
// --- Action depending on message type
switch (type) {
switch (message[messageNr].GetMessType()) {
case stsxyter::MessType::Hit: {
ProcessHitMessage(message, digiVec);
ProcessHitMessage(message[messageNr], digiVec, moni);
break;
}
case stsxyter::MessType::TsMsb: {
ProcessTsmsbMessage(message);
ProcessTsmsbMessage(message[messageNr]);
break;
}
default: {
moni.fNumNonHitOrTsbMessage++;
break;
}
......@@ -68,23 +76,29 @@ namespace cbm::algo
} //# Messages
return digiVec;
return std::make_pair(digiVec, moni);
}
// --------------------------------------------------------------------------
// ----- Process hit message --------------------------------------------
void UnpackSts::ProcessHitMessage(const stsxyter::Message& message, vector<CbmStsDigi>& digiVec) const
void UnpackSts::ProcessHitMessage(const stsxyter::Message& message, vector<CbmStsDigi>& digiVec,
UnpackStsMonitorData& moni) const
{
uint16_t elink = message.GetLinkIndexHitBinning();
const UnpackStsElinkPar& elinkPar = fParams->GetElinkPar(elink);
// --- Check eLink and get parameters
uint16_t elink = message.GetLinkIndexHitBinning();
if (elink >= fParams->fElinkParams.size()) {
moni.fNumErrElinkOutOfRange++;
return;
}
const UnpackStsElinkPar& elinkPar = fParams->fElinkParams.at(elink);
uint32_t asicNr = elinkPar.fAsicNr;
uint32_t numChansPerModule = fParams->fNumAsicsPerModule * fParams->fNumChansPerAsic;
// --- Hardware-to-software address
uint32_t address = elinkPar.fAddress;
uint32_t channel = 0;
uint32_t numChansPerModule = fParams->fNumAsicsPerModule * fParams->fNumChansPerAsic;
uint32_t address = elinkPar.fAddress;
uint32_t channel = 0;
if (asicNr < fParams->fNumAsicsPerModule / 2) { // front side (n side)
channel = message.GetHitChannel() + fParams->fNumChansPerAsic * asicNr;
}
......@@ -94,10 +108,13 @@ namespace cbm::algo
// --- Time stamp
// --- Expand to full Unix time in clock cycles
uint64_t timeCC = message.GetHitTimeBinning() + fCurrentEpochTime;
uint64_t timeCc = message.GetHitTimeBinning() + fCurrentEpochTime;
if (timeCc >> 59 != 0) { // avoid overflow in 64 bit // TODO: Hard-coded number!
moni.fNumErrTimestampOverflow++;
return;
}
// --- Convert time into ns
assert(timeCC >> 59 == 0); // avoid overflow in 64 bit
uint64_t timeNs = (timeCC * fParams->fClockCycleNom) / fParams->fClockCycleDen;
uint64_t timeNs = (timeCc * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen;
// --- Correct ASIC-wise offsets
timeNs -= elinkPar.fTimeOffset;
// --- Calculate time relative to timeslice
......@@ -124,7 +141,7 @@ namespace cbm::algo
// --- Update current epoch
fCurrentEpoch = epoch;
fCurrentEpochTime = (fCurrentCycle * fParams->fEpochsPerCycle + epoch) * fParams->fEpochLength;
fCurrentEpochTime = (fCurrentCycle * fkEpochsPerCycle + epoch) * fkEpochLength;
}
// --------------------------------------------------------------------------
......
......@@ -23,10 +23,10 @@ namespace cbm::algo
{
/** @struct UnpackStsAsicPar
/** @struct UnpackStsElinkPar
** @author Volker Friese <v.friese@gsi.de>
** @since 25 November 2021
** @brief Unpacking parameters for one eLink / ASIC
** @brief STS Unpacking parameters for one eLink / ASIC
**/
struct UnpackStsElinkPar {
uint32_t fAddress = 0; ///< CbmStsAddress for the connected module
......@@ -43,22 +43,23 @@ namespace cbm::algo
** @brief Parameters required for the STS unpacking (specific to one component)
**/
struct UnpackStsPar {
uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC
uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module
std::vector<UnpackStsElinkPar> fElinkParams = {}; ///< Parameters for each eLink
};
uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC
uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module
uint64_t fEpochsPerCycle = 0; ///< TS_MSB epochs per epoch cycle
uint64_t fEpochLength = 0; ///< Length of TS_MSB epoch in clock cycles
uint32_t fClockCycleNom = 0; ///< Clock cycle nominator [ns]
uint32_t fClockCycleDen = 0.; ///< Clock cycle denominator
std::vector<UnpackStsElinkPar> fElinkParams; ///< Parameters for each eLink
size_t GetNumElinks() const { return fElinkParams.size(); }
const UnpackStsElinkPar& GetElinkPar(size_t eLink) const
{
assert(eLink < GetNumElinks());
return fElinkParams[eLink];
}
/** @struct UnpackStsMoni
** @author Volker Friese <v.friese@gsi.de>
** @since 2 December 2021
** @brief Monitoring data for STS unpacking
**/
struct UnpackStsMonitorData {
uint32_t fNumNonHitOrTsbMessage = 0;
uint32_t fNumErrElinkOutOfRange = 0; ///< Elink not contained in parameters
uint32_t fNumErrInvalidFirstMessage = 0; ///< First message is not TS_MSB
uint32_t fNumErrInvalidMsSize = 0; ///< Microslice size is not multiple of message size
uint32_t fNumErrTimestampOverflow = 0; ///< Overflow in 64 bit time stamp
};
......@@ -71,6 +72,9 @@ namespace cbm::algo
class UnpackSts {
public:
typedef std::pair<std::vector<CbmStsDigi>, UnpackStsMonitorData> resultType;
/** @brief Default constructor **/
UnpackSts() {};
......@@ -85,39 +89,43 @@ namespace cbm::algo
** @param tTimeslice Unix start time of timeslice [ns]
** @return STS digi data
**/
std::vector<CbmStsDigi> operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
const uint64_t tTimeslice);
resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
const uint64_t tTimeslice);
/** @brief Set the parameter container
** @param params Pointer to parameter container
**/
void SetParams(std::unique_ptr<UnpackStsPar> params)
{
fParams = std::move(params);
fCycleLength = (fParams->fEpochsPerCycle * fParams->fEpochLength * fParams->fClockCycleNom);
fCycleLength /= fParams->fClockCycleDen;
}
void SetParams(std::unique_ptr<UnpackStsPar> params) { fParams = std::move(params); }
private:
/** @brief Process an epoch message (TS_MSB)
private: // methods
/** @brief Process a hit message
** @param message SMX message (32-bit word)
** @param digiVec Vector to append the created digi to
**/
void ProcessTsmsbMessage(const stsxyter::Message& message);
void ProcessHitMessage(const stsxyter::Message& message, std::vector<CbmStsDigi>& digiVec,
UnpackStsMonitorData& moni) const;
/** @brief Process a hit message
/** @brief Process an epoch message (TS_MSB)
** @param message SMX message (32-bit word)
** @param digiVec Vector to append the created digi to
**/
void ProcessHitMessage(const stsxyter::Message& message, std::vector<CbmStsDigi>& digiVec) const;
void ProcessTsmsbMessage(const stsxyter::Message& message);
private:
private: // members
uint64_t fCurrentTsTime = 0; ///< Unix time of timeslice in ns
uint64_t fCurrentCycle = 0; ///< Current epoch cycle
uint32_t fCurrentEpoch = 0; ///< Current epoch number within epoch cycle
uint64_t fCurrentEpochTime = 0; ///< Unix time of current epoch in clock cycles
uint64_t fCycleLength = 0; ///< Epoch cycle length in ns
static constexpr uint64_t fkEpochsPerCycle = stsxyter::kuTsMsbNbTsBinsBinning; ///< TS_MSB epochs per epoch cycle
static constexpr uint64_t fkEpochLength =
stsxyter::kuHitNbTsBinsBinning; ///< Length of TS_MSB epoch in clock cycles
static constexpr uint32_t fkClockCycleNom = stsxyter::kulClockCycleNom; ///< Clock cycle nominator [ns]
static constexpr uint32_t fkClockCycleDen = stsxyter::kulClockCycleDen; ///< Clock cycle denominator
static constexpr uint64_t fkCycleLength =
(fkEpochsPerCycle * fkEpochLength * fkClockCycleNom) / fkClockCycleDen; ///< Epoch cycle length in ns
std::unique_ptr<UnpackStsPar> fParams = nullptr; ///< Parameter container
};
......
......@@ -156,10 +156,11 @@ namespace stsxyter
static const uint32_t kuTsMsbNbTsBins = (0 < kusLenTsMsbVal ? 1 << kusLenTsMsbVal : 0);
static const uint64_t kulTsCycleNbBins =
static_cast<uint64_t>(kuTsMsbNbTsBins) * static_cast<uint64_t>(kuHitNbTsBins);
static const uint16_t kusMaskTsMsbOver = (1 << kusLenHitTsOver) - 1;
static const double kdClockCycleNs = 3.125; // ns, equivalent to 2*160 MHz clock
/// Binning FW adds 1 bit to TS in HIT message
/// => Quick and dirty hack is a factor 2!!!
static const uint16_t kusMaskTsMsbOver = (1 << kusLenHitTsOver) - 1;
static constexpr uint32_t kulClockCycleNom = 25; ///< Clock cycle nominator [ns], equivalent to 2*160 MHz clock
static constexpr uint32_t kulClockCycleDen = 8; ///< Clock cycle denominator, equivalent to 2*160 MHz clock
static constexpr double kdClockCycleNs = static_cast<double>(kulClockCycleNom) / kulClockCycleDen; // ns, not rounded
static const uint32_t kuHitNbTsBinsBinning = 1 << 10;
static const uint32_t kuTsMsbNbTsBinsBinning = 1 << kusLenTsMsbValBinning;
static const uint64_t kulTsCycleNbBinsBinning =
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment