pi_pico/src/MCU_USB/prg/MCU_USB_prg.c
Mohamed Salem 3d5e63c790 Redesign RX to non-blocking ring buffer model
UART/USB now receive in the background and store into ring buffers.
Callers read from the buffer via non-blocking ReadByte/ReadBuffer.
Removed blocking ReceiveByte, async ReceiveBuffer with request
state and callbacks. MCU_USB uses lazy drain from SDK stdio into
its own ring buffer. MCU_UART ring buffer unchanged (ISR/DMA).
HAL_COM updated with ReadByte/ReadBuffer function pointer dispatch.
APP_CLSW updated to use new ReadByte API.
2026-04-13 01:50:58 +02:00

230 lines
6.7 KiB
C

/******************************************************************************
* File: MCU_USB_prg.c
* Component: MCU_USB
* Description: USB-CDC driver. TX via putchar_raw (fire-and-forget).
* RX via internal ring buffer, lazily drained from the SDK's
* stdio layer on every ReadByte / ReadBuffer / IsDataAvailable
* call. No separate RX task or interrupt needed — the SDK's
* TinyUSB background task fills stdio internally, and we pull
* from stdio into our ring buffer on demand.
*
* Layer: MCU (hardware abstraction)
*****************************************************************************/
#include "STD_TYPES.h"
#include "pico/stdio_usb.h"
#include "pico/stdio.h"
#include "pico/time.h"
#include "MCU_USB.h"
#include "MCU_USB_priv.h"
#include "MCU_USB_cfg.h"
/* ------------------------------------------------------------------------ */
/* RX RING BUFFER */
/* ------------------------------------------------------------------------ */
/** @brief RX ring buffer size — must be power of 2. */
#define USB_RX_BUFFER_SIZE_BITS 6U
#define USB_RX_BUFFER_SIZE (1U << USB_RX_BUFFER_SIZE_BITS)
#define USB_RX_BUFFER_MASK (USB_RX_BUFFER_SIZE - 1U)
static u8 au8RxBuffer[USB_RX_BUFFER_SIZE];
static u16 u16RxHead = 0U;
static u16 u16RxTail = 0U;
/**
* @brief Drain any available bytes from the SDK's stdio into our ring buffer.
*
* Called lazily from ReadByte, ReadBuffer, and bIsRxDataAvailable.
* getchar_timeout_us(0) is non-blocking — returns PICO_ERROR_TIMEOUT (-1)
* immediately if no data. We keep pulling until the SDK has nothing left
* or our ring buffer is full.
*/
static void vDrainStdio(void)
{
s32 s32ByteLoc;
u16 u16NextHeadLoc;
s32ByteLoc = (s32)getchar_timeout_us(0);
while (s32ByteLoc >= 0)
{
u16NextHeadLoc = (u16RxHead + 1U) & USB_RX_BUFFER_MASK;
/* If the ring buffer is full, stop draining (oldest data preserved,
* newest data from SDK is lost). Caller should read faster. */
if (u16NextHeadLoc == u16RxTail)
{
/* Buffer full — can't store this byte. Break out. */
break;
}
au8RxBuffer[u16RxHead] = (u8)s32ByteLoc;
u16RxHead = u16NextHeadLoc;
s32ByteLoc = (s32)getchar_timeout_us(0);
}
}
/* ========================================================================= */
/* INIT */
/* ========================================================================= */
STD_tenuResult MCU_USB_enuInit(void)
{
STD_tenuResult enuResultLoc = STD_OK;
STD_tBool bSdkInitSuccess = STD_FALSE;
bSdkInitSuccess = (stdio_usb_init() != 0) ? STD_TRUE : STD_FALSE;
if (bSdkInitSuccess == STD_FALSE)
{
enuResultLoc = STD_NOK;
}
else
{
#if MCU_USB_WAIT_FOR_CONNECTION == MCU_USB_WAIT_FOR_CONNECTION_ENABLED
absolute_time_t absTimeout = make_timeout_time_ms(MCU_USB_CONNECTION_TIMEOUT_MS);
STD_tBool bHostOpen = STD_FALSE;
STD_tBool bTimeoutReached = STD_FALSE;
do
{
sleep_ms(10);
bHostOpen = (stdio_usb_connected() != 0) ? STD_TRUE : STD_FALSE;
bTimeoutReached = (time_reached(absTimeout) != 0) ? STD_TRUE : STD_FALSE;
} while ((bHostOpen == STD_FALSE) && (bTimeoutReached == STD_FALSE));
if (bHostOpen == STD_FALSE)
{
enuResultLoc = STD_NOK;
}
#endif
}
return enuResultLoc;
}
/* ========================================================================= */
/* SEND BYTE */
/* ========================================================================= */
STD_tenuResult MCU_USB_enuSendByte(u8 u8Byte)
{
STD_tenuResult enuResultLoc = STD_OK;
putchar_raw(u8Byte);
return enuResultLoc;
}
/* ========================================================================= */
/* SEND BUFFER */
/* ========================================================================= */
STD_tenuResult MCU_USB_enuSendBuffer(const u8 *pu8Data, u16 u16Length)
{
STD_tenuResult enuResultLoc = STD_OK;
u16 u16IndexLoc;
if (pu8Data == STD_NULL)
{
enuResultLoc = STD_NULL_POINTER_ERROR;
}
else
{
for (u16IndexLoc = 0U; u16IndexLoc < u16Length; u16IndexLoc++)
{
putchar_raw(pu8Data[u16IndexLoc]);
}
}
return enuResultLoc;
}
/* ========================================================================= */
/* READ BYTE (NON-BLOCKING) */
/* ========================================================================= */
STD_tenuResult MCU_USB_enuReadByte(u8 *pu8Byte)
{
STD_tenuResult enuResultLoc = STD_OK;
if (pu8Byte == STD_NULL)
{
enuResultLoc = STD_NULL_POINTER_ERROR;
}
else
{
/* Pull any pending data from SDK into our ring buffer */
vDrainStdio();
if (u16RxHead == u16RxTail)
{
enuResultLoc = STD_NOK;
}
else
{
*pu8Byte = au8RxBuffer[u16RxTail];
u16RxTail = (u16RxTail + 1U) & USB_RX_BUFFER_MASK;
}
}
return enuResultLoc;
}
/* ========================================================================= */
/* READ BUFFER (NON-BLOCKING) */
/* ========================================================================= */
STD_tenuResult MCU_USB_enuReadBuffer(u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read)
{
STD_tenuResult enuResultLoc = STD_OK;
if ((pu8Data == STD_NULL) || (pu16Read == STD_NULL))
{
enuResultLoc = STD_NULL_POINTER_ERROR;
}
else
{
vDrainStdio();
u16 u16CountLoc = 0U;
while ((u16RxHead != u16RxTail) && (u16CountLoc < u16MaxLength))
{
pu8Data[u16CountLoc] = au8RxBuffer[u16RxTail];
u16RxTail = (u16RxTail + 1U) & USB_RX_BUFFER_MASK;
u16CountLoc++;
}
*pu16Read = u16CountLoc;
if (u16CountLoc == 0U)
{
enuResultLoc = STD_NOK;
}
}
return enuResultLoc;
}
/* ========================================================================= */
/* RX DATA AVAILABLE CHECK */
/* ========================================================================= */
STD_tBool MCU_USB_bIsRxDataAvailable(void)
{
STD_tBool bResultLoc = STD_FALSE;
vDrainStdio();
if (u16RxHead != u16RxTail)
{
bResultLoc = STD_TRUE;
}
return bResultLoc;
}