in lib/nxp/drivers/fsl_usart.c [784:897]
status_t USART_TransferReceiveNonBlocking(USART_Type *base,
usart_handle_t *handle,
usart_transfer_t *xfer,
size_t *receivedBytes)
{
uint32_t i;
/* How many bytes to copy from ring buffer to user memory. */
size_t bytesToCopy = 0U;
/* How many bytes to receive. */
size_t bytesToReceive;
/* How many bytes currently have received. */
size_t bytesCurrentReceived;
uint32_t regPrimask = 0U;
/* Check arguments */
assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
if ((NULL == base) || (NULL == handle) || (NULL == xfer))
{
return kStatus_InvalidArgument;
}
/* Check xfer members */
assert(!((0U == xfer->dataSize) || (NULL == xfer->data)));
if ((0U == xfer->dataSize) || (NULL == xfer->data))
{
return kStatus_InvalidArgument;
}
/* How to get data:
1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
to uart handle, enable interrupt to store received data to xfer->data. When
all data received, trigger callback.
2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
If there are enough data in ring buffer, copy them to xfer->data and return.
If there are not enough data in ring buffer, copy all of them to xfer->data,
save the xfer->data remained empty space to uart handle, receive data
to this empty space and trigger callback when finished. */
if ((uint8_t)kUSART_RxBusy == handle->rxState)
{
return kStatus_USART_RxBusy;
}
else
{
bytesToReceive = xfer->dataSize;
bytesCurrentReceived = 0U;
/* If RX ring buffer is used. */
if (handle->rxRingBuffer != NULL)
{
/* Disable IRQ, protect ring buffer. */
regPrimask = DisableGlobalIRQ();
/* How many bytes in RX ring buffer currently. */
bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
if (bytesToCopy != 0U)
{
bytesToCopy = MIN(bytesToReceive, bytesToCopy);
bytesToReceive -= bytesToCopy;
/* Copy data from ring buffer to user memory. */
for (i = 0U; i < bytesToCopy; i++)
{
xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
/* Wrap to 0. Not use modulo (%) because it might be large and slow. */
if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferTail = 0U;
}
else
{
handle->rxRingBufferTail++;
}
}
}
/* If ring buffer does not have enough data, still need to read more data. */
if (bytesToReceive != 0U)
{
/* No data in ring buffer, save the request to UART handle. */
handle->rxData = xfer->data + bytesCurrentReceived;
handle->rxDataSize = bytesToReceive;
handle->rxDataSizeAll = bytesToReceive;
handle->rxState = (uint8_t)kUSART_RxBusy;
}
/* Enable IRQ if previously enabled. */
EnableGlobalIRQ(regPrimask);
/* Call user callback since all data are received. */
if (0U == bytesToReceive)
{
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
}
}
}
/* Ring buffer not used. */
else
{
/* Disable IRQ when configuring transfer handle, in case interrupt occurs during the process and messes up
* the handle value. */
regPrimask = DisableGlobalIRQ();
handle->rxData = xfer->data + bytesCurrentReceived;
handle->rxDataSize = bytesToReceive;
handle->rxDataSizeAll = bytesToReceive;
handle->rxState = (uint8_t)kUSART_RxBusy;
/* Enable RX interrupt. */
base->FIFOINTENSET = USART_FIFOINTENSET_RXLVL_MASK;
/* Re-enable IRQ. */
EnableGlobalIRQ(regPrimask);
}
/* Return the how many bytes have read. */
if (receivedBytes != NULL)
{
*receivedBytes = bytesCurrentReceived;
}
}
return kStatus_Success;
}