EventLoaderATLASpix.cpp 24.2 KB
Newer Older
1
#include "EventLoaderATLASpix.h"
2
3
4
5
6
#include <regex>

using namespace corryvreckan;
using namespace std;

7
8
EventLoaderATLASpix::EventLoaderATLASpix(Configuration config, std::shared_ptr<Detector> detector)
    : Module(std::move(config), detector), m_detector(detector) {
9
10
11
12

    m_timewalkCorrectionFactors = m_config.getArray<double>("timewalkCorrectionFactors", std::vector<double>());

    m_inputDirectory = m_config.get<std::string>("inputDirectory");
13
14
    m_calibrationFile = m_config.get<std::string>("calibrationFile", std::string());

15
    m_clockCycle = m_config.get<double>("clockCycle", static_cast<double>(Units::convert(6.25, "ns")));
16
17
18

    // Allow reading of legacy data format using the Karlsruhe readout system:
    m_legacyFormat = m_config.get<bool>("legacyFormat", false);
19

20
    m_startTime = m_config.get<double>("startTime", 0.);
21
    m_toaMode = m_config.get<bool>("toaMode", false);
22
23
24
25
26
27

    // m_clkdivendM = m_config.get<int>("clkdivend", 0.) + 1;
    m_clkdivend2M = m_config.get<int>("clkdivend2", 0.) + 1;

    // ts1Range = 0x800 * m_clkdivendM;
    ts2Range = 0x40 * m_clkdivend2M;
28
}
29

30
uint32_t EventLoaderATLASpix::gray_decode(uint32_t gray) {
31
32
33
34
35
    uint32_t bin = gray;
    while(gray >>= 1) {
        bin ^= gray;
    }
    return bin;
36
}
37

38
void EventLoaderATLASpix::initialise() {
39

40
    uint32_t datain;
41

42
43
    m_detectorBusy = false;

Tomas Vanat's avatar
Tomas Vanat committed
44
45
    // File structure is RunX/data.bin
    // Assume that the ATLASpix is the DUT (if running this algorithm)
46

47
    // Open the root directory
48
    DIR* directory = opendir(m_inputDirectory.c_str());
49
    if(directory == nullptr) {
50
        LOG(ERROR) << "Directory " << m_inputDirectory << " does not exist";
51
52
53
54
55
        return;
    }
    dirent* entry;

    // Read the entries in the folder
56
    while((entry = readdir(directory))) {
57
        // Check for the data file
58
        string filename = m_inputDirectory + "/" + entry->d_name;
59
        if(filename.find("data.bin") != string::npos) {
60
61
62
63
64
            m_filename = filename;
        }
    }

    // If no data was loaded, give a warning
65
    if(m_filename.length() == 0) {
66
        LOG(WARNING) << "No data file was found for ATLASpix in " << m_inputDirectory;
67
    } else {
68
        LOG(STATUS) << "Opened data file for ATLASpix: (dbg)" << m_filename;
69
    }
70

71
72
73
74
75
    // Open the binary data file for later
    m_file.open(m_filename.c_str(), ios::in | ios::binary);
    LOG(DEBUG) << "Opening file " << m_filename;

    // fast forward file to T0 event
76
    old_fpga_ts = 0;
77
    while(1) {
78
        m_file.read(reinterpret_cast<char*>(&datain), 4);
79
80
81
82
        if(m_file.eof()) {
            m_file.clear();
            m_file.seekg(ios::beg);
            LOG(WARNING) << "No T0 event was found in file " << m_filename
83
                         << ". Rewinding the file to the beginning and loading all events.";
84
85
86
87
88
            break;
        } else if((datain & 0xFF000000) == 0x70000000) {
            LOG(STATUS) << "Found T0 event at position " << m_file.tellg() << ". Skipping all data before this event.";
            oldpos = m_file.tellg();
            unsigned long ts3 = datain & 0x00FFFFFF;
89
90
            old_fpga_ts = (static_cast<unsigned long long>(ts3));
            int checkpos = static_cast<int>(oldpos) - 8;
91
            while(checkpos >= 0) {
92
93
                std::streampos tmppos = checkpos;
                m_file.seekg(tmppos);
94
                m_file.read(reinterpret_cast<char*>(&datain), 4);
95
96
97
                unsigned int message_type = (datain >> 24);
                // TS2
                if(message_type == 0b00100000) {
98
                    old_fpga_ts = ((static_cast<unsigned long long>(datain & 0x00FFFFFF)) << 24) | ts3;
99
                    LOG(DEBUG) << "Set old_fpga_ts to " << old_fpga_ts;
100
101
102
103
104
105
106
107
108
                    break;
                }
                // TS3
                else if(message_type == 0b01100000) {
                    if(ts3 != (datain & 0x00FFFFFF)) {
                        LOG(WARNING) << "Last FPGA timestamp " << (datain & 0x00FFFFFF) << " does not match to T0 event "
                                     << ts3 << ". Some timestamps at the begining might be corrupted.";
                    }
                }
109
                checkpos = static_cast<int>(tmppos) - 4;
110
111
112
113
114
            }
            m_file.seekg(oldpos);
            break;
        }
    }
115

116
    // Make histograms for debugging
117
118
    hHitMap = new TH2F("hitMap",
                       "hitMap",
119
                       m_detector->nPixels().X(),
120
                       0,
121
122
                       m_detector->nPixels().X(),
                       m_detector->nPixels().Y(),
123
                       0,
124
                       m_detector->nPixels().Y());
Jens Kroeger's avatar
Jens Kroeger committed
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

    hHitMap_highTot = new TH2F("hitMap_highTot",
                               "hitMap_hithTot",
                               m_detector->nPixels().X(),
                               0,
                               m_detector->nPixels().X(),
                               m_detector->nPixels().Y(),
                               0,
                               m_detector->nPixels().Y());

    hHitMap_totWeighted = new TProfile2D("hHitMap_totWeighted",
                                         "hHitMap_totWeighted",
                                         m_detector->nPixels().X(),
                                         0,
                                         m_detector->nPixels().X(),
                                         m_detector->nPixels().Y(),
                                         0,
                                         m_detector->nPixels().Y(),
                                         0,
                                         100);

146
147
    hPixelToT = new TH1F("pixelToT", "pixelToT", 64, 0, 64);
    hPixelToT->GetXaxis()->SetTitle("ToT in TS2 clock cycles.");
148
149
    hPixelToTCal = new TH1F("pixelToTCal", "pixelToT", 100, 0, 100);
    hPixelToA = new TH1F("pixelToA", "pixelToA", 100, 0, 100);
150
    hPixelsPerFrame = new TH1F("pixelsPerFrame", "pixelsPerFrame", 200, 0, 200);
151
    hPixelsOverTime = new TH1F("pixelsOverTime", "pixelsOverTime", 2e6, 0, 2e6);
152

153
    // Read calibration:
154
    m_calibrationFactors.resize(static_cast<size_t>(m_detector->nPixels().X() * m_detector->nPixels().Y()), 1.0);
155
156
157
158
159
160
161
162
163
    if(!m_calibrationFile.empty()) {
        std::ifstream calibration(m_calibrationFile);
        std::string line;
        std::getline(calibration, line);

        int col, row;
        double calibfactor;
        while(getline(calibration, line)) {
            std::istringstream(line) >> col >> row >> calibfactor;
164
            m_calibrationFactors.at(static_cast<size_t>(row * 25 + col)) = calibfactor;
165
166
        }
        calibration.close();
167
168
    }

169
    LOG(INFO) << "Timewalk correction factors: ";
170
171
172
173
    for(auto& ts : m_timewalkCorrectionFactors) {
        LOG(INFO) << ts;
    }

Jens Kroeger's avatar
Jens Kroeger committed
174
    LOG(INFO) << "Using clock cycle length of " << m_clockCycle << " ns." << std::endl;
175

176
177
    m_oldtoa = 0;
    m_overflowcounter = 0;
178
179
}

180
StatusCode EventLoaderATLASpix::run(std::shared_ptr<Clipboard> clipboard) {
181

182
183
184
185
186
    // Check if event frame is defined:
    if(!clipboard->has_persistent("eventStart") || !clipboard->has_persistent("eventEnd")) {
        throw ModuleError("Event not defined. Add Metronome module or Event reader defining the event.");
    }

187
188
189
    // If have reached the end of file, close it and exit program running
    if(m_file.eof()) {
        m_file.close();
190
        LOG(DEBUG) << "Returning <Failure> status, ATLASPix data file reached the end.";
191
        return StatusCode::Failure;
192
193
    }

194
195
    double start_time = clipboard->get_persistent("eventStart");
    double end_time = clipboard->get_persistent("eventEnd");
196
    bool busy_at_start = m_detectorBusy;
197
198

    // Read pixel data
199
    Pixels* pixels = (m_legacyFormat ? read_legacy_data(start_time, end_time) : read_caribou_data(start_time, end_time));
200

201
202
203
204
205
    if(busy_at_start || m_detectorBusy) {
        LOG(DEBUG) << "Returning <DeadTime> status, ATLASPix is BUSY.";
        return StatusCode::DeadTime;
    }

206
207
    for(auto px : (*pixels)) {
        hHitMap->Fill(px->column(), px->row());
Jens Kroeger's avatar
Jens Kroeger committed
208
209
210
211
        if(px->tot() > 40) {
            hHitMap_highTot->Fill(px->column(), px->row());
        }
        hHitMap_totWeighted->Fill(px->column(), px->row(), px->tot());
212
213
214
        hPixelToT->Fill(px->tot());
        hPixelToTCal->Fill(px->charge());
        hPixelToA->Fill(px->timestamp());
215
216

        // Pixels per 100us:
217
        hPixelsOverTime->Fill(static_cast<double>(Units::convert(px->timestamp(), "ms")));
218
219
    }

220
    // Fill histograms
221
    hPixelsPerFrame->Fill(static_cast<double>(pixels->size()));
222

223
224
    // Put the data on the clipboard
    if(!pixels->empty()) {
225
        clipboard->put(m_detector->name(), "pixels", reinterpret_cast<Objects*>(pixels));
226
    } else {
Jens Kroeger's avatar
Jens Kroeger committed
227
        delete pixels;
228
        LOG(DEBUG) << "Returning <NoData> status, no hits found.";
229
        return StatusCode::NoData;
230
231
232
    }

    // Return value telling analysis to keep running
233
    LOG(DEBUG) << "Returning <Success> status, hits found in this event window.";
234
    return StatusCode::Success;
235
236
}

237
Pixels* EventLoaderATLASpix::read_caribou_data(double start_time, double end_time) {
238
239
    LOG(DEBUG) << "Searching for events in interval from " << Units::display(start_time, {"s", "us", "ns"}) << " to "
               << Units::display(end_time, {"s", "us", "ns"}) << ", file read position " << m_file.tellg()
240
               << ", old_fpga_ts = " << old_fpga_ts << ".";
241

242
243
244
245
    // Pixel container
    Pixels* pixels = new Pixels();

    // Read file and load data
246
    uint32_t datain;
247
    long long ts_diff; // tmp
248
249

    // Initialize all to 0 for a case that hit data come before timestamp/trigger data
250
251
252
    long long hit_ts = 0;            // 64bit value of a hit timestamp combined from readout and pixel hit timestamp
    unsigned long long atp_ts = 0;   // 16bit value of ATLASpix readout timestamp
    unsigned long long trig_cnt = 0; // 32bit value of trigger counter (in FPGA)
253
254
255
256
257
258
259
    unsigned long long readout_ts =
        old_readout_ts;                       // 64bit value of a readout timestamp combined from FPGA and ATp timestamp
    unsigned long long fpga_ts = old_fpga_ts; // 64bit value of FPGA readout timestamp
    unsigned long long fpga_ts1 = 0;          // tmp [63:48] of FPGA readout timestamp
    unsigned long long fpga_ts2 = 0;          // tmp [47:24] of FPGA readout timestamp
    unsigned long long fpga_ts3 = 0;          // tmp [23:0] of FPGA readout timestamp
    unsigned long long fpga_tsx = 0;          // tmp for FPGA readout timestamp
260
261
    bool new_ts1 = true;
    bool new_ts2 = true;
262
263
264
    bool window_end = false;
    bool keep_pointer_stored = false;
    bool keep_reading = true;
265
266

    // Repeat until input EOF:
267
    while(keep_reading) {
268
        // Read next 4-byte data from file
269
        m_file.read(reinterpret_cast<char*>(&datain), 4);
270
271
272
273
        if(m_file.eof()) {
            LOG(DEBUG) << "EOF...";
            break;
        }
274

275
276
277
278
279
280
        // LOG(DEBUG) << "Found " << (datain & 0x80000000 ? "pixel data" : "header information");

        // Check if current word is a pixel data:
        if(datain & 0x80000000) {
            // Structure: {1'b1, column_addr[5:0], row_addr[8:0], rise_timestamp[9:0], fall_timestamp[5:0]}
            // Extract pixel data
281
            long ts2 = gray_decode((datain)&0x003F);
282
            // long ts2 = gray_decode((datain>>6)&0x003F);
283
            // TS1 counter is by default half speed of TS2. By multiplying with 2 we make it equal.
284
285
            long ts1 = (gray_decode((datain >> 6) & 0x03FF)) << 1;
            // long ts1 = (gray_decode(((datain << 4) & 0x3F0) | ((datain >> 12) & 0xF)))<<1;
286
287
            int row = ((datain >> (6 + 10)) & 0x01FF);
            int col = ((datain >> (6 + 10 + 9)) & 0x003F);
288
289
            // long tot = 0;

290
            ts_diff = ts1 - static_cast<long long>(readout_ts & 0x07FF);
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

            if(ts_diff > 0) {
                // Hit probably came before readout started and meanwhile an OVF of TS1 happened
                if(ts_diff > 0x01FF) {
                    ts_diff -= 0x0800;
                }
                // Hit probably came after readout started and is within range.
                // else {
                //    // OK...
                //}
            } else {
                // Hit probably came after readout started and after OVF of TS1.
                if(ts_diff < (0x01FF - 0x0800)) {
                    ts_diff += 0x0800;
                }
                // Hit probably came before readout started and is within range.
                // else {
                //    // OK...
                //}
            }
311

312
            hit_ts = static_cast<long long>(readout_ts) + ts_diff;
313

314
            // Convert the timestamp to nanoseconds:
315
            double timestamp = m_clockCycle * static_cast<double>(hit_ts);
316

317
            if(timestamp > end_time) {
318
319
                keep_pointer_stored = true;
                LOG(DEBUG) << "Skipping processing event, pixel is after event window ("
320
                           << Units::display(timestamp, {"s", "us", "ns"}) << " > "
321
                           << Units::display(end_time, {"s", "us", "ns"}) << ")";
322
                continue;
323
324
            }

325
326
327
328
329
330
            if(timestamp < start_time) {
                LOG(DEBUG) << "Skipping pixel hit, pixel is before event window ("
                           << Units::display(timestamp, {"s", "us", "ns"}) << " < "
                           << Units::display(start_time, {"s", "us", "ns"}) << ")";
                continue;
            }
331
332
            // this window still contains data in the event window, do not stop processing
            window_end = false;
333
334
335
336
337
338
339
            if(m_detectorBusy && (busy_readout_ts < readout_ts)) {
                LOG(WARNING) << "ATLASPix went BUSY between "
                             << Units::display((m_clockCycle * static_cast<double>(busy_readout_ts)), {"s", "us", "ns"})
                             << " and "
                             << Units::display((m_clockCycle * static_cast<double>(readout_ts)), {"s", "us", "ns"}) << ".";
                m_detectorBusy = false;
            }
340
            data_pixel_++;
341
            // If this pixel is masked, do not save it
342
            if(m_detector->masked(col, row)) {
343
344
345
                continue;
            }

346
            // calculate ToT only when pixel is good for storing (division is time consuming)
347
            int tot = static_cast<int>(ts2 - ((hit_ts % static_cast<long long>(64 * m_clkdivend2M)) / m_clkdivend2M));
348
            if(tot < 0) {
349
                tot += 64;
350
            }
Tomas Vanat's avatar
Tomas Vanat committed
351
            // convert ToT to nanoseconds
352
            // double tot_ns = tot * m_clockCycle;
353
354
355
356
357

            LOG(TRACE) << "HIT: TS1: " << ts1 << "\t0x" << std::hex << ts1 << "\tTS2: " << ts2 << "\t0x" << std::hex << ts2
                       << "\tTS_FULL: " << hit_ts << "\t" << Units::display(timestamp, {"s", "us", "ns"})
                       << "\tTOT: " << tot; // << "\t" << Units::display(tot_ns, {"s", "us", "ns"});

358
            Pixel* pixel = new Pixel(m_detector->name(), row, col, tot, timestamp);
359
            LOG(DEBUG) << "PIXEL:\t" << *pixel;
360
            pixels->push_back(pixel);
361

362
        } else {
363
364
365
366
367
            // data is not hit information
            // if (keep_pointer_stored) then we will go through the data one more time and wee will count that next time.
            if(!keep_pointer_stored) {
                data_header_++;
            }
368

369
370
371
372
373
            // Decode the message content according to 8 MSBits
            unsigned int message_type = (datain >> 24);
            switch(message_type) {
            // Timestamp from ATLASpix [23:0]
            case 0b01000000:
374
375
376
377
378
379
380
381
382
                // the whole previous readout was behind the time window, we can stop processing and return
                if(window_end) {
                    LOG(TRACE) << "Rewinding to file pointer : " << oldpos;
                    m_file.seekg(oldpos);
                    // exit the while loop
                    keep_reading = false;
                    // exit case
                    break;
                }
383
384

                atp_ts = (datain >> 7) & 0x1FFFE;
385
                ts_diff = static_cast<long long>(atp_ts) - static_cast<long long>(fpga_ts & 0x1FFFF);
386
387
388
389
390
391
392
393
394
395

                if(ts_diff > 0) {
                    if(ts_diff > 0x10000) {
                        ts_diff -= 0x20000;
                    }
                } else {
                    if(ts_diff < -0x1000) {
                        ts_diff += 0x20000;
                    }
                }
396
                readout_ts = static_cast<unsigned long long>(static_cast<long long>(fpga_ts) + ts_diff);
397

398
399
400
401
402
403
404
405
406
407
408
                if(!keep_pointer_stored) {
                    // Store this position in the file in case we need to rewind:
                    LOG(TRACE) << "Storing file pointer position: " << m_file.tellg() << " and readout TS: " << readout_ts;
                    oldpos = m_file.tellg();
                    old_readout_ts = readout_ts;
                } else {
                    LOG(TRACE) << "File pointer position already stored for the first event out of the window. Current "
                                  "readout_ts = "
                               << readout_ts;
                }
                // If the readout time is after the window, mark it as a candidate for last readout in the window
409
                if((static_cast<double>(readout_ts) * m_clockCycle) > end_time) {
410
411
                    window_end = true;
                }
412
                break;
413

414
415
416
417
418
419
420
421
            // Trigger counter from FPGA [23:0] (1/4)
            case 0b00010000:
                trig_cnt = datain & 0x00FFFFFF;
                break;

            // Trigger counter from FPGA [31:24] and timestamp from FPGA [63:48] (2/4)
            case 0b00110000:
                trig_cnt |= (datain << 8) & 0xFF000000;
422
                fpga_ts1 = ((static_cast<unsigned long long>(datain) << 48) & 0xFFFF000000000000);
423
424
425
426
427
                new_ts1 = true;
                break;

            // Timestamp from FPGA [47:24] (3/4)
            case 0b00100000:
428
                fpga_tsx = ((static_cast<unsigned long long>(datain) << 24) & 0x0000FFFFFF000000);
429
430
                if((!new_ts1) && (fpga_tsx < fpga_ts2)) {
                    fpga_ts1 += 0x0001000000000000;
431
                    LOG(WARNING) << "Missing TS_FPGA_1, adding one";
432
433
434
435
436
437
438
439
440
441
442
443
                }
                new_ts1 = false;
                new_ts2 = true;
                fpga_ts2 = fpga_tsx;
                break;

            // Timestamp from FPGA [23:0] (4/4)
            case 0b01100000:
                m_identifiers["FPGA_TS"]++;
                fpga_tsx = ((datain)&0xFFFFFF);
                if((!new_ts2) && (fpga_tsx < fpga_ts3)) {
                    fpga_ts2 += 0x0000000001000000;
444
                    LOG(WARNING) << "Missing TS_FPGA_2, adding one";
445
446
447
448
449
                }
                new_ts2 = false;
                fpga_ts3 = fpga_tsx;
                fpga_ts = fpga_ts1 | fpga_ts2 | fpga_ts3;
                break;
450

451
452
453
            // BUSY was asserted due to FIFO_FULL + 24 LSBs of FPGA timestamp when it happened
            case 0b00000010:
                m_identifiers["BUSY_ASSERT"]++;
454
455
                busy_readout_ts = readout_ts;
                m_detectorBusy = true;
456
457
458
459
460
461
462
463
464
465
                break;

            // T0 received
            case 0b01110000:
                LOG(WARNING) << "Another T0 event was found in the data at position " << m_file.tellg();
                break;

            // Empty data - should not happen
            case 0b00000000:
                m_identifiers["EMPTY_DATA"]++;
Tomas Vanat's avatar
Tomas Vanat committed
466
                LOG(DEBUG) << "EMPTY_DATA";
467
468
469
470
471
472
473
474
                break;

            // Other options...
            default:
                // LOG(DEBUG) << "...Other";
                // Unknown message identifier
                if(message_type & 0b11110010) {
                    m_identifiers["UNKNOWN_MESSAGE"]++;
Tomas Vanat's avatar
Tomas Vanat committed
475
                    LOG(DEBUG) << "UNKNOWN_MESSAGE";
476
477
478
479
                } else {
                    // Buffer for chip data overflow (data that came after this word were lost)
                    if((message_type & 0b11110011) == 0b00000001) {
                        m_identifiers["BUFFER_OVERFLOW"]++;
Tomas Vanat's avatar
Tomas Vanat committed
480
                        LOG(DEBUG) << "BUFFER_OVERFLOW";
481
482
483
484
                    }
                    // SERDES lock established (after reset or after lock lost)
                    if((message_type & 0b11111110) == 0b00001000) {
                        m_identifiers["SERDES_LOCK_ESTABLISHED"]++;
Tomas Vanat's avatar
Tomas Vanat committed
485
                        LOG(DEBUG) << "SERDES_LOCK_ESTABLISHED";
486
487
488
489
                    }
                    // SERDES lock lost (data might be nonsense, including up to 2 previous messages)
                    else if((message_type & 0b11111110) == 0b00001100) {
                        m_identifiers["SERDES_LOCK_LOST"]++;
Tomas Vanat's avatar
Tomas Vanat committed
490
                        LOG(DEBUG) << "SERDES_LOCK_LOST";
491
492
493
494
                    }
                    // Unexpected data came from the chip or there was a checksum error.
                    else if((message_type & 0b11111110) == 0b00000100) {
                        m_identifiers["WEIRD_DATA"]++;
Tomas Vanat's avatar
Tomas Vanat committed
495
                        LOG(DEBUG) << "WEIRD_DATA";
496
497
498
499
500
501
502
503
504
505
506
507
508
                    }
                    // Unknown message identifier
                    else {
                        m_identifiers["UNKNOWN_MESSAGE"]++;
                        LOG(WARNING) << "UNKNOWN_MESSAGE";
                    }
                }
                break;
                // End case
            }
        }
    }
    LOG(DEBUG) << "Returning " << pixels->size() << " pixels";
509
510
511
    return pixels;
}

512
Pixels* EventLoaderATLASpix::read_legacy_data(double, double) {
513

514
    // Pixel container
515
516
517
    Pixels* pixels = new Pixels();

    // Read file and load data
518
519
    while(!m_file.eof()) {

520
        int col, row, tot, ts;
521
522
523
524
525
        unsigned long long int toa, TriggerDebugTS, dummy, bincounter;

        m_file >> col >> row >> ts >> tot >> dummy >> dummy >> bincounter >> TriggerDebugTS;

        // If this pixel is masked, do not save it
526
        if(m_detector->masked(col, row)) {
527
528
529
530
531
532
            continue;
        }

        // TOT
        if(tot <= (ts * 2 & 0x3F)) {
            tot = 64 + tot - (ts * 2 & 0x3F);
533
        } else {
534
535
536
537
            tot = tot - (ts * 2 & 0x3F);
        }

        // Apply calibration:
538
539
540
        double cal_tot = tot * m_calibrationFactors.at(static_cast<size_t>(row * 25 + col));
        LOG(TRACE) << "Hit " << row << "\t" << col << ": " << m_calibrationFactors.at(static_cast<size_t>(row * 25 + col))
                   << " * " << tot << " = " << cal_tot;
541
542
543
544

        ts &= 0xFF;
        ts *= 2; // atlaspix timestamp runs at 10MHz, multiply by to to get 20.

545
        if((bincounter & 0x1FF) < static_cast<unsigned long long>(ts)) {
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
            toa = ((bincounter & 0xFFFFFFFFFFFFFE00) - (1 << 9)) | (ts & 0x1FF);
        } else {
            toa = (bincounter & 0xFFFFFFFFFFFFFE00) | (ts & 0x1FF);
        }

        if(((toa + 10000) & 0xFFFFF000) < (m_oldtoa & 0xFFFFF000)) {
            m_overflowcounter++;
            LOG(DEBUG) << "Overflow detected " << m_overflowcounter << " " << (toa & 0xFFFFF000) << " "
                       << (m_oldtoa & 0xFFFFF000);
        } // Atlaspix only! Toa has overflow at 32 bits.

        toa += (0x100000000 * m_overflowcounter);
        m_oldtoa = toa & 0xFFFFFFFF;
        LOG(DEBUG) << "    " << row << "\t" << col << ": " << tot << " " << ts << " " << bincounter << " " << toa << " "
                   << (TriggerDebugTS - toa);

562
        // TriggerDebugTS *= 4096. / 5;              // runs with 200MHz, divide by 5 to scale counter value to 40MHz
563
564
        double toa_timestamp =
            4096. * 2 * static_cast<double>(toa); // runs with 20MHz, multiply by 2 to scale counter value to 40MHz
565
566
567
568
569
570
571

        // Timewalk correction:
        if(m_timewalkCorrectionFactors.size() == 5) {
            double corr = m_timewalkCorrectionFactors.at(0) + m_timewalkCorrectionFactors.at(1) * tot +
                          m_timewalkCorrectionFactors.at(2) * tot * tot +
                          m_timewalkCorrectionFactors.at(3) * tot * tot * tot +
                          m_timewalkCorrectionFactors.at(4) * tot * tot * tot * tot;
572
            toa_timestamp -= corr * 163840000000; //(40000000 * 4096)
573
574
        }

575
        // Convert TOA to nanoseconds:
576
        toa_timestamp /= (4096. * 0.04);
577

578
        Pixel* pixel = new Pixel(m_detector->name(), row, col, tot, toa_timestamp);
579
        pixel->setCharge(cal_tot);
580
        pixels->push_back(pixel);
581
582
    }

583
    return pixels;
584
585
}

586
void EventLoaderATLASpix::finalise() {
587

588
589
590
591
    LOG(INFO) << "Identifier distribution:";
    for(auto id : m_identifiers) {
        LOG(INFO) << "\t" << id.first << ": " << id.second;
    }
592
593

    LOG(INFO) << "Found " << data_pixel_ << " pixel data blocks and " << data_header_ << " header words";
594
}