CbcInterface.cc 45.7 KB
Newer Older
npierre's avatar
npierre committed
1
2
/*

3
4
5
6
7
8
        FileName :                     CbcInterface.cc
        Content :                      User Interface to the Cbcs
        Programmer :                   Lorenzo BIDEGAIN, Nicolas PIERRE, Georg AUZINGER
        Version :                      1.0
        Date of creation :             10/07/14
        Support :                      mail to : lorenzo.bidegain@gmail.com, nico.pierre@icloud.com
npierre's avatar
npierre committed
9

10
 */
11

12
#include "CbcInterface.h"
13
#include "../Utils/ChannelGroupHandler.h"
Fabio Ravera's avatar
Fabio Ravera committed
14
#include "../Utils/ConsoleColor.h"
15
#include "../Utils/Container.h"
16
#include <bitset>
Lorenzo Bidegain's avatar
Lorenzo Bidegain committed
17
18
19

#define DEV_FLAG 0

20
using namespace Ph2_HwDescription;
21

22
23
namespace Ph2_HwInterface
{
24
CbcInterface::CbcInterface(const BeBoardFWMap& pBoardMap) : ReadoutChipInterface(pBoardMap) { fActiveChannels.reset(); resetPageMap(); }
25

Fabio Ravera's avatar
Fabio Ravera committed
26
CbcInterface::~CbcInterface() {}
27

Fabio Ravera's avatar
Fabio Ravera committed
28
29
bool CbcInterface::ConfigureChip(Chip* pCbc, bool pVerifLoop, uint32_t pBlockSize)
{
30
    fTrackRegisters=false;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
31
    std::stringstream cOutput;
Fabio Ravera's avatar
Fabio Ravera committed
32
    setBoard(pCbc->getBeBoardId());
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
33
    pCbc->printChipType(cOutput);
34
    LOG(INFO) << BOLDBLUE << cOutput.str() << "...Configuring chip with Id[" << +pCbc->getId() << "] oh Hybrid" << +pCbc->getHybridId() << RESET;
35

Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
36
    bool cSkipLocalRegs = false;
Fabio Ravera's avatar
Fabio Ravera committed
37
    // Deal with the ChipRegItems and encode them
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
38
39
40
41
42
43
44
45
    bool                                             cSuccess   = false;
    ChipRegMap                                       cCbcRegMap = pCbc->getRegMap();
    std::vector<std::pair<std::string, ChipRegItem>> cRegList;
    cRegList.clear();
    for(auto cMapItem: cCbcRegMap)
    {
        std::pair<std::string, ChipRegItem> cItem;
        cItem.first  = cMapItem.first;
46
        cItem.second = cMapItem.second;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
47
        cRegList.push_back(cItem);
48
    }
49
50
51
52
53
    struct
    {
        bool operator()(std::pair<std::string, ChipRegItem> a, std::pair<std::string, ChipRegItem> b) const { return a.second.fPage > b.second.fPage; }
    } customPageDec;

54
55
56
57
58
    struct
    {
        bool operator()(std::pair<std::string, ChipRegItem> a, std::pair<std::string, ChipRegItem> b) const { return a.second.fPage < b.second.fPage; }
    } customPageInc;

acarvalh's avatar
acarvalh committed
59
60
61
62
    // sort register map
    bool cSortPageInc = true;
    if(cSortPageInc)
        std::sort(cRegList.begin(), cRegList.end(), customPageInc); // all to page0 then page 1
63
    else
acarvalh's avatar
acarvalh committed
64
        std::sort(cRegList.begin(), cRegList.end(), customPageDec); // all to page1 then page 0
65
66
67
68
    struct
    {
        bool operator()(std::pair<std::string, ChipRegItem> a, std::pair<std::string, ChipRegItem> b) const { return a.second.fAddress < b.second.fAddress; }
    } customAddressInc;
acarvalh's avatar
acarvalh committed
69
70
    std::sort(cRegList.begin(), cRegList.end(), customAddressInc); // sort by address - for convenience later
    if(!lpGBTFound())
71
72
73
    {
        // vector to encode all the registers into
        std::vector<uint32_t> cVec;
74
        for(auto& cRegItem: cRegList)
75
76
77
        {
            // this is to protect from readback errors during Configure as the BandgapFuse and ChipIDFuse registers should
            // be e-fused in the CBC3
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
78
            if(cRegItem.first.find("Channel") != std::string::npos && cSkipLocalRegs) continue;
79
80
81
            if(cRegItem.first.find("BandgapFuse") != std::string::npos) continue;
            if(cRegItem.first.find("ChipIDFuse") != std::string::npos) continue;

Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
82
            // if( cRegItem.second.fPage == 0 )
83
            //     LOG (DEBUG) << BOLDBLUE << "Writing 0x" << std::hex << +cRegItem.second.fValue << std::dec << " to " <<
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
84
            //         cRegItem.first <<  " : register address 0x" << std::hex << +cRegItem.second.fAddress << std::dec
85
86
            //         << " on page " << +cRegItem.second.fPage <<  RESET;
            fBoardFW->EncodeReg(cRegItem.second, pCbc, cVec, pVerifLoop, true);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
87
#ifdef COUNT_FLAG
88
            fRegisterCount++;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
89
#endif
90
        }
91

92
93
94
        // write the registers, the answer will be in the same cVec
        // the number of times the write operation has been attempted is given by cWriteAttempts
        uint8_t cWriteAttempts = 0;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
95
96
97
98
        cSuccess               = fBoardFW->WriteChipBlockReg(cVec, cWriteAttempts, pVerifLoop);
#ifdef COUNT_FLAG
        fTransactionCount++;
#endif
99
100
    }
    else
Fabio Ravera's avatar
Fabio Ravera committed
101
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
102
103
        std::vector<std::pair<std::string, uint16_t>> cRegsToWrite;
        cRegsToWrite.clear();
104
        for(auto& cRegItem: cRegList)
105
106
107
        {
            // this is to protect from readback errors during Configure as the BandgapFuse and ChipIDFuse registers should
            // be e-fused in the CBC3
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
108
            if(cRegItem.first.find("Channel") != std::string::npos && cSkipLocalRegs) continue;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
109
            if(cRegItem.first.find("BandgapFuse") != std::string::npos) continue;
110
            if(cRegItem.first.find("ChipIDFuse") != std::string::npos) continue;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
111
112
113
114
115

            std::pair<std::string, uint16_t> cRegToWrite;
            cRegToWrite.first  = cRegItem.first;
            cRegToWrite.second = cRegItem.second.fValue;
            cRegsToWrite.push_back(cRegToWrite);
Fabio Ravera's avatar
Fabio Ravera committed
116
        }
117
        cSuccess = this->WriteChipMultReg(pCbc, cRegsToWrite, pVerifLoop);
Fabio Ravera's avatar
Fabio Ravera committed
118
    }
119
    fTrackRegisters=true;
Fabio Ravera's avatar
Fabio Ravera committed
120
121
    return cSuccess;
}
122

Fabio Ravera's avatar
Fabio Ravera committed
123
bool CbcInterface::enableInjection(ReadoutChip* pChip, bool inject, bool pVerifLoop) { return this->WriteChipReg(pChip, "TestPulse", (int)inject, pVerifLoop); }
124

Fabio Ravera's avatar
Fabio Ravera committed
125
bool CbcInterface::setInjectionAmplitude(ReadoutChip* pChip, uint8_t injectionAmplitude, bool pVerifLoop) { return this->WriteChipReg(pChip, "TestPulsePotNodeSel", injectionAmplitude, pVerifLoop); }
126

Fabio Ravera's avatar
Fabio Ravera committed
127
128
129
130
131
132
133
134
bool CbcInterface::setInjectionSchema(ReadoutChip* pCbc, const ChannelGroupBase* group, bool pVerifLoop)
{
    std::bitset<NCHANNELS> cBitset = std::bitset<NCHANNELS>(static_cast<const ChannelGroup<NCHANNELS>*>(group)->getBitset());
    if(cBitset.count() == 0) // no mask set... so do nothing
        return true;
    // LOG (DEBUG) << BOLDBLUE << "Setting injection scheme for " << std::bitset<NCHANNELS>(cBitset) << RESET;
    uint16_t cFirstHit;
    for(cFirstHit = 0; cFirstHit < NCHANNELS; cFirstHit++)
135
    {
Fabio Ravera's avatar
Fabio Ravera committed
136
        if(cBitset[cFirstHit] != 0) break;
137
    }
Fabio Ravera's avatar
Fabio Ravera committed
138
139
140
141
142
143
144
145
146
    uint8_t cGroupId = std::floor((cFirstHit % 16) / 2);
    // LOG (DEBUG) << BOLDBLUE << "First unmasked channel in position " << +cFirstHit << " --- i.e. in TP group " <<
    // +cGroupId << RESET;
    if(cGroupId > 7)
        throw Exception("bool CbcInterface::setInjectionSchema (ReadoutChip* pCbc, const ChannelGroupBase *group, bool "
                        "pVerifLoop): CBC is not able to inject the channel pattern");
    // write register which selects group
    return this->WriteChipReg(pCbc, "TestPulseGroup", cGroupId, pVerifLoop);
}
147

Fabio Ravera's avatar
Fabio Ravera committed
148
149
150
151
bool CbcInterface::maskChannelsGroup(ReadoutChip* pCbc, const ChannelGroupBase* group, bool pVerifLoop)
{
    const ChannelGroup<NCHANNELS>* originalMask = static_cast<const ChannelGroup<NCHANNELS>*>(pCbc->getChipOriginalMask());
    const ChannelGroup<NCHANNELS>* groupToMask  = static_cast<const ChannelGroup<NCHANNELS>*>(group);
152
    LOG(DEBUG) << BOLDBLUE << "\t... Applying mask to CBC" << +pCbc->getId() << " with " << group->getNumberOfEnabledChannels()
Fabio Ravera's avatar
Fabio Ravera committed
153
154
155
156
157
158
159
160
               << " enabled channels\t... mask : " << std::bitset<NCHANNELS>(groupToMask->getBitset()) << RESET;

    fActiveChannels = groupToMask->getBitset();
    // auto  a = static_cast<const ChannelGroup<NCHANNELS,1>*>(groupToMask);
    std::vector<std::pair<std::string, uint16_t>> cRegVec;
    cRegVec.clear();
    std::bitset<NCHANNELS> tmpBit(255);
    for(uint8_t maskGroup = 0; maskGroup < 32; ++maskGroup)
161
    {
Fabio Ravera's avatar
Fabio Ravera committed
162
163
164
        uint16_t cValue = (uint16_t)((originalMask->getBitset() & fActiveChannels) >> (maskGroup << 3) & tmpBit).to_ulong();
        LOG(DEBUG) << BOLDBLUE << "\t...Group" << +maskGroup << " : " << std::bitset<8>(cValue) << RESET;
        cRegVec.push_back(make_pair(fChannelMaskMapCBC3[maskGroup], (uint16_t)((originalMask->getBitset() & fActiveChannels) >> (maskGroup << 3) & tmpBit).to_ulong()));
165
    }
Fabio Ravera's avatar
Fabio Ravera committed
166
167
    return WriteChipMultReg(pCbc, cRegVec, pVerifLoop);
}
168

Fabio Ravera's avatar
Fabio Ravera committed
169
170
171
bool CbcInterface::maskChannelsAndSetInjectionSchema(ReadoutChip* pChip, const ChannelGroupBase* group, bool mask, bool inject, bool pVerifLoop)
{
    bool success = true;
Fabio Ravera's avatar
Fabio Ravera committed
172
173
    if(mask) success &= maskChannelsGroup(pChip, group, pVerifLoop);
    if(inject) success &= setInjectionSchema(pChip, group, pVerifLoop);
Fabio Ravera's avatar
Fabio Ravera committed
174
175
    return success;
}
176

Fabio Ravera's avatar
Fabio Ravera committed
177
178
179
180
181
bool CbcInterface::ConfigureChipOriginalMask(ReadoutChip* pCbc, bool pVerifLoop, uint32_t pBlockSize)
{
    ChannelGroup<NCHANNELS> allChannelEnabledGroup;
    return CbcInterface::maskChannelsGroup(pCbc, &allChannelEnabledGroup, pVerifLoop);
}
182

Fabio Ravera's avatar
Fabio Ravera committed
183
184
185
186
std::vector<uint8_t> CbcInterface::createHitListFromStubs(uint8_t pSeed, bool pSeedLayer)
{
    std::vector<uint8_t> cChannelList(0);
    uint32_t             cSeedStrip = std::floor(pSeed / 2.0); // counting from 1
acarvalh's avatar
acarvalh committed
187
    // LOG(DEBUG) << BOLDMAGENTA << "Seed of " << +pSeed << " means first hit is in strip " << +cSeedStrip << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
188
189
190
191
    size_t cNumberOfChannels = 1 + (pSeed % 2 != 0);
    for(size_t cIndex = 0; cIndex < cNumberOfChannels; cIndex++)
    {
        uint32_t cSeedChannel = 2 * (cSeedStrip - 1) + !pSeedLayer + 2 * cIndex;
acarvalh's avatar
acarvalh committed
192
        // LOG(DEBUG) << BOLDMAGENTA << ".. need to unmask channel " << +cSeedChannel << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
193
194
195
196
197
198
        cChannelList.push_back(static_cast<uint32_t>(cSeedChannel));
    }
    return cChannelList;
}
std::vector<uint8_t> CbcInterface::stubInjectionPattern(uint8_t pStubAddress, int pStubBend, bool pLayerSwap)
{
acarvalh's avatar
acarvalh committed
199
    // LOG(DEBUG) << BOLDBLUE << "Injecting... stub in position " << +pStubAddress << " [half strips] with a bend of " << pStubBend << " [half strips]." << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
200
201
202
203
204
205
206
207
208
209
210
211
212
    std::vector<uint8_t> cSeedHits = createHitListFromStubs(pStubAddress, !pLayerSwap);
    // correlation layer
    uint8_t              cCorrelated     = pStubAddress + pStubBend; // start counting strips from 0
    std::vector<uint8_t> cCorrelatedHits = createHitListFromStubs(cCorrelated, pLayerSwap);
    // merge two lists and unmask
    cSeedHits.insert(cSeedHits.end(), cCorrelatedHits.begin(), cCorrelatedHits.end());
    return cSeedHits;
}
std::vector<uint8_t> CbcInterface::stubInjectionPattern(ReadoutChip* pChip, uint8_t pStubAddress, int pStubBend)
{
    bool cLayerSwap = (this->ReadChipReg(pChip, "LayerSwap") == 1);
    return stubInjectionPattern(pStubAddress, pStubBend, cLayerSwap);
}
213
bool CbcInterface::injectStubs(ReadoutChip* pCbc, std::vector<uint8_t> pStubAddresses, std::vector<int> pStubBends, bool pUseNoise, bool pUseOffsets, uint8_t pAllOff)
Fabio Ravera's avatar
Fabio Ravera committed
214
215
{
    setBoard(pCbc->getBeBoardId());
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
216

Fabio Ravera's avatar
Fabio Ravera committed
217
218
    ChannelGroup<NCHANNELS, 1> cChannelMask;
    cChannelMask.disableAllChannels();
219
220
    std::vector<uint8_t> cActiveChannels(0);
    std::vector<uint8_t> cDisabledChannels(0);
Fabio Ravera's avatar
Fabio Ravera committed
221
222
223
    for(size_t cIndex = 0; cIndex < pStubAddresses.size(); cIndex += 1)
    {
        std::vector<uint8_t> cPattern = this->stubInjectionPattern(pCbc, pStubAddresses[cIndex], pStubBends[cIndex]);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
224
225
        // for(auto cChannel: cPattern) cChannelMask.enableChannel(cChannel);
        for(size_t cChnl = 0; cChnl < pCbc->size(); cChnl++)
226
        {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
227
            if(std::find(cPattern.begin(), cPattern.end(), cChnl) != cPattern.end())
228
            {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
229
                cActiveChannels.push_back(cChnl);
230
231
232
                cChannelMask.enableChannel(cChnl);
            }
            else
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
233
                cDisabledChannels.push_back(cChnl);
234
        }
Fabio Ravera's avatar
Fabio Ravera committed
235
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
236
    if(!pUseNoise) // with TP
Fabio Ravera's avatar
Fabio Ravera committed
237
238
239
    {
        uint16_t               cFirstHit = 0;
        std::bitset<NCHANNELS> cBitset   = std::bitset<NCHANNELS>(cChannelMask.getBitset());
acarvalh's avatar
acarvalh committed
240
        // LOG(DEBUG) << BOLDMAGENTA << "Bitset for this mask is " << cBitset << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
241
        for(cFirstHit = 0; cFirstHit < NCHANNELS; cFirstHit++)
242
        {
Fabio Ravera's avatar
Fabio Ravera committed
243
            if(cBitset[cFirstHit] != 0) break;
244
        }
Fabio Ravera's avatar
Fabio Ravera committed
245
        uint8_t cGroupId = std::floor((cFirstHit % 16) / 2);
acarvalh's avatar
acarvalh committed
246
        // LOG(DEBUG) << BOLDBLUE << "First unmasked channel in position " << +cFirstHit << " --- i.e. in TP group " << +cGroupId << RESET;
247
        if(cGroupId > 7)
Fabio Ravera's avatar
Fabio Ravera committed
248
249
            throw Exception("bool CbcInterface::setInjectionSchema (ReadoutChip* pCbc, const ChannelGroupBase *group, "
                            "bool pVerifLoop): CBC is not able to inject the channel pattern");
250
        // write register which selects group
Fabio Ravera's avatar
Fabio Ravera committed
251
        this->WriteChipReg(pCbc, "TestPulseGroup", cGroupId);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
252
253
        // write registers which enable injection
        this->enableInjection(pCbc, true); // enable injection
254
        // write register which sets TP amplitude
acarvalh's avatar
acarvalh committed
255
        // this->setInjectionAmplitude(pCbc, 0xFF - 100); // fix injection amplitude
256
257
        return this->maskChannelsGroup(pCbc, &cChannelMask);
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
258
    else // with noise
259
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
260
261
262
        // assuming global chip threshold
        // is already at the pedestal
        if(pUseOffsets)
263
264
        {
            uint8_t cAllOff = pAllOff;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
265
            uint8_t cAllOn  = 0x00;
266
            // use offsets on individual disc. to shift output to all 1 or all 0
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
267
            // always off for disabled channels
268
            std::vector<std::pair<std::string, uint16_t>> cVecReq;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
269
            for(auto cDisabledChannel: cDisabledChannels)
270
271
272
            {
                char cDacName[20];
                sprintf(cDacName, "Channel%03d", cDisabledChannel + 1);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
273
                cVecReq.push_back({cDacName, cAllOff});
274
            }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
275
276
            // always on for active channels
            for(auto cActiveChannel: cActiveChannels)
277
278
279
            {
                char cDacName[20];
                sprintf(cDacName, "Channel%03d", cActiveChannel + 1);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
280
                cVecReq.push_back({cDacName, cAllOn});
281
282
283
            }
            return this->WriteChipMultReg(pCbc, cVecReq, true);
        }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
284
        else
285
286
287
288
289
        {
            uint16_t cVcth = 1023;
            this->WriteChipReg(pCbc, "VCth", cVcth);
            return this->maskChannelsGroup(pCbc, &cChannelMask);
        }
290
    }
Fabio Ravera's avatar
Fabio Ravera committed
291
}
292

Fabio Ravera's avatar
Fabio Ravera committed
293
294
295
296
297
std::vector<uint8_t> CbcInterface::readLUT(ReadoutChip* pCbc)
{
    setBoard(pCbc->getBeBoardId());
    std::vector<uint8_t> cBendCodes(30, 0); // bend registers are 0 -- 14. Each register encodes 2 codes
    for(size_t cIndex = 0; cIndex < 15; cIndex += 1)
Fabio Ravera's avatar
Fabio Ravera committed
298
    {
Fabio Ravera's avatar
Fabio Ravera committed
299
300
301
302
        const size_t cLength = (cIndex < 10) ? 5 : 6;
        char         cBuffer[20];
        sprintf(cBuffer, "Bend%d", static_cast<int>(cIndex));
        std::string cRegName(cBuffer, cLength);
acarvalh's avatar
acarvalh committed
303
        // LOG(DEBUG) << BOLDBLUE << "Reading bend register " << cRegName << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
304
305
306
        uint16_t cValue            = this->ReadChipReg(pCbc, cRegName);
        cBendCodes[cIndex * 2]     = (cValue & 0x0F);
        cBendCodes[cIndex * 2 + 1] = (cValue & 0xF0) >> 4;
Fabio Ravera's avatar
Fabio Ravera committed
307
    }
Fabio Ravera's avatar
Fabio Ravera committed
308
309
    return cBendCodes;
}
Fabio Ravera's avatar
Fabio Ravera committed
310

Fabio Ravera's avatar
Fabio Ravera committed
311
312
313
314
315
316
uint16_t CbcInterface::readErrorRegister(ReadoutChip* pCbc)
{
    // read I2c register with error flags
    ChipRegItem cRegItem;
    cRegItem.fPage    = 0x01;
    cRegItem.fAddress = 0x1D;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
317
318
    uint8_t cErrorReg = 0xFF;
    if(!lpGBTFound())
319
320
321
    {
        setBoard(pCbc->getBeBoardId());
        std::vector<uint32_t> cVecReq;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
322
        // fBoardFW->EncodeReg(cRegItem, pCbc->getHybridId(), pCbc->getId(), cVecReq, true, false);
323
        fBoardFW->EncodeReg(cRegItem, pCbc, cVecReq, true, false);
324
325
326
327
328
329
330
        fBoardFW->ReadChipBlockReg(cVecReq);
        // bools to find the values of failed and read
        bool    cFailed = false;
        bool    cRead;
        uint8_t cChipId;
        fBoardFW->DecodeReg(cRegItem, cChipId, cVecReq[0], cRead, cFailed);
        std::pair<bool, uint16_t> cReadBack = std::make_pair(!cFailed, cRegItem.fValue);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
331
        if(cReadBack.first) cErrorReg = cReadBack.second;
332
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
333
    else
334
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
335
336
        bool cVerifLoop = true;
        bool cSuccess   = ConfigurePage(pCbc, cRegItem.fPage, cVerifLoop);
337
        if(cSuccess) cErrorReg = fBoardFW->ReadFERegister(pCbc, cRegItem.fAddress);
338
339
    }
    return cErrorReg;
Fabio Ravera's avatar
Fabio Ravera committed
340
}
341

Fabio Ravera's avatar
Fabio Ravera committed
342
343
344
345
346
347
348
349
350
351
352
353
bool CbcInterface::selectLogicMode(ReadoutChip* pCbc, std::string pModeSelect, bool pForHits, bool pForStubs, bool pVerifLoop)
{
    uint8_t pMode;
    if(pModeSelect == "Sampled")
        pMode = 0;
    else if(pModeSelect == "OR")
        pMode = 1;
    else if(pModeSelect == "HIP")
        pMode = 2;
    else if(pModeSelect == "Latched")
        pMode = 3;
    else
354
    {
Fabio Ravera's avatar
Fabio Ravera committed
355
356
        LOG(INFO) << BOLDYELLOW << "Invalid mode selected! Valid modes are Sampled/OR/Latched/HIP" << RESET;
        return false;
357
    }
Fabio Ravera's avatar
Fabio Ravera committed
358
359
360
361
362
363
364
365
    std::vector<std::pair<std::string, uint16_t>> cRegVec;
    setBoard(pCbc->getBeBoardId());
    std::string cRegName       = "Pipe&StubInpSel&Ptwidth";
    uint16_t    cOriginalValue = this->ReadChipReg(pCbc, cRegName);
    uint16_t    cMask          = 0xFF - ((3 * pForHits << 6) | (3 * pForStubs << 4));
    uint16_t    cRegValue      = (cOriginalValue & cMask) | (pMode * pForHits << 6) | (pMode * pForStubs << 4);
    // LOG (DEBUG) << BOLDBLUE << "Original register value : 0x" << std::hex << cOriginalValue << std::dec << "\t logic
    // register set to 0x" << std::hex << +cRegValue << std::dec << " to select " << pModeSelect << " mode on CBC" <<
366
    // +pCbc->getId() << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
367
368
369
370
371
    return WriteChipSingleReg(pCbc, cRegName, cRegValue, pVerifLoop);
    // WriteChipSingleReg
    // uint8_t cMask = (uint8_t)(~(((3*pForHits) << 6) | ((3*pForStubs) << 4)));
    // uint8_t cValue = (((pMode*pForHits) << 6) | ((pMode*pForStubs) << 4)) | (cOriginalValue & cMask);
    // LOG (DEBUG) << BOLDBLUE << "Settinng logic selection register to 0x" << std::hex << +cValue << std::dec << " to
372
    // select " << pModeSelect << " mode on CBC" << +pCbc->getId() << RESET; cRegVec.emplace_back (cRegName, cValue);
Fabio Ravera's avatar
Fabio Ravera committed
373
374
    // return WriteChipMultReg (pCbc, cRegVec, pVerifLoop);
}
Georg Auzinger's avatar
Georg Auzinger committed
375

Fabio Ravera's avatar
Fabio Ravera committed
376
377
378
379
380
381
bool CbcInterface::enableHipSuppression(ReadoutChip* pCbc, bool pForHits, bool pForStubs, uint8_t pClocks, bool pVerifLoop)
{
    std::vector<std::pair<std::string, uint16_t>> cRegVec;
    setBoard(pCbc->getBeBoardId());
    // configure logic mode
    if(!this->selectLogicMode(pCbc, "HIP", pForHits, pForStubs, pVerifLoop))
382
    {
Fabio Ravera's avatar
Fabio Ravera committed
383
384
        LOG(INFO) << BOLDYELLOW << "Could not select HIP mode..." << RESET;
        return false;
385
    }
Fabio Ravera's avatar
Fabio Ravera committed
386
387
388
389
390
391
392
393
    // configure hip logic
    std::string cRegName       = "HIP&TestMode";
    uint8_t     cOriginalValue = this->ReadChipReg(pCbc, cRegName);
    uint8_t     cMask          = 0x0F;
    bool        cEnableHips    = true;
    uint8_t     cMaxClocks     = 7;
    uint8_t     cValue         = (((pClocks << 5) & (cMaxClocks << 5)) & (!cEnableHips << 4)) | (cOriginalValue & cMask);
    // LOG (DEBUG) << BOLDBLUE << "Settinng HIP configuration register to 0x" << std::hex << +cValue << std::dec << " to
394
    // enable max. " << +pClocks << " clocks on CBC" << +pCbc->getId() << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
395
396
397
398
399
400
401
402
    cRegVec.emplace_back(cRegName, cValue);
    return WriteChipMultReg(pCbc, cRegVec, pVerifLoop);
}

bool CbcInterface::MaskAllChannels(ReadoutChip* pCbc, bool mask, bool pVerifLoop)
{
    ChannelGroup<NCHANNELS, 1> cChannelMask;
    if(mask)
403
        cChannelMask.disableAllChannels();
Fabio Ravera's avatar
Fabio Ravera committed
404
405
406
407
408
409
410
411
    else
        cChannelMask.enableAllChannels();
    // LOG (DEBUG)  << BOLDBLUE << "Mask to be set is " << std::bitset<254>( cChannelMask.getBitset() ) << RESET;
    return this->maskChannelsGroup(pCbc, &cChannelMask, pVerifLoop);
}

bool CbcInterface::WriteChipReg(Chip* pCbc, const std::string& dacName, uint16_t dacValue, bool pVerifLoop)
{
Fabio Ravera's avatar
Fabio Ravera committed
412
    std::lock_guard<std::mutex> theGuard(fMutex);
413
    LOG (DEBUG) << BOLDYELLOW << "CbcInterface::WriteChipReg " << dacName << RESET;
414
    if(dacName == "VCth" || dacName == "Threshold")
Fabio Ravera's avatar
Fabio Ravera committed
415
416
    {
        if(pCbc->getFrontEndType() == FrontEndType::CBC3)
417
        {
Fabio Ravera's avatar
Fabio Ravera committed
418
419
420
            if(dacValue > 1023)
                LOG(ERROR) << "Error, Threshold for CBC3 can only be 10 bit max (1023)!";
            else
421
            {
Fabio Ravera's avatar
Fabio Ravera committed
422
423
424
425
426
427
428
                std::vector<std::pair<std::string, uint16_t>> cRegVec;
                // VCth1 holds bits 0-7 and VCth2 holds 8-9
                uint16_t cVCth1 = dacValue & 0x00FF;
                uint16_t cVCth2 = (dacValue & 0x0300) >> 8;
                cRegVec.emplace_back("VCth1", cVCth1);
                cRegVec.emplace_back("VCth2", cVCth2);
                return WriteChipMultReg(pCbc, cRegVec, pVerifLoop);
429
            }
430
        }
Fabio Ravera's avatar
Fabio Ravera committed
431
432
        else
            LOG(ERROR) << "Not a valid chip type!";
433
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
434
    else if(dacName == "ClusterCut")
435
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
436
437
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "LayerSwap&CluWidth");
        uint8_t cValue    = (cRegValue & 0xF8) | dacValue;
438
439
        return WriteChipSingleReg(pCbc, "LayerSwap&CluWidth", cValue, pVerifLoop);
    }
Fabio Ravera's avatar
Fabio Ravera committed
440
    else if(dacName == "TriggerLatency")
441
    {
Fabio Ravera's avatar
Fabio Ravera committed
442
        if(pCbc->getFrontEndType() == FrontEndType::CBC3)
443
        {
Fabio Ravera's avatar
Fabio Ravera committed
444
445
446
            if(dacValue > 511)
                LOG(ERROR) << "Error, Threshold for CBC3 can only be 10 bit max (1023)!";
            else
447
            {
Fabio Ravera's avatar
Fabio Ravera committed
448
449
450
451
452
453
                std::vector<std::pair<std::string, uint16_t>> cRegVec;
                // TriggerLatency1 holds bits 0-7 and FeCtrl&TrgLate2 holds 8
                uint16_t cLat1 = dacValue & 0x00FF;
                uint16_t cLat2 = (pCbc->getReg("FeCtrl&TrgLat2") & 0xFE) | ((dacValue & 0x0100) >> 8);
                cRegVec.emplace_back("TriggerLatency1", cLat1);
                cRegVec.emplace_back("FeCtrl&TrgLat2", cLat2);
454
455
                // LOG(INFO) << BOLDBLUE << "Setting latency on " << +pCbc->getId() << " to " << +dacValue << " 0x" << std::hex << +cLat1 << std::dec << " --- 0x" << std::hex << +cLat2 << std::dec
                //            << " for a latency vale of " << dacValue << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
456
                return WriteChipMultReg(pCbc, cRegVec, pVerifLoop);
457
            }
458
        }
459
        else
Fabio Ravera's avatar
Fabio Ravera committed
460
            LOG(ERROR) << "Not a valid chip type!";
461
    }
Fabio Ravera's avatar
Fabio Ravera committed
462
463
464
465
466
467
468
469
470
471
    else if(dacName == "TestPulseDelay")
    {
        uint8_t cValue = pCbc->getReg("TestPulseDel&ChanGroup");
        uint8_t cGroup = cValue & 0x07;
        // groupId is reversed in this register
        std::bitset<5> cDelay  = dacValue;
        std::string    cSelect = cDelay.to_string();
        std::reverse(cSelect.begin(), cSelect.end());
        std::bitset<5> cTestPulseDelay(cSelect);
        uint8_t        cRegValue = (cGroup | (static_cast<uint8_t>(cTestPulseDelay.to_ulong()) << 3));
472
473
        // LOG(DEBUG) << BOLDBLUE << "Setting test pulse delay for goup [rev.] " << std::bitset<3>(cGroup) << " to " << +dacValue << " --  register to  0x" << std::bitset<8>(+cRegValue) << std::dec
        //            << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
474
475
476
477
478
479
480
481
482
483
484
485
        return WriteChipSingleReg(pCbc, "TestPulseDel&ChanGroup", cRegValue, pVerifLoop);
    }
    else if(dacName == "TestPulseGroup")
    {
        uint8_t cValue = pCbc->getReg("TestPulseDel&ChanGroup");
        uint8_t cDelay = cValue & 0xF8;
        // groupId is reversed in this register
        std::bitset<3> cGroup  = dacValue;
        std::string    cSelect = cGroup.to_string();
        std::reverse(cSelect.begin(), cSelect.end());
        std::bitset<3> cTestPulseGroup(cSelect);
        uint8_t        cRegValue = (cDelay | (static_cast<uint8_t>(cTestPulseGroup.to_ulong())));
486
487
        // LOG(DEBUG) << BOLDBLUE << "Setting test pulse register on CBC" << +pCbc->getId() << " to select group " << +dacValue << " --  register to  0x" << std::bitset<8>(+cRegValue) << std::dec
        //            << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
488
489
490
491
492
493
        return WriteChipSingleReg(pCbc, "TestPulseDel&ChanGroup", cRegValue, pVerifLoop);
    }
    else if(dacName == "AmuxOutput")
    {
        uint8_t cValue    = pCbc->getReg("MiscTestPulseCtrl&AnalogMux");
        uint8_t cRegValue = (cValue & 0xE0) | dacValue;
494
        LOG(DEBUG) << BOLDBLUE << "Setting AmuxOutput on Chip" << +pCbc->getId() << " to " << +dacValue << " - register set to : 0x" << std::hex << +cRegValue << std::dec << RESET;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
495
496
497
        bool cSuccess = WriteChipSingleReg(pCbc, "MiscTestPulseCtrl&AnalogMux", cRegValue, pVerifLoop);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        return cSuccess;
Fabio Ravera's avatar
Fabio Ravera committed
498
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
499
    else if(dacName == "TestPulse" || dacName == "InjectedCharge")
Fabio Ravera's avatar
Fabio Ravera committed
500
501
502
503
504
505
506
507
508
    {
        uint8_t cValue    = pCbc->getReg("MiscTestPulseCtrl&AnalogMux");
        uint8_t cRegValue = (cValue & 0xBF) | (dacValue << 6);
        return WriteChipSingleReg(pCbc, "MiscTestPulseCtrl&AnalogMux", cRegValue, pVerifLoop);
    }
    else if(dacName == "HitOr")
    {
        uint8_t cValue    = pCbc->getReg("40MhzClk&Or254");
        uint8_t cRegValue = (cValue & 0xBf) | (dacValue << 6);
509
510
        // LOG(DEBUG) << BOLDBLUE << "Setting HITOr on Chip" << +pCbc->getId() << " from 0x" << std::hex << +cValue << std::dec << " to " << +dacValue << " - register set to : 0x" << std::hex
        //            << +cRegValue << std::dec << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
511
512
513
        return WriteChipSingleReg(pCbc, "40MhzClk&Or254", cRegValue, pVerifLoop);
    }
    else if(dacName == "DLL")
514
    {
Fabio Ravera's avatar
Fabio Ravera committed
515
516
517
518
519
520
521
        uint8_t cOriginalValue = pCbc->getReg("40MhzClk&Or254");
        // dll is reversed in this register
        std::bitset<5> cDelay  = dacValue;
        std::string    cSelect = cDelay.to_string();
        std::reverse(cSelect.begin(), cSelect.end());
        std::bitset<5> cClockDelay(cSelect);
        uint8_t        cNewRegValue = ((cOriginalValue & 0xE0) | static_cast<uint8_t>(cClockDelay.to_ulong()));
acarvalh's avatar
acarvalh committed
522
523
        // LOG(DEBUG) << BOLDBLUE << "Setting clock delay on Chip" << +pCbc->getId() << " to " << std::bitset<5>(+dacValue) << " - register set to : 0x" << std::hex << +cNewRegValue << std::dec <<
        // RESET;
Fabio Ravera's avatar
Fabio Ravera committed
524
525
526
527
528
529
530
531
532
533
534
535
        return WriteChipSingleReg(pCbc, "40MhzClk&Or254", cNewRegValue, pVerifLoop);
    }
    else if(dacName == "PtCut")
    {
        uint8_t cValue    = pCbc->getReg("Pipe&StubInpSel&Ptwidth");
        uint8_t cRegValue = (cValue & 0xF0) | dacValue;
        return WriteChipSingleReg(pCbc, "Pipe&StubInpSel&Ptwidth", cRegValue, pVerifLoop);
    }
    else if(dacName == "EnableSLVS")
    {
        uint8_t cValue    = pCbc->getReg("HIP&TestMode");
        uint8_t cRegValue = (cValue & 0xFE) | !dacValue;
536
537
538
539
        // if(dacValue == 1)
        //     LOG(DEBUG) << BOLDBLUE << "Enabling SLVS output on CBCs by setting register to " << std::bitset<8>(cRegValue) << RESET;
        // else
        //     LOG(DEBUG) << BOLDBLUE << "Disabling SLVS output on CBCs by setting register to " << std::bitset<8>(cRegValue) << RESET;
Fabio Ravera's avatar
Fabio Ravera committed
540
541
542
543
544
545
546
547
548
549
550
        return WriteChipSingleReg(pCbc, "HIP&TestMode", cRegValue, pVerifLoop);
    }
    else
    {
        if(dacValue > 255)
            LOG(ERROR) << "Error, DAC " << dacName << " for CBC3 can only be 8 bit max (255)!";
        else
            return WriteChipSingleReg(pCbc, dacName, dacValue, pVerifLoop);
    }
    return false;
}
551
552
bool CbcInterface::ConfigurePage(Chip* pCbc, uint8_t pPage, bool pVerifLoop)
{
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
553
554
555
556
557
558
559
    // only written for optical .. electrical readout the fw takes care of this
    bool cSuccess = !lpGBTFound();
    if(cSuccess) return cSuccess;

    // address in map depends on board id, hybrid id, chip id
    uint32_t cAddress = (pCbc->getBeBoardId() << 16) | (pCbc->getHybridId() << 8) | pCbc->getId();
    auto     cIter    = fPageMap.find(cAddress);
560
    bool     cMapWasEmpty = false;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
561
562
    if(cIter == fPageMap.end())
    {
563
        uint8_t cDefaultPage = ReadChipReg(pCbc,"Page"); 
564
        LOG (INFO) << BOLDMAGENTA << "Default page on CBC" << +pCbc->getId() << " on hybrid " << +pCbc->getHybridId() << " is " << +cDefaultPage << RESET;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
565
        fPageMap.insert(std::make_pair(cAddress, cDefaultPage));
566
        cMapWasEmpty=true;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
567
568
569
570
571
    }
    cIter         = fPageMap.find(cAddress);
    uint8_t cPage = cIter->second;
    cSuccess      = (cPage == pPage);
    // don't need to change page
572
573
574
575
576
    LOG (DEBUG) << BOLDBLUE << "\t...No need to switch page on CBC#" << +pCbc->getId() << " on hybrid " << +pCbc->getHybridId()
        << " current page " <<+cPage
        << " page to write to is " << +pPage
        << RESET;
    if(cSuccess && !cMapWasEmpty ) return true;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
577
578

    // switch page
579
580
581
582
    LOG (DEBUG) << BOLDBLUE << "Switching page on CBC#" << +pCbc->getId() << " on hybrid " << +pCbc->getHybridId()
        << " from page " <<+cPage
        << " to page " << +pPage
        << RESET;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
583
584
585
    ChipRegItem cPageReg  = pCbc->getRegItem("FeCtrl&TrgLat2");
    uint8_t     cRegValue = (cPageReg.fValue & 0x7F) | (pPage << 7);
    // LOG (INFO) << BOLDBLUE << "\t...Current page is " << cPage << " want to write to page " << +pPage << " need to update page register on the CBC" << RESET;
586
587
    // update page in map
    cIter->second = pPage;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
588
    // write to page register in the CBC
589
    cSuccess = fBoardFW->WriteFERegister(pCbc, cPageReg.fAddress, cRegValue, pVerifLoop);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
590
591
592
    // return false if this didn't work
    if(!cSuccess) return cSuccess;
    // update register value in map
593
    pCbc->setReg("FeCtrl&TrgLat2", cRegValue);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
594
    return cSuccess;
595
}
Fabio Ravera's avatar
Fabio Ravera committed
596
597
bool CbcInterface::WriteChipSingleReg(Chip* pCbc, const std::string& pRegNode, uint16_t pValue, bool pVerifLoop)
{
598
599
600
    // first, identify the correct BeBoardFWInterface
    setBoard(pCbc->getBeBoardId());
    bool cSuccess = false;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
601
    bool cFound   = pCbc->getRegMap().find(pRegNode) != pCbc->getRegMap().end();
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
602
603
604
605
606
607
608
609
610
611
    if(pRegNode.find("BandgapFuse") != std::string::npos)
    {
        LOG(ERROR) << "Cbc register  " << pRegNode << " is READ ONLY." << RESET;
        return cSuccess;
    }
    if(pValue > 0xFF)
    {
        LOG(ERROR) << "Cbc register are 8 bits, impossible to write " << pValue << " on registed " << pRegNode;
        return cSuccess;
    }
612
613
    if( !cFound ) return cFound; 
    ChipRegItem cRegItem = pCbc->getRegMap().find(pRegNode)->second; 
614
    if( fTrackRegisters ) { LOG (DEBUG) << BOLDYELLOW << "CbcInterface::WriteChipSingleReg updating " << pRegNode << RESET; UpdateModifiedRegMap(pCbc,  cRegItem.fAddress, cRegItem.fPage); }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
615
    cRegItem.fValue = pValue & 0xFF;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
616
    if(!lpGBTFound())
617
618
619
    {
        // vector for transaction
        std::vector<uint32_t> cVec;
620

621
        // encode the reg specific to the FW, pVerifLoop decides if it should be read back, true means to write it
622
        fBoardFW->EncodeReg(cRegItem, pCbc, cVec, pVerifLoop, true);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
623
        // fBoardFW->EncodeReg(cRegItem, pCbc->getHybridId(), pCbc->getId(), cVec, pVerifLoop, true);
624
625
626
        // write the registers, the answer will be in the same cVec
        // the number of times the write operation has been attempted is given by cWriteAttempts
        uint8_t cWriteAttempts = 0;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
627
        cSuccess               = fBoardFW->WriteChipBlockReg(cVec, cWriteAttempts, pVerifLoop);
628
629
630
    }
    else
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
631
632
633
634
        cSuccess = ConfigurePage(pCbc, cRegItem.fPage, pVerifLoop);
        if(!cSuccess) return cSuccess;
        // read only  register
        if(pRegNode.find("ChipIDFuse") != std::string::npos) { pVerifLoop = false; }
635
        cSuccess = fBoardFW->WriteFERegister(pCbc, cRegItem.fAddress, pValue, pVerifLoop);
636
    }
Fabio Ravera's avatar
Fabio Ravera committed
637
    // update the HWDescription object
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
638
639
640
641
642
    if(cSuccess)
    {
        // LOG (INFO) << BOLDMAGENTA << "CbcInterface::WriteChipSingleReg written 0x"
        //     << std::hex << +pValue << std::dec
        //     << " to register " << pRegNode
643
644
645
        //     << RESET;
        pCbc->setReg(pRegNode, pValue);
    }
Fabio Ravera's avatar
Fabio Ravera committed
646
647
648
649
#ifdef COUNT_FLAG
    fRegisterCount++;
    fTransactionCount++;
#endif
650

Fabio Ravera's avatar
Fabio Ravera committed
651
652
    return cSuccess;
}
653
654
655
656
uint8_t CbcInterface::GetLastPage(Chip* pCbc)
{
    uint32_t cAddress = (pCbc->getBeBoardId() << 16) | (pCbc->getHybridId() << 8) | pCbc->getId();
    auto     cIter    = fPageMap.find(cAddress);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
657
658
659
660
    if(cIter == fPageMap.end())
        return 6;
    else
        return cIter->second;
661
}
Fabio Ravera's avatar
Fabio Ravera committed
662
663
bool CbcInterface::WriteChipMultReg(Chip* pCbc, const std::vector<std::pair<std::string, uint16_t>>& pVecReq, bool pVerifLoop)
{
664
    // remember to sort by page . that is helpful for speeding things up later
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
665
666
667
668
669
670
    std::vector<std::pair<std::string, ChipRegItem>> cRegItems;
    struct
    {
        bool operator()(std::pair<std::string, ChipRegItem> a, std::pair<std::string, ChipRegItem> b) const { return a.second.fPage < b.second.fPage; }
    } customLessForPage;
    struct
671
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
672
673
674
675
        bool operator()(std::pair<std::string, ChipRegItem> a, std::pair<std::string, ChipRegItem> b) const { return a.second.fPage > b.second.fPage; }
    } customGreaterForPage;
    for(auto& cReg: pVecReq)
    {
676
        if( pCbc->getRegMap().find(cReg.first) == pCbc->getRegMap().end() ) continue;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
677
        if(cReg.first.find("BandgapFuse") != std::string::npos) continue;
678
        if(cReg.first.find("ChipIDFuse") != std::string::npos) continue;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
679
680
681

        ChipRegItem cRegister = pCbc->getRegItem(cReg.first);
        cRegister.fValue      = cReg.second;
682
683
684
685
686
687
        if(cRegister.fValue > 0xFF)
        {
            LOG(ERROR) << "Cbc register are 8 bits, impossible to write " << cRegister.fValue << " on register " << cReg.first;
            continue;
        }
            
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
688
689
690
691
692
693
694
        cRegItems.push_back(std::make_pair(cReg.first, cRegister));
    }
    // address in map depends on board id, hybrid id, chip id
    uint32_t cAddress = (pCbc->getBeBoardId() << 16) | (pCbc->getHybridId() << 8) | pCbc->getId();
    auto     cIter    = fPageMap.find(cAddress);
    if(cIter == fPageMap.end())
    {
695
696
        uint8_t cDefaultPage = ReadChipReg(pCbc,"Page"); 
        LOG (INFO) << BOLDMAGENTA << "Default page on CBC" << +pCbc->getId() << " on hybrid " << +pCbc->getHybridId() << " is " << +cDefaultPage << RESET;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
697
698
699
700
701
702
        fPageMap.insert(std::make_pair(cAddress, cDefaultPage));
    }
    cIter         = fPageMap.find(cAddress);
    uint8_t cPage = cIter->second;
    if(cPage == 1) std::sort(cRegItems.begin(), cRegItems.end(), customGreaterForPage); // all to page1 then page 0
    if(cPage == 0) std::sort(cRegItems.begin(), cRegItems.end(), customLessForPage);    // all to page0 then page 1
acarvalh's avatar
acarvalh committed
703

Fabio Ravera's avatar
Fabio Ravera committed
704
705
    // first, identify the correct BeBoardFWInterface
    setBoard(pCbc->getBeBoardId());
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
706
707
    bool cSuccess = false;
    if(!lpGBTFound())
Fabio Ravera's avatar
Fabio Ravera committed
708
    {
709
        // Deal with the ChipRegItems and encode them
710
        std::vector<uint32_t> cVec;
711
        for(const auto& cRegItem: cRegItems)
712
        {
713
            // update list of modified registers 
714
            if( fTrackRegisters ) { LOG (DEBUG) << BOLDYELLOW << "CbcInterface::WriteChipMultReg updating " << cRegItem.first << RESET; UpdateModifiedRegMap(pCbc,  cRegItem.second.fAddress, cRegItem.second.fPage); }
715
            fBoardFW->EncodeReg(cRegItem.second, pCbc, cVec, pVerifLoop, true);
716
717
718
            #ifdef COUNT_FLAG
                fRegisterCount++;
            #endif
719
        }
720

721
722
723
        // write the registers, the answer will be in the same cVec
        // the number of times the write operation has been attempted is given by cWriteAttempts
        uint8_t cWriteAttempts = 0;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
724
725
726
727
728
729
        if(cVec.size() == 0) return true;

        cSuccess = fBoardFW->WriteChipBlockReg(cVec, cWriteAttempts, pVerifLoop);
#ifdef COUNT_FLAG
        fTransactionCount++;
#endif
730
731
732
        // if the transaction is successfull, update the HWDescription object
        if(cSuccess)
        {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
733
            for(const auto& cRegItem: cRegItems) { pCbc->setReg(cRegItem.first, cRegItem.second.fValue); }
734
735
736
        }
    }
    else
Fabio Ravera's avatar
Fabio Ravera committed
737
    {
738
        for(const auto& cRegItem: cRegItems)
739
        {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
740
741
            bool cRegWriteSuccess = this->WriteChipSingleReg(pCbc, cRegItem.first, cRegItem.second.fValue, pVerifLoop);
            if(!cRegWriteSuccess) LOG(INFO) << BOLDRED << "Failed to write to " << cRegItem.first << RESET;
742
            cSuccess = cSuccess && cRegWriteSuccess;
743
        }
Fabio Ravera's avatar
Fabio Ravera committed
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
    }
    return cSuccess;
}
bool CbcInterface::WriteChipAllLocalReg(ReadoutChip* pCbc, const std::string& dacName, ChipContainer& localRegValues, bool pVerifLoop)
{
    setBoard(pCbc->getBeBoardId());
    assert(localRegValues.size() == pCbc->getNumberOfChannels());
    std::string dacTemplate;
    bool        isMask = false;

    if(dacName == "ChannelOffset")
        dacTemplate = "Channel%03d";
    else if(dacName == "Mask")
        isMask = true;
    else
        LOG(ERROR) << "Error, DAC " << dacName << " is not a Local DAC";

    std::vector<std::pair<std::string, uint16_t>> cRegVec;
    // std::vector<uint32_t> listOfChannelToUnMask;
    ChannelGroup<NCHANNELS, 1> channelToEnable;

    std::vector<uint32_t> cVec;
    cVec.clear();
    for(uint8_t iChannel = 0; iChannel < pCbc->getNumberOfChannels(); ++iChannel)
    {
        if(isMask)
770
        {
Fabio Ravera's avatar
Fabio Ravera committed
771
            if(localRegValues.getChannel<uint16_t>(iChannel))
772
            {
Fabio Ravera's avatar
Fabio Ravera committed
773
774
                channelToEnable.enableChannel(iChannel);
                // listOfChannelToUnMask.emplace_back(iChannel);
775
776
            }
        }
777
778
        else
        {
Fabio Ravera's avatar
Fabio Ravera committed
779
780
            char dacName1[20];
            sprintf(dacName1, dacTemplate.c_str(), iChannel + 1);
781
            // fBoardFW->EncodeReg ( cRegItem, pCbc->getHybridId(), pCbc->getId(), cVec, pVerifLoop, true );
782
            // #ifdef COUNT_FLAG
Fabio Ravera's avatar
Fabio Ravera committed
783
            //     fRegisterCount++;
784
            // #endif
Fabio Ravera's avatar
Fabio Ravera committed
785
            cRegVec.emplace_back(dacName1, localRegValues.getChannel<uint16_t>(iChannel));
786
787
        }
    }
788

Fabio Ravera's avatar
Fabio Ravera committed
789
    if(isMask) { return maskChannelsGroup(pCbc, &channelToEnable, pVerifLoop); }
Fabio Ravera's avatar
Fabio Ravera committed
790
    else
791
    {
Fabio Ravera's avatar
Fabio Ravera committed
792
793
794
795
796
797
798
799
800
        // uint8_t cWriteAttempts = 0 ;
        // bool cSuccess = fBoardFW->WriteChipBlockReg ( cVec, cWriteAttempts, pVerifLoop);
        // #ifdef COUNT_FLAG
        //     fTransactionCount++;
        // #endif
        // return cSuccess;
        return WriteChipMultReg(pCbc, cRegVec, pVerifLoop);
    }
}
801
802
803
804
uint8_t CbcInterface::ReadChipSingleReg(Chip* pCbc, const std::string& pRegNode)
{
    setBoard(pCbc->getBeBoardId());
    ChipRegItem cRegItem = pCbc->getRegItem(pRegNode);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
805
806
    uint8_t     cValue   = 0x00;
    if(!lpGBTFound())
807
808
    {
        std::vector<uint32_t> cVecReq;
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
809
810
        fBoardFW->EncodeReg(cRegItem, pCbc, cVecReq, true, false);
        // fBoardFW->EncodeReg( cRegItem,  pCbc->getHybridId(), pCbc->getId(), cVecReq, true, false);
811
        fBoardFW->ReadChipBlockReg(cVecReq);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
812
813
814
        bool    cRead;
        uint8_t cCbcId;
        bool    cFailed = false;
815
        fBoardFW->DecodeReg(cRegItem, cCbcId, cVecReq[0], cRead, cFailed);
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
816
        cValue = cRegItem.fValue;
817
818
819
    }
    else
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
820
        bool cVerifLoop = true;
821
        bool cSuccess = ( pRegNode == "FeCtrl&TrgLat2" ) ? true : ConfigurePage(pCbc, cRegItem.fPage, cVerifLoop);
822
        if(cSuccess) cValue = fBoardFW->ReadFERegister(pCbc, cRegItem.fAddress);
823
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
824
825
    pCbc->setReg(pRegNode, cRegItem.fValue);

826
827
    return cValue;
}
Fabio Ravera's avatar
Fabio Ravera committed
828
829
uint16_t CbcInterface::ReadChipReg(Chip* pCbc, const std::string& pRegNode)
{
Fabio Ravera's avatar
Fabio Ravera committed
830
    std::lock_guard<std::mutex> theGuard(fMutex);
831
    ChipRegItem                 cRegItem;
Fabio Ravera's avatar
Fabio Ravera committed
832
833
    setBoard(pCbc->getBeBoardId());
    std::vector<uint32_t> cVecReq;
834
    if(pRegNode == "VCth" || pRegNode == "Threshold")
Fabio Ravera's avatar
Fabio Ravera committed
835
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
836
837
        uint8_t  cReg0      = ReadChipSingleReg(pCbc, "VCth1");
        uint8_t  cReg1      = ReadChipSingleReg(pCbc, "VCth2");
Fabio Ravera's avatar
Fabio Ravera committed
838
839
840
        uint16_t cThreshold = ((cReg1 & 0x3) << 8) | cReg0;
        return cThreshold;
    }
841
842
    else if(pRegNode == "Page")
    {
843
        auto cValue = ReadChipSingleReg(pCbc, "FeCtrl&TrgLat2");
844
        ChipRegMask cMask;  cMask.fBitShift=7; cMask.fNbits=1;
845
846
847
        auto cPage = pCbc->getRegBits( "FeCtrl&TrgLat2",cMask );
        LOG (DEBUG) << BOLDMAGENTA << "Page register set to 0x" << std::hex << +cValue << std::dec << " page is " << +cPage << RESET;
        return cPage;
848
    }
Fabio Ravera's avatar
Fabio Ravera committed
849
850
    else if(pRegNode == "HitLogic")
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
851
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "Pipe&StubInpSel&Ptwidth");
852
        return (cRegValue & 0xC0) >> 6;
Fabio Ravera's avatar
Fabio Ravera committed
853
854
855
    }
    else if(pRegNode == "StubLogic")
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
856
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "Pipe&StubInpSel&Ptwidth");
857
        return (cRegValue & 0x30) >> 4;
Fabio Ravera's avatar
Fabio Ravera committed
858
859
860
    }
    else if(pRegNode == "HitOr")
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
861
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "Pipe&StubInpSel&Ptwidth");
862
        return (cRegValue & 0x40) >> 6;
Fabio Ravera's avatar
Fabio Ravera committed
863
864
865
    }
    else if(pRegNode == "LayerSwap")
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
866
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "LayerSwap&CluWidth");
867
        return (cRegValue & 0x08) >> 3;
Fabio Ravera's avatar
Fabio Ravera committed
868
869
870
    }
    else if(pRegNode == "PtCut")
    {
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
871
        uint8_t cRegValue = ReadChipSingleReg(pCbc, "Pipe&StubInpSel&Ptwidth");
872
        return (cRegValue & 0x0F);
Fabio Ravera's avatar
Fabio Ravera committed
873
    }
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
874
    else if(pRegNode == "ChipId")
Sarah Seif El Nasr's avatar
Sarah Seif El Nasr committed
875
876
877
    {
        return ReadCbcIDeFuse(pCbc);
    }
878
879
    else if(pRegNode == "TriggerLatency")
    {
xtaldaq's avatar
xtaldaq committed
880
881
882
883
        auto     cRegValueFirst  = ReadChipSingleReg(pCbc, "FeCtrl&TrgLat2");
        auto     cRegValueSecond = ReadChipSingleReg(pCbc, "TriggerLatency1");
        uint16_t cLatency        = ((cRegValueFirst & 0x1) << 8) | cRegValueSecond;
        return cLatency;
884
    }