bool PayloadPacketizerPacketGet()

in src/cdi/payload.c [131:274]


bool PayloadPacketizerPacketGet(CdiProtocolHandle protocol_handle, CdiPacketizerStateHandle packetizer_state_handle,
                                char* header_ptr, CdiPoolHandle packet_sgl_entry_pool_handle,
                                TxPayloadState* payload_state_ptr, CdiSgList* packet_sgl_ptr,
                                bool* ret_is_last_packet_ptr)
{
    bool ret = true;

    CdiPacketizerState* packetizer_state_ptr = (CdiPacketizerState*)packetizer_state_handle;
    CdiPayloadPacketState* packet_state_ptr = &payload_state_ptr->payload_packet_state;

    if (kStateInactive == packetizer_state_ptr->state) {
        // Initialize all data and pointers used in the SGL list.
        memset((void*)packet_sgl_ptr, 0, sizeof(*packet_sgl_ptr));

        // Create new SGL entry for the payload data to hold the CDI header and first part of the payload data.
        packetizer_state_ptr->packet_entry_hdr_ptr = NULL;

        packetizer_state_ptr->state = kStateAddingHeader;
    }

    if (kStateAddingHeader == packetizer_state_ptr->state) {
        // NOTE: All the pools used in this function are not thread-safe, so must ensure that only one thread is
        // accessing them at a time.
#ifdef USE_MEMORY_POOL_APPENDED_LISTS
        ret = CdiPoolGetAndAppend(packet_sgl_entry_pool_handle, packet_sgl_ptr->sgl_tail_ptr,
                                  (void**)&packetizer_state_ptr->packet_entry_hdr_ptr);
#else
        ret = CdiPoolGet(packet_sgl_entry_pool_handle, (void**)&packetizer_state_ptr->packet_entry_hdr_ptr);
#endif
        if (ret) {
            // Initialize SGL entry.
            packetizer_state_ptr->packet_entry_hdr_ptr->next_ptr = NULL;
            packetizer_state_ptr->packet_entry_hdr_ptr->internal_data_ptr = NULL;

            // Include message prefix buffer space in header part.
            int msg_prefix_size = payload_state_ptr->cdi_endpoint_handle->adapter_endpoint_ptr->adapter_con_state_ptr->\
                                  adapter_state_ptr->msg_prefix_size;
            packetizer_state_ptr->header_size = msg_prefix_size;

            // Initialize the protocol specific packet header data.
            payload_state_ptr->payload_packet_state.packet_id = payload_state_ptr->cdi_endpoint_handle->tx_state.packet_id;
            packetizer_state_ptr->header_size += ProtocolPayloadHeaderInit(protocol_handle,
                (CdiRawPacketHeader*)(header_ptr + msg_prefix_size), payload_state_ptr);

            // Setup SGL entry for our header and add it to the packet SGL.
            packetizer_state_ptr->packet_entry_hdr_ptr->address_ptr = header_ptr;
            packetizer_state_ptr->packet_entry_hdr_ptr->size_in_bytes = packetizer_state_ptr->header_size;
            SglAppend(packet_sgl_ptr, packetizer_state_ptr->packet_entry_hdr_ptr); // NOTE: SGL list size is updated.

            // Try to fill an entire packet, either by using part of a large SGL entry and/or multiple smaller SGL
            // entries.
            packetizer_state_ptr->max_payload_bytes =
                packet_state_ptr->maximum_packet_byte_size - packetizer_state_ptr->header_size;
            if (payload_state_ptr->group_size_bytes > 0) {
                // If the pattern size is larger than the max payload then do not modify the payload size.
                if (payload_state_ptr->group_size_bytes <= packetizer_state_ptr->max_payload_bytes) {
                    packetizer_state_ptr->max_payload_bytes = PrevMultipleOf(packetizer_state_ptr->max_payload_bytes,
                                                                             payload_state_ptr->group_size_bytes);
                } else {
                    CDI_LOG_THREAD(kLogWarning,
                                   "Payload unit size [%d] bytes is larger than available packet data [%d] bytes",
                                   payload_state_ptr->group_size_bytes, packetizer_state_ptr->max_payload_bytes);
                }
            }

            packetizer_state_ptr->accumulated_payload_bytes = 0;
            packetizer_state_ptr->sgl_entry_count = 1; // Allow for CDI header created above.
            packetizer_state_ptr->data_addr_ptr = (uint8_t*)packet_state_ptr->source_entry_ptr->address_ptr +
                                                  packet_state_ptr->source_entry_address_offset;

            packetizer_state_ptr->state = kStateAddingEntries;
        }
    }

    if (kStateAddingEntries == packetizer_state_ptr->state) {
        // Break out of this loop if we filled the packet, or we ran out of source SGL entries, or we have reached the
        // maximum number of SGL entries supported by the underlying adapter.
        while (ret && packetizer_state_ptr->accumulated_payload_bytes < packetizer_state_ptr->max_payload_bytes &&
               packet_state_ptr->source_entry_ptr) {
            // Create new SGL entry for the payload data and add it to the packet SGL.
            CdiSglEntry *packet_entry_data_ptr = NULL;
#ifdef USE_MEMORY_POOL_APPENDED_LISTS
            ret = CdiPoolGetAndAppend(packet_sgl_entry_pool_handle, packet_sgl_ptr->sgl_tail_ptr,
                                        (void**)&packet_entry_data_ptr);
#else
            ret = CdiPoolGet(packet_sgl_entry_pool_handle, (void**)&packet_entry_data_ptr);
#endif
            if (ret) {
                const int sgl_data_size = CDI_MIN(packet_state_ptr->source_entry_ptr->size_in_bytes -
                                                  packet_state_ptr->source_entry_address_offset,
                                                  packetizer_state_ptr->max_payload_bytes -
                                                  packetizer_state_ptr->accumulated_payload_bytes);

                // Initialize SGL entry.
                packet_entry_data_ptr->next_ptr = NULL;
                packet_entry_data_ptr->internal_data_ptr = NULL;

                // Set SGL entry data and add it to the SGL list.
                packet_entry_data_ptr->address_ptr = packetizer_state_ptr->data_addr_ptr;
                packet_entry_data_ptr->size_in_bytes = sgl_data_size;
                SglAppend(packet_sgl_ptr, packet_entry_data_ptr); // NOTE: SGL list size is updated in this call.

                packetizer_state_ptr->accumulated_payload_bytes += sgl_data_size;
                packetizer_state_ptr->data_addr_ptr += sgl_data_size;
                packet_state_ptr->payload_data_offset += sgl_data_size;

                packet_state_ptr->source_entry_address_offset += sgl_data_size;
                if (packet_state_ptr->source_entry_address_offset >=
                    packet_state_ptr->source_entry_ptr->size_in_bytes) {
                    packet_state_ptr->source_entry_ptr = packet_state_ptr->source_entry_ptr->next_ptr;
                    packet_state_ptr->source_entry_address_offset = 0;
                    if (NULL != packet_state_ptr->source_entry_ptr) {
                        packetizer_state_ptr->data_addr_ptr = packet_state_ptr->source_entry_ptr->address_ptr;
                    }
                }

                packet_state_ptr->packet_payload_data_size = packetizer_state_ptr->accumulated_payload_bytes;

                // Determine if we have reached the maximum number of SGL entries the adapter supports for a single
                // packet.
                if (++packetizer_state_ptr->sgl_entry_count >= packet_state_ptr->maximum_tx_sgl_entries) {
                    // Force subsequent packets to include a data offset in their headers; this packet doesn't need the
                    // offset to be correctly placed on the receive side. The data offset is needed for the receive side
                    // to know where to place the data when its using a linear buffer since packets can arrive out of
                    // order.
                    packet_state_ptr->payload_type = kPayloadTypeDataOffset;
                    break;
                }
            }
        }

        *ret_is_last_packet_ptr = false;
        if (ret) {
            // Packet was successfully obtained, so update returned last state flag, increment packet counters and
            // initialize the packet state.
            *ret_is_last_packet_ptr = NULL == packet_state_ptr->source_entry_ptr;
            packet_state_ptr->packet_sequence_num++;
            payload_state_ptr->cdi_endpoint_handle->tx_state.packet_id++;
            packetizer_state_ptr->state = kStateInactive;
        }
    }

    return ret;
}