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