Program Listing for File encoder.cpp

Return to documentation for file (encoder.cpp)

#include "encoder.hpp"
#include "log.hpp"


void Encoder::set_data_format(int format)
{
#if REGMAP_VERSION < 0x0500
    m_header_size = 2;
    m_block_bytes = 32;
    m_length_mask = TOFLX_LENGTH_MASK_RM4;
    m_elink_shift = TOFLX_ELINK_SHIFT_RM4;
#else
    switch (format)
    {
        case FROMHOST_FORMAT_5BIT_LENGTH:
            m_header_size = 2;
            m_block_bytes = 32;
            m_length_mask = TOFLX_LENGTH_MASK;
            m_elink_shift = TOFLX_ELINK_SHIFT;
            break;
        case FROMHOST_FORMAT_HDR32_PACKET32:
            m_header_size = 4;
            m_block_bytes = 32;
            m_length_mask = TOFLX_LENGTH_MASK_HDR32;
            m_elink_shift = TOFLX_ELINK_SHIFT_HDR32;
            break;
        case FROMHOST_FORMAT_HDR32_PACKET64:
            m_block_bytes = 64;
            m_length_mask = TOFLX_LENGTH_MASK_HDR32;
            m_elink_shift = TOFLX_ELINK_SHIFT_HDR32;
            break;
        case FROMHOST_FORMAT_HDR32_PACKET32_8B:
            m_block_bytes = 32;
            break;
        case FROMHOST_FORMAT_HDR32_PACKET64_8B:
            m_block_bytes = 64;
            break;
        case FROMHOST_FORMAT_HDR32_PACKET128_8B:
            m_block_bytes = 128;
            break;
        default:
            LOG_ERR("Invalid FromHost data format %d. Assuming rm-5.1 for PCIe gen3.", format);
            break;
    }
#endif
    m_payload_bytes = m_block_bytes - m_header_size;
}

void Encoder::set_destination_parameters(uint8_t* dest_start, uint32_t dest_size)
{
    m_dest_start = dest_start;
    m_dest_size = dest_size;
}


size_t Encoder::compute_max_msg_occupancy(size_t size) const
{
    return (compute_full_blocks(size) + 1) * m_block_bytes;
}


int Encoder::compute_full_blocks(size_t size) const
{
    return ((size + m_payload_bytes - 1) / m_payload_bytes);
}


size_t Encoder::compute_final_bytes(size_t size) const
{
    size_t blocks = (size + m_payload_bytes - 1) / m_payload_bytes;
    size_t final_bytes = size - (blocks - 1) * m_payload_bytes;
    return final_bytes;
}


uint64_t Encoder::encode_and_write_msg(uint64_t elink, const uint8_t *source, size_t size, uint32_t dest_offset)
{
    if (m_dest_start == nullptr){
        LOG_ERR("FromHost encoder not initialized. The message for 0x%lx will not be written.", elink);
        return 0;
    }
    uint32_t src_i(0);
    uint32_t dest_i(dest_offset);
    int blocks = compute_full_blocks(size);
    int final_bytes = size - (blocks - 1) * m_payload_bytes;
#if REGMAP_VERSION < 0x0500
    int hdr = ((elink << m_elink_shift) | ((m_payload_bytes / 2) << TOFLX_LENGTH_SHIFT_RM4));
    int final_size = (final_bytes + 1) / 2; // Length in 2-byte units
    int final_hdr = hdr & ~m_length_mask;
    final_hdr |= ((final_size << TOFLX_LENGTH_SHIFT_RM4) | TOFLX_EOM_MASK_RM4);
#else
    // Regmap 0x0500 and beyond, see FLX-1355, FLX-1601 and FLX-1886
    if (m_length_mask == TOFLX_LENGTH_MASK_HDR32_8B and m_elink_shift == TOFLX_ELINK_SHIFT_HDR32_8B){
        // Keeping the existing 4-byte header e-link numbering,
        // so map the e-link number to the '8-bit-fields' version
        uint64_t linknr = (elink & 0x07C0) >> 6;
        uint64_t eindex = (elink & 0x003F);
        elink = (linknr << 8) | eindex;
    }
    int hdr = ((elink << m_elink_shift) | m_length_mask);
    int final_hdr = hdr & ~m_length_mask;
    final_hdr |= final_bytes; // Length in bytes
#endif
    // Fully-filled FromHost data packets
    for (int i = 0; i < blocks - 1; ++i)
    {
        // Invert payload byte order
        for (int j = m_payload_bytes - 1; j >= 0; --j, ++dest_i)
        {
            m_dest_start[dest_i] = source[src_i + j] & 0xFF;
        }
        src_i += m_payload_bytes;

        // Header
        for (int j = 0; j < m_header_size; ++j, ++dest_i)
            m_dest_start[dest_i] = (uint8_t)((hdr >> j * 8) & 0xFF);

        // Wrap-around ?
        if (dest_i >= m_dest_size)
            dest_i = 0;
    }

    // Final (likely not fully filled) FromHost data packet
    // Invert payload byte order
    for (int j = m_payload_bytes - 1; j >= final_bytes; --j, ++dest_i)
    {
        // destination[dest_i] = (char) 0xFF; // Remaining payload bytes: set to 0xFF
        m_dest_start[dest_i] = (uint8_t)0x00; // Remaining payload bytes: set to 0x00
    }
    for (int j = final_bytes - 1; j >= 0; --j, ++dest_i)
    {
        m_dest_start[dest_i] = source[src_i + j] & 0xFF; // Final data bytes
    }

    // Header
    for (int j = 0; j < m_header_size; ++j, ++dest_i)
        m_dest_start[dest_i] = (uint8_t)((final_hdr >> j * 8) & 0xFF);

    // Wrap-around ?
    if (dest_i >= m_dest_size){
        dest_i = 0;
    }

    return dest_i;
}