/*
 * SingleFrameIncomingTransfer
 */
SingleFrameIncomingTransfer::SingleFrameIncomingTransfer(const RxFrame& frm)
    : IncomingTransfer(frm.getMonotonicTimestamp(), frm.getUtcTimestamp(), frm.getPriority(),
                       frm.getTransferType(), frm.getTransferID(), frm.getSrcNodeID(), frm.getIfaceIndex())
    , payload_(frm.getPayloadPtr())
    , payload_len_(uint8_t(frm.getPayloadLen()))
{
    UAVCAN_ASSERT(frm.isValid());
}
TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, TransferBufferAccessor& tba)
{
    // Transfer timestamps are derived from the first frame
    if (frame.isFirst())
    {
        this_transfer_ts_ = frame.getMonotonicTimestamp();
        first_frame_ts_   = frame.getUtcTimestamp();
    }

    if (frame.isFirst() && frame.isLast())
    {
        tba.remove();
        updateTransferTimings();
        prepareForNextTransfer();
        this_transfer_crc_ = 0;         // SFT has no CRC
        return ResultSingleFrame;
    }

    // Payload write
    ITransferBuffer* buf = tba.access();
    if (buf == NULL)
    {
        buf = tba.create();
    }
    if (buf == NULL)
    {
        UAVCAN_TRACE("TransferReceiver", "Failed to access the buffer, %s", frame.toString().c_str());
        prepareForNextTransfer();
        registerError();
        return ResultNotComplete;
    }
    if (!writePayload(frame, *buf))
    {
        UAVCAN_TRACE("TransferReceiver", "Payload write failed, %s", frame.toString().c_str());
        tba.remove();
        prepareForNextTransfer();
        registerError();
        return ResultNotComplete;
    }
    next_frame_index_++;

    if (frame.isLast())
    {
        updateTransferTimings();
        prepareForNextTransfer();
        return ResultComplete;
    }
    return ResultNotComplete;
}
/*
 * GlobalTimeSyncMaster
 */
void GlobalTimeSyncMaster::handleLoopbackFrame(const RxFrame& frame)
{
    const uint8_t iface = frame.getIfaceIndex();
    if (initialized_ && iface < MaxCanIfaces)
    {
        if (frame.getDataTypeID() == dtid_ &&
            frame.getTransferType() == TransferTypeMessageBroadcast &&
            frame.isLast() && frame.isFirst() &&
            frame.getSrcNodeID() == node_.getNodeID())
        {
            iface_masters_[iface]->setTxTimestamp(frame.getUtcTimestamp());
        }
    }
    else
    {
        UAVCAN_ASSERT(0);
    }
}
TEST(MultiFrameIncomingTransfer, Basic)
{
    using uavcan::RxFrame;
    using uavcan::MultiFrameIncomingTransfer;

    uavcan::PoolManager<1> poolmgr;                 // We don't need dynamic memory
    uavcan::TransferBufferManager<256, 1> bufmgr(poolmgr);

    const RxFrame frame = makeFrame();
    uavcan::TransferBufferManagerKey bufmgr_key(frame.getSrcNodeID(), frame.getTransferType());
    uavcan::TransferBufferAccessor tba(bufmgr, bufmgr_key);

    MultiFrameIncomingTransfer it(frame.getMonotonicTimestamp(), frame.getUtcTimestamp(), frame, tba);

    /*
     * Empty read must fail
     */
    uint8_t data_byte = 0;
    ASSERT_GT(0, it.read(0, &data_byte, 1));  // Error - no such buffer

    /*
     * Filling the test data
     */
    const std::string data = "123Hello world";
    const uint8_t* const data_ptr = reinterpret_cast<const uint8_t*>(data.c_str());
    ASSERT_FALSE(bufmgr.access(bufmgr_key));
    ASSERT_TRUE(bufmgr.create(bufmgr_key));
    ASSERT_EQ(data.length(), bufmgr.access(bufmgr_key)->write(0, data_ptr, data.length()));

    /*
     * Check
     */
    ASSERT_TRUE(match(it, frame, data_ptr, data.length()));

    /*
     * Buffer release
     */
    ASSERT_TRUE(bufmgr.access(bufmgr_key));
    it.release();
    ASSERT_FALSE(bufmgr.access(bufmgr_key));
}