EventLoaderATLASpix.cpp 23.1 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
    m_timewalkCorrectionFactors = m_config.getArray<double>("timewalk_correction_factors", std::vector<double>());
11

12
    m_inputDirectory = m_config.getPath("input_directory");
Simon Spannagel's avatar
Simon Spannagel committed
13

14
15
    if(m_config.has("calibration_file")) {
        m_calibrationFile = m_config.getPath("calibration_file");
Simon Spannagel's avatar
Simon Spannagel committed
16
    }
17

18
    m_clockCycle = m_config.get<double>("clock_cycle", static_cast<double>(Units::convert(6.25, "ns")));
19
20

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

23
24
    m_startTime = m_config.get<double>("start_time", 0.);
    m_toaMode = m_config.get<bool>("toa_mode", false);
25
26
27
28
29
30

    // 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;
31
}
32

33
uint32_t EventLoaderATLASpix::gray_decode(uint32_t gray) {
34
35
36
37
38
    uint32_t bin = gray;
    while(gray >>= 1) {
        bin ^= gray;
    }
    return bin;
39
}
40

41
void EventLoaderATLASpix::initialise() {
42

43
    uint32_t datain;
44

45
46
    m_detectorBusy = false;

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

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

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

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

74
75
76
77
78
    // 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
79
    old_fpga_ts = 0;
80
    while(1) {
81
        m_file.read(reinterpret_cast<char*>(&datain), 4);
82
83
84
85
        if(m_file.eof()) {
            m_file.clear();
            m_file.seekg(ios::beg);
            LOG(WARNING) << "No T0 event was found in file " << m_filename
86
                         << ". Rewinding the file to the beginning and loading all events.";
87
88
89
90
91
            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;
92
93
            old_fpga_ts = (static_cast<unsigned long long>(ts3));
            int checkpos = static_cast<int>(oldpos) - 8;
94
            while(checkpos >= 0) {
95
96
                std::streampos tmppos = checkpos;
                m_file.seekg(tmppos);
97
                m_file.read(reinterpret_cast<char*>(&datain), 4);
98
99
100
                unsigned int message_type = (datain >> 24);
                // TS2
                if(message_type == 0b00100000) {
101
                    old_fpga_ts = ((static_cast<unsigned long long>(datain & 0x00FFFFFF)) << 24) | ts3;
102
                    LOG(DEBUG) << "Set old_fpga_ts to " << old_fpga_ts;
103
104
105
106
107
108
109
110
111
                    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.";
                    }
                }
112
                checkpos = static_cast<int>(tmppos) - 4;
113
114
115
116
117
            }
            m_file.seekg(oldpos);
            break;
        }
    }
118

119
    // Make histograms for debugging
120
121
    hHitMap = new TH2F("hitMap",
                       "hitMap",
122
                       m_detector->nPixels().X(),
123
                       0,
124
125
                       m_detector->nPixels().X(),
                       m_detector->nPixels().Y(),
126
                       0,
127
                       m_detector->nPixels().Y());
Jens Kroeger's avatar
Jens Kroeger committed
128

129
130
    hPixelToT = new TH1F("pixelToT", "pixelToT", 64, 0, 64);
    hPixelToT->GetXaxis()->SetTitle("ToT in TS2 clock cycles.");
131
132
    hPixelToTCal = new TH1F("pixelToTCal", "pixelToT", 100, 0, 100);
    hPixelToA = new TH1F("pixelToA", "pixelToA", 100, 0, 100);
133
    hPixelsPerFrame = new TH1F("pixelsPerFrame", "pixelsPerFrame", 200, 0, 200);
134
    hPixelsOverTime = new TH1F("pixelsOverTime", "pixelsOverTime", 2e6, 0, 2e6);
135

136
    // Read calibration:
137
    m_calibrationFactors.resize(static_cast<size_t>(m_detector->nPixels().X() * m_detector->nPixels().Y()), 1.0);
138
139
140
141
142
143
144
145
146
    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;
147
            m_calibrationFactors.at(static_cast<size_t>(row * 25 + col)) = calibfactor;
148
149
        }
        calibration.close();
150
151
    }

152
    LOG(INFO) << "Timewalk correction factors: ";
153
154
155
156
    for(auto& ts : m_timewalkCorrectionFactors) {
        LOG(INFO) << ts;
    }

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

159
160
    m_oldtoa = 0;
    m_overflowcounter = 0;
161
162
}

163
StatusCode EventLoaderATLASpix::run(std::shared_ptr<Clipboard> clipboard) {
164

165
166
167
168
169
    // 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.");
    }

170
171
172
    // If have reached the end of file, close it and exit program running
    if(m_file.eof()) {
        m_file.close();
173
        LOG(DEBUG) << "Returning <Failure> status, ATLASPix data file reached the end.";
174
        return StatusCode::Failure;
175
176
    }

177
178
    double start_time = clipboard->get_persistent("eventStart");
    double end_time = clipboard->get_persistent("eventEnd");
179
    bool busy_at_start = m_detectorBusy;
180
181

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

184
185
186
187
188
    if(busy_at_start || m_detectorBusy) {
        LOG(DEBUG) << "Returning <DeadTime> status, ATLASPix is BUSY.";
        return StatusCode::DeadTime;
    }

189
190
191
192
193
    for(auto px : (*pixels)) {
        hHitMap->Fill(px->column(), px->row());
        hPixelToT->Fill(px->tot());
        hPixelToTCal->Fill(px->charge());
        hPixelToA->Fill(px->timestamp());
194
195

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

199
    // Fill histograms
200
    hPixelsPerFrame->Fill(static_cast<double>(pixels->size()));
201

202
203
    // Put the data on the clipboard
    if(!pixels->empty()) {
204
        clipboard->put(m_detector->name(), "pixels", reinterpret_cast<Objects*>(pixels));
205
    } else {
Jens Kroeger's avatar
Jens Kroeger committed
206
        delete pixels;
207
        LOG(DEBUG) << "Returning <NoData> status, no hits found.";
208
        return StatusCode::NoData;
209
210
211
    }

    // Return value telling analysis to keep running
212
    LOG(DEBUG) << "Returning <Success> status, hits found in this event window.";
213
    return StatusCode::Success;
214
215
}

216
Pixels* EventLoaderATLASpix::read_caribou_data(double start_time, double end_time) {
217
218
    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()
219
               << ", old_fpga_ts = " << old_fpga_ts << ".";
220

221
222
223
224
    // Pixel container
    Pixels* pixels = new Pixels();

    // Read file and load data
225
    uint32_t datain;
226
    long long ts_diff; // tmp
227
228

    // Initialize all to 0 for a case that hit data come before timestamp/trigger data
229
230
231
    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)
232
233
234
235
236
237
238
    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
239
240
    bool new_ts1 = true;
    bool new_ts2 = true;
241
242
243
    bool window_end = false;
    bool keep_pointer_stored = false;
    bool keep_reading = true;
244
245

    // Repeat until input EOF:
246
    while(keep_reading) {
247
        // Read next 4-byte data from file
248
        m_file.read(reinterpret_cast<char*>(&datain), 4);
249
250
251
252
        if(m_file.eof()) {
            LOG(DEBUG) << "EOF...";
            break;
        }
253

254
255
256
257
258
259
        // 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
260
            long ts2 = gray_decode((datain)&0x003F);
261
            // long ts2 = gray_decode((datain>>6)&0x003F);
262
            // TS1 counter is by default half speed of TS2. By multiplying with 2 we make it equal.
263
264
            long ts1 = (gray_decode((datain >> 6) & 0x03FF)) << 1;
            // long ts1 = (gray_decode(((datain << 4) & 0x3F0) | ((datain >> 12) & 0xF)))<<1;
265
266
            int row = ((datain >> (6 + 10)) & 0x01FF);
            int col = ((datain >> (6 + 10 + 9)) & 0x003F);
267
268
            // long tot = 0;

269
            ts_diff = ts1 - static_cast<long long>(readout_ts & 0x07FF);
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

            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...
                //}
            }
290

291
            hit_ts = static_cast<long long>(readout_ts) + ts_diff;
292

293
            // Convert the timestamp to nanoseconds:
294
            double timestamp = m_clockCycle * static_cast<double>(hit_ts);
295

296
            if(timestamp > end_time) {
297
298
                keep_pointer_stored = true;
                LOG(DEBUG) << "Skipping processing event, pixel is after event window ("
299
                           << Units::display(timestamp, {"s", "us", "ns"}) << " > "
300
                           << Units::display(end_time, {"s", "us", "ns"}) << ")";
301
                continue;
302
303
            }

304
305
306
307
308
309
            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;
            }
310
311
            // this window still contains data in the event window, do not stop processing
            window_end = false;
312
313
314
315
316
317
318
            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;
            }
319
            data_pixel_++;
320
            // If this pixel is masked, do not save it
321
            if(m_detector->masked(col, row)) {
322
323
324
                continue;
            }

325
            // calculate ToT only when pixel is good for storing (division is time consuming)
326
            int tot = static_cast<int>(ts2 - ((hit_ts % static_cast<long long>(64 * m_clkdivend2M)) / m_clkdivend2M));
327
            if(tot < 0) {
328
                tot += 64;
329
            }
Tomas Vanat's avatar
Tomas Vanat committed
330
            // convert ToT to nanoseconds
331
            // double tot_ns = tot * m_clockCycle;
332
333
334
335
336

            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"});

337
            Pixel* pixel = new Pixel(m_detector->name(), row, col, tot, timestamp);
338
            LOG(DEBUG) << "PIXEL:\t" << *pixel;
339
            pixels->push_back(pixel);
340

341
        } else {
342
343
344
345
346
            // 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_++;
            }
347

348
349
350
351
352
            // Decode the message content according to 8 MSBits
            unsigned int message_type = (datain >> 24);
            switch(message_type) {
            // Timestamp from ATLASpix [23:0]
            case 0b01000000:
353
354
355
356
357
358
359
360
361
                // 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;
                }
362
363

                atp_ts = (datain >> 7) & 0x1FFFE;
364
                ts_diff = static_cast<long long>(atp_ts) - static_cast<long long>(fpga_ts & 0x1FFFF);
365
366
367
368
369
370
371
372
373
374

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

377
378
379
380
381
382
383
384
385
386
387
                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
388
                if((static_cast<double>(readout_ts) * m_clockCycle) > end_time) {
389
390
                    window_end = true;
                }
391
                break;
392

393
394
395
396
397
398
399
400
            // 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;
401
                fpga_ts1 = ((static_cast<unsigned long long>(datain) << 48) & 0xFFFF000000000000);
402
403
404
405
406
                new_ts1 = true;
                break;

            // Timestamp from FPGA [47:24] (3/4)
            case 0b00100000:
407
                fpga_tsx = ((static_cast<unsigned long long>(datain) << 24) & 0x0000FFFFFF000000);
408
409
                if((!new_ts1) && (fpga_tsx < fpga_ts2)) {
                    fpga_ts1 += 0x0001000000000000;
410
                    LOG(WARNING) << "Missing TS_FPGA_1, adding one";
411
412
413
414
415
416
417
418
419
420
421
422
                }
                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;
423
                    LOG(WARNING) << "Missing TS_FPGA_2, adding one";
424
425
426
427
428
                }
                new_ts2 = false;
                fpga_ts3 = fpga_tsx;
                fpga_ts = fpga_ts1 | fpga_ts2 | fpga_ts3;
                break;
429

430
431
432
            // BUSY was asserted due to FIFO_FULL + 24 LSBs of FPGA timestamp when it happened
            case 0b00000010:
                m_identifiers["BUSY_ASSERT"]++;
433
434
                busy_readout_ts = readout_ts;
                m_detectorBusy = true;
435
436
437
438
439
440
441
442
443
444
                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
445
                LOG(DEBUG) << "EMPTY_DATA";
446
447
448
449
450
451
452
453
                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
454
                    LOG(DEBUG) << "UNKNOWN_MESSAGE";
455
456
457
458
                } 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
459
                        LOG(DEBUG) << "BUFFER_OVERFLOW";
460
461
462
463
                    }
                    // 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
464
                        LOG(DEBUG) << "SERDES_LOCK_ESTABLISHED";
465
466
467
468
                    }
                    // 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
469
                        LOG(DEBUG) << "SERDES_LOCK_LOST";
470
471
472
473
                    }
                    // 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
474
                        LOG(DEBUG) << "WEIRD_DATA";
475
476
477
478
479
480
481
482
483
484
485
486
487
                    }
                    // Unknown message identifier
                    else {
                        m_identifiers["UNKNOWN_MESSAGE"]++;
                        LOG(WARNING) << "UNKNOWN_MESSAGE";
                    }
                }
                break;
                // End case
            }
        }
    }
    LOG(DEBUG) << "Returning " << pixels->size() << " pixels";
488
489
490
    return pixels;
}

491
Pixels* EventLoaderATLASpix::read_legacy_data(double, double) {
492

493
    // Pixel container
494
495
496
    Pixels* pixels = new Pixels();

    // Read file and load data
497
498
    while(!m_file.eof()) {

499
        int col, row, tot, ts;
500
501
502
503
504
        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
505
        if(m_detector->masked(col, row)) {
506
507
508
509
510
511
            continue;
        }

        // TOT
        if(tot <= (ts * 2 & 0x3F)) {
            tot = 64 + tot - (ts * 2 & 0x3F);
512
        } else {
513
514
515
516
            tot = tot - (ts * 2 & 0x3F);
        }

        // Apply calibration:
517
518
519
        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;
520
521
522
523

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

524
        if((bincounter & 0x1FF) < static_cast<unsigned long long>(ts)) {
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
            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);

541
        // TriggerDebugTS *= 4096. / 5;              // runs with 200MHz, divide by 5 to scale counter value to 40MHz
542
543
        double toa_timestamp =
            4096. * 2 * static_cast<double>(toa); // runs with 20MHz, multiply by 2 to scale counter value to 40MHz
544
545
546
547
548
549
550

        // 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;
551
            toa_timestamp -= corr * 163840000000; //(40000000 * 4096)
552
553
        }

554
        // Convert TOA to nanoseconds:
555
        toa_timestamp /= (4096. * 0.04);
556

557
        Pixel* pixel = new Pixel(m_detector->name(), row, col, tot, toa_timestamp);
558
        pixel->setCharge(cal_tot);
559
        pixels->push_back(pixel);
560
561
    }

562
    return pixels;
563
564
}

565
void EventLoaderATLASpix::finalise() {
566

567
568
569
570
    LOG(INFO) << "Identifier distribution:";
    for(auto id : m_identifiers) {
        LOG(INFO) << "\t" << id.first << ": " << id.second;
    }
571
572

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