230 lines
6.7 KiB
C
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;
|
|
}
|