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