/*************************************************************************************************/
|
/*!
|
* \file
|
*
|
* \brief WSF buffer IO for UART driver.
|
*
|
* Copyright (c) 2013-2018 Arm Ltd. All Rights Reserved.
|
*
|
* Copyright (c) 2019-2020 Packetcraft, Inc.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
/*************************************************************************************************/
|
|
#include <string.h>
|
|
#include "wsf_types.h"
|
#include "wsf_bufio.h"
|
|
#include "wsf_cs.h"
|
#include "wsf_trace.h"
|
#include "wsf_os.h"
|
|
#include "pal_uart.h"
|
|
/**************************************************************************************************
|
Data Types
|
**************************************************************************************************/
|
|
/*! \brief TX structure */
|
typedef struct
|
{
|
uint8_t *pBuf; /*!< UART TX buffer pointer */
|
uint16_t size; /*!< UART TX buffer size */
|
uint16_t in; /*!< UART TX buffer in index */
|
uint16_t out; /*!< UART TX buffer out index */
|
uint16_t crt; /*!< UART TX current number of bytes sent */
|
} WsfBufIoUartTx_t;
|
|
/*! \brief RX structure */
|
typedef struct
|
{
|
WsfBufIoUartRxCback_t cback; /*!< UART RX callback. */
|
uint8_t buf[1]; /*!< UART RX buffer */
|
} WsfBufIoUartRx_t;
|
|
/**************************************************************************************************
|
Local Variables
|
**************************************************************************************************/
|
|
/*! \brief Control block. */
|
static struct
|
{
|
WsfBufIoUartTx_t tx; /*!< Platform UART TX structure */
|
WsfBufIoUartRx_t rx; /*!< Platform UART RX structure */
|
bool_t initialized; /*!< UART RX is initialized */
|
} WsfBufIoCb = {0};
|
|
/**************************************************************************************************
|
Local Functions
|
**************************************************************************************************/
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Start transmit.
|
*
|
* \param len Length to transmit.
|
*/
|
/*************************************************************************************************/
|
static void wsfBufIoUartTxStart(uint16_t len)
|
{
|
/* If TX buffer overrun happens, send bytes only till the end of the buffer. */
|
if (WsfBufIoCb.tx.out + len > WsfBufIoCb.tx.size)
|
{
|
len = WsfBufIoCb.tx.size - WsfBufIoCb.tx.out;
|
}
|
|
/* Check if TX length exceeds 1 octet size from UART driver. */
|
if (len <= 0xFF)
|
{
|
PalUartWriteData(PAL_UART_ID_TERMINAL, WsfBufIoCb.tx.pBuf + WsfBufIoCb.tx.out, (uint16_t)len);
|
WsfBufIoCb.tx.crt = len;
|
}
|
else
|
{
|
PalUartWriteData(PAL_UART_ID_TERMINAL, WsfBufIoCb.tx.pBuf + WsfBufIoCb.tx.out, 0xFF);
|
WsfBufIoCb.tx.crt = 0xFF;
|
}
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Get number of characters in Tx buffer.
|
*
|
* \return Number of characters in Tx buffer.
|
*/
|
/*************************************************************************************************/
|
static uint16_t wsfBufIoUartTxBufCount(void)
|
{
|
uint16_t count;
|
|
if (WsfBufIoCb.tx.in >= WsfBufIoCb.tx.out)
|
{
|
count = WsfBufIoCb.tx.in - WsfBufIoCb.tx.out;
|
}
|
else
|
{
|
count = WsfBufIoCb.tx.size - WsfBufIoCb.tx.out + WsfBufIoCb.tx.in;
|
}
|
|
return count;
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Rx handler.
|
*/
|
/*************************************************************************************************/
|
static void wsfBufIoUartRxHandler(void)
|
{
|
if (WsfBufIoCb.rx.cback)
|
{
|
WsfBufIoCb.rx.cback(WsfBufIoCb.rx.buf[0]);
|
}
|
/* Read next byte. */
|
PalUartReadData(PAL_UART_ID_TERMINAL, WsfBufIoCb.rx.buf, 1);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Tx handler.
|
*/
|
/*************************************************************************************************/
|
static void wsfBufIoUartTxHandler(void)
|
{
|
uint16_t count;
|
|
WSF_CS_INIT(cs);
|
uint32_t lock = WSF_CS_ENTER();
|
|
if (WsfBufIoCb.tx.out + WsfBufIoCb.tx.crt >= WsfBufIoCb.tx.size)
|
{
|
WsfBufIoCb.tx.out = WsfBufIoCb.tx.crt - (WsfBufIoCb.tx.size - WsfBufIoCb.tx.out);
|
}
|
else
|
{
|
WsfBufIoCb.tx.out += WsfBufIoCb.tx.crt;
|
}
|
|
WsfBufIoCb.tx.crt = 0;
|
|
count = wsfBufIoUartTxBufCount();
|
|
if (count != 0)
|
{
|
wsfBufIoUartTxStart(count);
|
}
|
|
WSF_CS_EXIT(lock);
|
}
|
|
/**************************************************************************************************
|
Global Functions
|
**************************************************************************************************/
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Initialize the UART.
|
*
|
* \param pBuf Tx Buffer pointer.
|
* \param size Length of buffer.
|
*
|
* \return memory used.
|
*/
|
/*************************************************************************************************/
|
uint16_t WsfBufIoUartInit(void *pBuf, uint16_t size)
|
{
|
/* Skip initialization if it is already done. */
|
if (WsfBufIoCb.initialized)
|
{
|
return 0;
|
}
|
|
WsfBufIoCb.tx.pBuf = (uint8_t *)pBuf;
|
WsfBufIoCb.tx.size = size;
|
|
PalUartConfig_t cfg;
|
cfg.baud = 115200;
|
cfg.hwFlow = FALSE;
|
cfg.rdCback = wsfBufIoUartRxHandler;
|
cfg.wrCback = wsfBufIoUartTxHandler;
|
|
PalUartInit(PAL_UART_ID_TERMINAL, &cfg);
|
|
/* Start UART RX. */
|
PalUartReadData(PAL_UART_ID_TERMINAL, WsfBufIoCb.rx.buf, 1);
|
|
WsfBufIoCb.initialized = TRUE;
|
return WsfBufIoCb.tx.size;
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Register the UART RX callback.
|
*
|
* \param rxCback Callback function for UART RX.
|
*/
|
/*************************************************************************************************/
|
void WsfBufIoUartRegister(WsfBufIoUartRxCback_t rxCback)
|
{
|
if (rxCback != NULL)
|
{
|
WsfBufIoCb.rx.cback = rxCback;
|
}
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Transmit buffer on UART.
|
*
|
* \param pBuf Buffer to transmit.
|
* \param len Length of buffer in octets.
|
*
|
* \return if write successfully.
|
*/
|
/*************************************************************************************************/
|
bool_t WsfBufIoWrite(const uint8_t *pBuf, uint16_t len)
|
{
|
uint16_t end;
|
uint8_t retValue = TRUE;
|
|
WSF_CS_INIT(cs);
|
|
uint32_t lock = WSF_CS_ENTER();
|
|
/* Check if there is enough space in TX buffer */
|
if ((WsfBufIoCb.tx.size - wsfBufIoUartTxBufCount() >= (uint16_t)len) && (WsfBufIoCb.tx.size > WsfBufIoCb.tx.crt))
|
{
|
/* Compute the space available till the end of the buffer. */
|
end = WsfBufIoCb.tx.size - WsfBufIoCb.tx.in;
|
|
/* Check if overrun should happen. */
|
if (end < len)
|
{
|
/* Copy the bytes till the end of the buffer. */
|
memcpy(WsfBufIoCb.tx.pBuf + WsfBufIoCb.tx.in, pBuf, end);
|
/* Copy the remaining bytes. */
|
memcpy(WsfBufIoCb.tx.pBuf, pBuf + end, len - end);
|
/* Increment input count */
|
WsfBufIoCb.tx.in = len - end;
|
}
|
else
|
{
|
/* Enough space till the end of the buffer. Just copy. */
|
memcpy(WsfBufIoCb.tx.pBuf + WsfBufIoCb.tx.in, pBuf, len);
|
WsfBufIoCb.tx.in += len;
|
}
|
|
if (WsfBufIoCb.tx.in == WsfBufIoCb.tx.size)
|
{
|
WsfBufIoCb.tx.in = 0;
|
}
|
|
/* Check if UART TX is idle. */
|
if (PalUartGetState(PAL_UART_ID_TERMINAL) == PAL_UART_STATE_READY)
|
{
|
/* Start TX */
|
wsfBufIoUartTxStart(len);
|
}
|
}
|
else
|
{
|
retValue = FALSE;
|
}
|
|
WSF_CS_EXIT(lock);
|
|
return retValue;
|
}
|