Program Listing for File l0id_decoder.cpp

Return to documentation for file (l0id_decoder.cpp)

#include <cstring>
#include "l0id_decoder.hpp"
#include "log.hpp"


L0Decoder::L0Decoder(int format, uint64_t fid)
    : m_fid(fid)
{
    m_last.xl1id = 0x00ffffff;

    switch (format)
    {
    case 0:
        break;
    case L0ID_FMT::TTC2H:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H only");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_ttc2h, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 8;
        m_ec_mask = 0x00ffffff;
        break;
    case L0ID_FMT::LATOME:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H, LATOME data");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_latome, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 48;
        m_ec_mask = 0x00ffffff;
        break;
    case L0ID_FMT::FMEMU:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H, FMEMU data");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_fmemu, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 4;
        m_ec_mask = 0x00ffffff;
        break;
    case L0ID_FMT::FELIG:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H, FELIG data");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_felig, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 4;
        m_ec_mask = 0x0000ffff;
        break;
    case L0ID_FMT::NSW_VMM:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H, NSW VMM data");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_nsw_vmm, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 4;
        m_ec_mask = 0x0000ffff;
        break;
    case L0ID_FMT::NSW_TP:
        LOG_INFO("L1ID sequentiality check enabled: TTC2H, NSW TP data");
        check_sequence_error = std::bind(&L0Decoder::check_sequence_nsw_tp, this, std::placeholders::_1, std::placeholders::_2);
        m_required_bytes = 8;
        m_ec_mask =  0x00ffffff;
        break;
    default:
        LOG_INFO("Invalid choice for L1ID sequentiality check. Check disabled");
    }
}


bool L0Decoder::check_tohost_chunk(std::vector<iovec> const &data)
{
    uint8_t* chunk = new uint8_t[m_required_bytes];
    unsigned int copied = 0;
    if (data.size() >= 1) {
        for (unsigned int idx = 1; idx < data.size(); ++idx) {
            unsigned int max = data[idx].iov_len > m_required_bytes ? m_required_bytes : data[idx].iov_len;
            memcpy(chunk + copied, data[idx].iov_base, max);
            copied += max;
            if (copied >= m_required_bytes){
                break;
            }
        }
    }
    bool ret = check_sequence_error(chunk, copied);
    delete[] chunk;
    return ret;
}


bool inline L0Decoder::compare(xl1id_t current, xl1id_t expected)
{
  if(current.fields.ec != expected.fields.ec){
    LOG_INFO("fid 0x%lx (0x%x) has L1ID 0x%06x, expected 0x%06x", m_fid, get_elink(m_fid), current.fields.ec, expected.fields.ec);
    return true;
  }
  return false;
}


bool L0Decoder::check_sequence_ttc2h(const uint8_t* data, size_t len)
{
    if (len < m_required_bytes)
    {
        LOG_INFO("TTC2H message from fid 0x%lx (0x%x) too small to retrieve XL1ID, size %lu.", m_fid, get_elink(m_fid), len);
        return true;
    }
    xl1id_t current, expected;
    current.xl1id = reinterpret_cast<const uint32_t *>(data)[1];

    bcid_t current_bc;
    current_bc.bc_data = reinterpret_cast<const uint32_t *>(data)[0];

    LOG_DBG("Current L1ID 0x%06x BCID 0x%04x", current.fields.ec, current_bc.fields.bcid);
    if (current.fields.ecrc == (m_last.fields.ecrc + 1))
    {
        LOG_INFO("ECR on TTC2H fid 0x%lx (0x%x)", m_fid, get_elink(m_fid));
        expected.fields.ec = 0x0;
    }
    else
    {
        expected.fields.ec = (m_last.fields.ec + 1) & 0x00ffffff;
    }
    m_last.xl1id = current.xl1id;
    return compare(current, expected);
}


bool L0Decoder::check_sequence_latome(const uint8_t* data, size_t len)
{
    if (len < m_required_bytes)
    {
        LOG_INFO("LATOME message from fid 0x%lx (0x%x) too small to retrieve XL1ID, size %lu.", m_fid, get_elink(m_fid), len);
        return true;
    }
    xl1id_t current, expected;
    current.xl1id = reinterpret_cast<const uint32_t *>(data)[5];

    if (current.fields.ecrc == (m_last.fields.ecrc + 1))
    {
        LOG_DBG("ECR on fid 0x%lx (0x%x)", m_fid, get_elink(m_fid));
        expected.fields.ec = 0x0;
    }
    else
    {
        expected.fields.ec = (m_last.fields.ec + 1) & 0x00ffffff;
    }
    m_last.xl1id = current.xl1id;
    return compare(current, expected);
}


bool L0Decoder::check_sequence_fmemu(const uint8_t* data, size_t len)
{
    if (len < m_required_bytes)
    {
        LOG_INFO("FMEMU message from fid 0x%lx (0x%x) too small to retrieve XL1ID, size %lu.", m_fid, get_elink(m_fid), len);
        return true;
    }
    xl1id_t current, expected;
    current.xl1id = reinterpret_cast<const uint32_t *>(data)[0];
    if (current.fields.ecrc == (m_last.fields.ecrc + 1))
    {
        LOG_DBG("ECR on fid 0x%lx (0x%x)", m_fid, get_elink(m_fid));
        expected.fields.ec = 0x0;
    }
    else
    {
        expected.fields.ec = (m_last.fields.ec + 1) & 0x00ffffff;
    }
    m_last.xl1id = current.xl1id;
    return compare(current, expected);
}


bool L0Decoder::check_sequence_felig(const uint8_t* data, size_t len)
{
    if (len < m_required_bytes)
    {
        LOG_INFO("FELIG message from fid 0x%lx (0x%x) smaller than FELIG header, size %lu.", m_fid, get_elink(m_fid), len);
        return true;
    }
    xl1id_t current, expected;
    uint8_t* chunk_data = const_cast<uint8_t*>(data);
    current.fields.ec = ( chunk_data[4] | (chunk_data[3] << 8) );
    expected.fields.ec = (m_last.fields.ec + 1) & 0x0000ffff;
    m_last.xl1id = current.xl1id;
    return compare(current, expected);
}


bool L0Decoder::check_sequence_nsw_vmm(const uint8_t* data, size_t len)
{
    if (len < 2){
        LOG_INFO("NSW VMM message from fid 0x%lx (0x%x) too small to retrieve header, size %lu.",
            m_fid, get_elink(m_fid), len);
        return true;
    }
    if (len > 4*(512+4)) {
        LOG_INFO("NSW VMM message from fid 0x%lx (0x%x) too long, size %lu.", m_fid, get_elink(m_fid), len);
    }
    xl1id_t current, expected;
    //enum packetType { FULL_MM=0, NULL_EVENT=1, FULL_STGC=2 , ILLEGAL=3};
    unsigned char headerType = data[0] >> 6;
    switch (headerType)
    {
    case 0: // MM   full header
    case 2: // sTGC full header
        current.fields.ec = (data[3] | (data[2] << 8)) & 0xff;
        expected.fields.ec = (m_last.fields.ec + 1) & 0xff;
        m_last.fields.ec = (data[3] | (data[2] << 8)) & 0xffff;
        m_ec_mask = 0xffff;
        break;
    case 1: // null header
        current.fields.ec = data[1];
        expected.fields.ec = (m_last.fields.ec + 1) & 0xff;
        m_last.fields.ec = data[1];
        m_ec_mask = 0xff;
        break;
    case 3: // illegal header type
    {
        unsigned int vmmHeader = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
        LOG_INFO("Illegal VMM message from fid 0x%lx (0x%x), headerType = 3, headerword = 0x%x, size %d.", m_fid, get_elink(m_fid), vmmHeader, len);
        break;
    }
    default:
        LOG_INFO("Invalid header from fid 0x%lx (0x%x), type 0x%x", m_fid, get_elink(m_fid), headerType);
    }

    return compare(current, expected);
}


bool L0Decoder::check_sequence_nsw_tp(const uint8_t* data, size_t len)
{
    if (len < m_required_bytes)
    {
        LOG_INFO("NSW TP message from fid 0x%lx (0x%x) too small to retrieve XL1ID, size %lu.", m_fid, get_elink(m_fid), len);
        return true;
    }
    xl1id_t current, expected;
    current.fields.ec =  ( data[5]<<16 | data[6]<<8 | data[7] ) & 0x00ffffff;
    current.fields.ecrc = (data[4]<<24) & 0xff;
    if(current.fields.ecrc == (m_last.fields.ecrc+1) ){
      LOG_DBG("ECR on fid 0x%lx (0x%x)", m_fid, get_elink(m_fid));
      expected.fields.ec = 0x0;
    } else{
      expected.fields.ec = (m_last.fields.ec+1) & 0x00ffffff;
    }
    m_last.xl1id = current.xl1id;
    return compare(current, expected);
}