- #include <algorithm>
- #include <fstream>
- #include <sstream>
-
- // Local
- #include "TbKernel/TbConstants.h"
- #include "TbKernel/TbCondFile.h"
- #include "TbKernel/ITbDataSvc.h"
- #include "TbPixelSvc.h"
-
- DECLARE_SERVICE_FACTORY(TbPixelSvc)
-
- //============================================================================
- // Constructor
- //============================================================================
- TbPixelSvc::TbPixelSvc(const std::string& name, ISvcLocator* svc)
- : base_class(name, svc), m_geomSvc(nullptr), m_msg(nullptr) {
- declareProperty("WriteTrimDACs", m_writeTrimDACs = false);
- }
-
- //============================================================================
- // Destructor
- //============================================================================
- TbPixelSvc::~TbPixelSvc() {
-
- // Delete the message service.
- if (m_msg) delete m_msg;
- }
-
- //============================================================================
- // Initialisation
- //============================================================================
- StatusCode TbPixelSvc::initialize() {
-
- StatusCode sc = Service::initialize();
- if (!sc.isSuccess()) return sc;
- // Get the number of chips.
- const unsigned int nDevices = geomSvc()->nDevices();
- m_pixelConfiguration.resize(nDevices);
-
- m_protectPhase = std::vector<bool>(nDevices, 0);
- for (unsigned int i = 0; i < nDevices; ++i) {
- m_pixelConfiguration[i].resize(Tb::NPixels, PixelConfig());
- }
- // Retrieve the names of the configuration files to be parsed.
- ITbDataSvc* dataSvc = Gaudi::svcLocator()->service<ITbDataSvc>("TbDataSvc");
- std::vector<std::string> files = dataSvc->getPixelConfig();
- files.push_back(dataSvc->getTimingConfig());
- for (auto& f : files) {
- if (f == "") continue;
- msg() << MSG::INFO << "Importing pixel configuration from " << f << endmsg;
- // Import conditions from configuration file.
- if (!readConditions(f)) {
- msg() << MSG::ERROR << "Cannot import pixel configuration" << endmsg;
- return StatusCode::FAILURE;
- }
- }
- return StatusCode::SUCCESS;
- }
-
- //============================================================================
- // Add a constant offset in time to a single super column
- //============================================================================
- void TbPixelSvc::addOffset(const int offset, const unsigned int device,
- const unsigned int dcol) {
-
- for (unsigned int pix = 0; pix < 512; ++pix) {
- const unsigned int address = pix + (0xFE00 & (dcol << 9));
- m_pixelConfiguration[device][address].tOffset += offset;
- }
- }
-
- //============================================================================
- // Export trim DACs and masked pixel flags to a text file
- //============================================================================
- void TbPixelSvc::writeTrimDAC(const unsigned int device) {
- std::ofstream trimdac;
- trimdac.open(("plane_" + std::to_string(device) + "_trimdac.txt").c_str());
- trimdac << "#col row trim mask tp_ena " << std::endl;
- for (unsigned int col = 0; col < Tb::NCols; ++col) {
- for (unsigned int row = 0; row < Tb::NRows; ++row) {
- const unsigned int pixel = address(col, row);
- trimdac << std::setw(3) << col << std::setw(4) << row << std::setw(4)
- << (int)(m_pixelConfiguration[device][pixel].trim) << std::setw(4)
- << m_pixelConfiguration[device][pixel].trimDac_isMasked
- << std::setw(4) << m_pixelConfiguration[device][pixel].tp_ena
- << std::endl;
- }
- }
- trimdac.close();
- }
-
- //============================================================================
- // Set trim DACs for the entire pixel matrix of a chip
- //============================================================================
- void TbPixelSvc::setTrim(const unsigned int device, const char* data) {
- for (unsigned int col = 0; col < Tb::NCols; ++col) {
- for (unsigned int row = 0; row < Tb::NRows; ++row) {
- const unsigned int pixel = address(col, row);
- const uint8_t word = *(data + col + Tb::NRows * row);
- m_pixelConfiguration[device][pixel].trim = 0xF & (word >> 1);
- m_pixelConfiguration[device][pixel].tp_ena = 0x1 & (word >> 5);
- m_pixelConfiguration[device][pixel].trimDac_isMasked = 0x1 & word;
- }
- }
- if (m_writeTrimDACs) writeTrimDAC(device);
- }
-
- void TbPixelSvc::resetClockPhase(const unsigned int device) {
-
- for (unsigned int pixel = 0; pixel < Tb::NPixels; ++pixel) {
- m_pixelConfiguration[device][pixel].tOffset = 0;
- }
- }
-
- //============================================================================
- // Calculate the clock phase correction.
- //============================================================================
- void TbPixelSvc::setPhase(const unsigned int device,
- const unsigned int pll_config = 1024,
- const int amplitude = 1) {
- if (m_protectPhase[device]) return;
- const unsigned int phase = pow(2, (pll_config & 0x1C0) >> 6);
- if (phase == 1) return;
-
- for (unsigned int pixel = 0; pixel < Tb::NPixels; ++pixel) {
- // Decode the pixel address, first the double column.
- const unsigned int dcol = (0xFE00 & pixel) >> 9;
- // Get the pixel within the super pixel.
- const unsigned int pix = (0x0007 & pixel);
- // Calculate the column number.
- const unsigned int col = 2 * dcol + pix / 4;
- // col = col % 128;
- int dt = 0;
- if (phase == 16) {
- dt = (-((16 - ((col / 2) % 16)) % 16)) << 8;
- } else if (phase == 4) {
- dt = (-4 * ((4 - ((col / 2) % 4)) % 4)) << 8;
- } else if (phase == 2) {
- dt = (((col % 4) < 2) ? 8 : 0) << 8;
- }
- m_pixelConfiguration[device][pixel].tOffset += amplitude * dt;
- }
- m_protectPhase[device] = true;
- }
-
- //============================================================================
- // Import pixel conditions from configuration file
- //============================================================================
- bool TbPixelSvc::readConditions(const std::string& filename) {
-
- TbCondFile f(filename);
- if (!f.is_open()) {
- msg() << MSG::WARNING << "Cannot open " << filename << endmsg;
- return false;
- }
- std::string mode = "";
- std::string chip = "";
- int deviceIndex = -1;
- unsigned int col(0), row(0);
- std::vector<unsigned int> badPixels;
- while (!f.eof()) {
- std::string line = "";
- if (!f.getLine(line)) continue;
- if (line.find("Charge") != std::string::npos) {
- f.split(line, ' ', mode, chip);
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- msg() << MSG::ERROR << "Stop parsing " << filename << endmsg;
- break;
- }
- } else if (line.find("Mask") != std::string::npos ||
- line.find("Offset") != std::string::npos ||
- line.find("Timing") != std::string::npos ||
- line.find("GlobalCharge") != std::string::npos ||
- line.find("PLL") != std::string::npos) {
- mode = line;
- } else if (mode == "Charge") {
- float a(0.), b(0.), c(0.), t(0.);
- f.split(line, ' ', col, row, a, b, c, t);
- const unsigned int pixel = address(col, row);
-
- if( isnan(a) || isinf(a) || isnan(b) || isnan(c) || isnan(t) || isinf(b) || isinf(c) || isinf(t)){
- badPixels.push_back(pixel);
- }
- m_pixelConfiguration[deviceIndex][pixel].p0 = a;
- m_pixelConfiguration[deviceIndex][pixel].p1 = b;
- m_pixelConfiguration[deviceIndex][pixel].c = c;
- m_pixelConfiguration[deviceIndex][pixel].t = t;
- } else if (mode == "Mask") {
- f.split(line, ' ', chip, col, row);
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- continue;
- }
- const unsigned int pixel = address(col, row);
- msg() << MSG::INFO << "Masking pixel " << format("0x%04x", pixel)
- << format(" (column %3d", col) << format(", row %3d)", row)
- << " on device " << chip << endmsg;
- m_pixelConfiguration[deviceIndex][pixel].isMasked = true;
- } else if (mode == "GlobalCharge") {
- double a(0.), b(0.), c(0.), t(0.);
- f.split(line, ' ', chip, a, b, c, t);
- // if( isnan(a) || isnan(b) || isnan(c) || isnan(d) )
-
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- continue;
- }
- for (auto& pixel : m_pixelConfiguration[deviceIndex]) {
- pixel.p0 = a;
- pixel.p1 = b;
- pixel.c = c;
- pixel.t = t;
- }
- msg() << MSG::INFO << "Applying global charge calibration on device "
- << chip << "(a = " << a << ", b = " << b << ", c = " << c
- << ", t = " << t << ")" << endmsg;
- } else if (mode == "Offset") {
- int offset = 0;
- f.split(line, ' ', chip, col, offset);
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- continue;
- }
- msg() << MSG::INFO << "Adding time offset " << offset * 25 << " ns "
- << "to double column " << col << " on chip " << chip << endmsg;
- addOffset(offset * Tb::ToA, deviceIndex, col);
- } else if (mode == "Timing") {
- double dt = 0.;
- f.split(line, ' ', chip, dt);
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- continue;
- }
- const int offset = static_cast<int>(std::round(dt * Tb::nanosecond));
- msg() << MSG::INFO << "Adding time offset " << dt << " ns (" << offset
- << " time units) to chip " << chip << endmsg;
- const unsigned int nDCols = Tb::NCols / 2;
- for (unsigned int col = 0; col < nDCols; ++col) {
- addOffset(offset, deviceIndex, col);
- }
- } else if (mode == "PLL") {
- int amplitude = 0.;
- unsigned int pll_mode;
- f.split(line, ' ', chip, pll_mode, amplitude);
- deviceIndex = geomSvc()->deviceIndex(chip);
- if (deviceIndex == 999) {
- msg() << MSG::ERROR << "Device " << chip
- << " is not in the alignment file" << endmsg;
- continue;
- }
- msg() << MSG::INFO << "Overwriting PLL CONFIG for chip " << chip
- << endmsg;
- m_protectPhase[deviceIndex] = false;
- resetClockPhase(deviceIndex);
- setPhase(deviceIndex, pll_mode, amplitude);
- }
- }
- for( auto& pixel : badPixels ){
- auto pos = posFromAddress(pixel);
- float avgt(0), avgc(0), avgp0(0), avgp1(0);
- unsigned int nPixels=0;
- if( pos.second != 255 ){
- unsigned int neighbour = address( pos.first, pos.second+1 );
- if( std::find( badPixels.begin(), badPixels.end(), neighbour) == badPixels.end() ){
- avgt += m_pixelConfiguration[deviceIndex][neighbour].t;
- avgc += m_pixelConfiguration[deviceIndex][neighbour].c;
- avgp0 += m_pixelConfiguration[deviceIndex][neighbour].p0;
- avgp1 += m_pixelConfiguration[deviceIndex][neighbour].p1;
- nPixels++;
- }
- }
- if( pos.second != 0 ){
- unsigned int neighbour = address( pos.first, pos.second-1 );
- if( std::find( badPixels.begin(), badPixels.end(), neighbour) == badPixels.end() ){
- avgt += m_pixelConfiguration[deviceIndex][neighbour].t;
- avgc += m_pixelConfiguration[deviceIndex][neighbour].c;
- avgp0 += m_pixelConfiguration[deviceIndex][neighbour].p0;
- avgp1 += m_pixelConfiguration[deviceIndex][neighbour].p1;
- nPixels++;
- }
- }
- if(nPixels==0){
- m_pixelConfiguration[deviceIndex][pixel].isMasked = true;
- // printConfig( deviceIndex, pixel ) ;
- continue;
- }
- m_pixelConfiguration[deviceIndex][pixel].t = avgt / (float)nPixels;
- m_pixelConfiguration[deviceIndex][pixel].p0 = avgp0 / (float)nPixels;
- m_pixelConfiguration[deviceIndex][pixel].p1 = avgp1 / (float)nPixels;
- m_pixelConfiguration[deviceIndex][pixel].c = avgc / (float)nPixels;
- //printConfig( deviceIndex, pixel ) ;
- }
- f.close();
- return true;
- }