/******************************************************************************

           Copyright @2024 - 2044 Shenzhen dcenzix Technology Ltd.

 ******************************************************************************
@file cola_fifo.c
@brief
@author xiexiongwu
@version V1.0
@date 2024年5月29日

******************************************************************************/

/*----------------------------------------------*
 * 包含头文件                                   *
 *----------------------------------------------*/
#include "cola_fifo.h"

/*----------------------------------------------*
 * 宏定义                                 *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 枚举定义                            *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 结构体定义                              *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 全局变量                                     *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 常量定义                                       *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 函数原型说明                                     *
 *----------------------------------------------*/


/**
 *@brief 判断当前是否需要升级
 *
 *@param void
 *@return uint8_t 1:需要升级
 *                0:不需要升级
 *
 */

static __inline uint32_t fifo_length(cola_fifo_t *p_fifo)
{
    return (p_fifo->buf_size - p_fifo->read_pos + p_fifo->write_pos) % p_fifo->buf_size;
}


#define FIFO_LENGTH() fifo_length(p_fifo)  /**< Macro for calculating the FIFO length. */


/**@brief Put one byte to the FIFO. */
static __inline void fifo_put(cola_fifo_t *p_fifo, uint8_t byte)
{
    p_fifo->p_buf[p_fifo->write_pos] = byte;
    p_fifo->write_pos = (p_fifo->write_pos + 1) % p_fifo->buf_size;
}


/**@brief Look at one byte in the FIFO. */
static __inline void fifo_peek(cola_fifo_t *p_fifo, uint16_t index, uint8_t *p_byte)
{
    *p_byte = p_fifo->p_buf[(p_fifo->read_pos + index) % p_fifo->buf_size];
}


/**@brief Get one byte from the FIFO. */
static __inline void fifo_get(cola_fifo_t *p_fifo, uint8_t *p_byte)
{
    fifo_peek(p_fifo, 0, p_byte);
    p_fifo->read_pos = (p_fifo->read_pos + 1) % p_fifo->buf_size;
}


/**@brief Function for initializing the FIFO.
 *
 * @param[out] p_fifo   FIFO object.
 * @param[in]  p_buf    FIFO buffer for storing data. The buffer size must be a power of two.
 * @param[in]  buf_size Size of the FIFO buffer provided. This size must be a power of two.
 *
 * @return     true     If initialization was successful.
 * @return     false    If a NULL pointer is provided as buffer.
 * @return     false    If size of buffer provided is not a power of two.
 */
bool cola_fifo_init(cola_fifo_t *p_fifo, uint8_t *p_buf, uint16_t buf_size)
{
    // Check buffer for null pointer.
    if (p_buf == NULL)
    {
        return false;
    }

    p_fifo->p_buf         = p_buf;
    p_fifo->buf_size 	  = buf_size;
    p_fifo->read_pos      = 0;
    p_fifo->write_pos     = 0;

    return true;
}

/**@brief Function for adding an element to the FIFO.
 *
 * @param[in]  p_fifo   Pointer to the FIFO.
 * @param[in]  byte     Data byte to add to the FIFO.
 *
 * @return     true     If an element has been successfully added to the FIFO.
 * @return     false    If the FIFO is full.
 */
bool cola_fifo_put(cola_fifo_t *p_fifo, uint8_t byte)
{
    if (FIFO_LENGTH() < p_fifo->buf_size)
    {
        fifo_put(p_fifo, byte);
        return true;
    }

    return false;
}

/**@brief Function for getting the next element from the FIFO.
 *
 * @param[in]  p_fifo   Pointer to the FIFO.
 * @param[out] p_byte   Byte fetched from the FIFO.
 *
 * @return     true     If an element was returned.
 * @return     false    If there are no more elements in the queue.
 */

bool cola_fifo_get(cola_fifo_t *p_fifo, uint8_t *p_byte)
{
    if (FIFO_LENGTH() != 0)
    {
        fifo_get(p_fifo, p_byte);
        return 1;
    }

    return 0;

}

bool __inline cola_fifo_is_full(cola_fifo_t *p_fifo)
{   
    if (!p_fifo)
    {
        return false;
    }
    return (((p_fifo->write_pos + 1) % p_fifo->buf_size) == p_fifo->read_pos) ? true : false;
}

bool __inline cola_fifo_is_empty(cola_fifo_t *p_fifo)
{
    if (!p_fifo)
    {
        return false;
    }

    return (p_fifo->write_pos == p_fifo->read_pos) ? true : false;
}


/**@brief Function for looking at an element in the FIFO, without consuming it.
 *
 * @param[in]  p_fifo   		Pointer to the FIFO.
 * @param[out] p_byte_array   	Byte fetched from the FIFO.
 * @param[in]  p_size    		Bytes size fetched from the FIFO.
 * @param[in]  p_offset 		Bytes offset from start point.
 *
 * @return     true         If an element was returned.
 * @return     false        If there are no more elements in the queue, or the index was
 *                                      too large.
 */

bool cola_fifo_peek(cola_fifo_t *p_fifo, uint8_t *p_byte_array, uint32_t  p_size, uint32_t  p_offset)
{
    if (!p_fifo || (0 == p_size) || !p_byte_array)
    {
        return false;
    }
    const uint32_t byte_count    = fifo_length(p_fifo);
    // Check if the FIFO is empty.
    if (0 == byte_count)
    {
        return false;
    }

    if (p_size + p_offset > byte_count)
    {
        return false;
    }

    uint32_t index         = 0;
    // Fetch bytes from the FIFO.
    while (index < p_size)
    {
        fifo_peek(p_fifo, index + p_offset, &p_byte_array[index]);
        index++;
    }


    return true;
}


/**@brief Function for flushing the FIFO.
 *
 * @param[in]  p_fifo   Pointer to the FIFO.
 *
 * @return     none
 */
void cola_fifo_flush(cola_fifo_t *p_fifo)
{
    if (!p_fifo)
    {
        return;
    }

    uint32_t usLen = cola_fifo_length(p_fifo);
    if (usLen > 0)
    {
        cola_fifo_remove(p_fifo, usLen);
    }

}


/**@brief Function for remove bytes from the FIFO.
 *
 * @param[in]  p_fifo   Pointer to the FIFO.
 * @param[in]  p_offset bytes removed from the FIFO.
 *
 * @return     none
 */
void cola_fifo_remove(cola_fifo_t *p_fifo, uint32_t p_offset)
{
    if (!p_fifo)
    {
        return;
    }
    const uint32_t byte_count	 = fifo_length(p_fifo);
    // Check if the FIFO is empty.
    if (0 == byte_count)
    {
        return;
    }

    if (p_offset > byte_count)
    {
        return;
    }


    p_fifo->read_pos = (p_fifo->read_pos + p_offset) % p_fifo->buf_size;
}

/**@brief Function for reading bytes from the FIFO.
 *
 * This function can also be used to get the number of bytes in the FIFO.
 *
 * @param[in]    p_fifo        Pointer to the FIFO. Must not be NULL.
 * @param[out]   p_byte_array  Memory pointer where the read bytes are fetched from the FIFO.
 *                             Can be NULL. If NULL, the number of bytes that can be read in the FIFO
 *                             are returned in the p_size parameter.
 * @param[in] p_size        Address to memory indicating the maximum number of bytes to be read.
 *                             The provided memory is overwritten with the actual number of bytes
 *                             read if the procedure was successful. This field must not be NULL.
 *                             If p_byte_array is set to NULL by the application, this parameter
 *                             returns the number of bytes in the FIFO.
 *
 * @return     true         If the procedure is successful. The actual number of bytes read might
 *                                  be less than the requested maximum, depending on how many elements exist
 *                                  in the FIFO. Even if less bytes are returned, the procedure is considered
 *                                  successful.
 * @return     false        If a NULL parameter was passed for a parameter that must not
 *                                  be NULL.
 * @return     false        If the FIFO is empty.
 */

bool cola_fifo_read(cola_fifo_t *p_fifo, uint8_t *p_byte_array, uint32_t  p_size)
{
    if (!p_fifo || (0 == p_size) || !p_byte_array)
    {
        return false;
    }

    if (cola_fifo_is_empty(p_fifo))
    {
        return false;
    }

    uint32_t index         = 0;
    // Fetch bytes from the FIFO.
    while (index < p_size)
    {
        fifo_get(p_fifo, &p_byte_array[index++]);
    }

    return true;
}

/**@brief Function for writing bytes to the FIFO.
 *
 * This function can also be used to get the available size on the FIFO.
 *
 * @param[in]  p_fifo       Pointer to the FIFO. Must not be NULL.
 * @param[in]  p_byte_array Memory pointer containing the bytes to be written to the FIFO.
 *                          Can be NULL. If NULL, this function returns the number of bytes
 *                          that can be written to the FIFO.
 * @param[in]  p_size     Address to memory indicating the maximum number of bytes to be written.
 *                          The provided memory is overwritten with the number of bytes that were actually
 *                          written if the procedure is successful. This field must not be NULL.
 *                          If p_byte_array is set to NULL by the application, this parameter
 *                          returns the number of bytes available in the FIFO.
 *
 * @return     true       If the procedure is successful. The actual number of bytes written might
 *                               be less than the requested maximum, depending on how much room there is in
 *                               the FIFO. Even if less bytes are written, the procedure is considered
 *                               successful. If the write was partial, the application should use
 *                               subsequent calls to attempt writing the data again.
 * @return     false      If a NULL parameter was passed for a parameter that must not
 *                               be NULL.
 * @return     false      If the FIFO is full.
 *
 */

bool cola_fifo_write(cola_fifo_t *p_fifo, const uint8_t   *p_byte_array, uint32_t  p_size)
{
    //VERIFY_PARAM_NOT_NULL(p_fifo);
    //VERIFY_PARAM_NOT_NULL(p_size);
    if (!p_fifo || (0 == p_size) || !p_byte_array)
    {
        return false;
    }
    
    if (cola_fifo_is_full(p_fifo))
    {
        return false;
    }
    uint32_t       index           = 0;

    //Fetch bytes from the FIFO.
    while (index < p_size)
    {
        fifo_put(p_fifo, p_byte_array[index++]);
    }

    return true;
}


/**@brief Function for the length of the FIFO.
 *
 * @param[in]  p_fifo   Pointer to the FIFO.
 *
 * @return     the length of the FIFO
 */

uint32_t cola_fifo_length(cola_fifo_t *p_fifo)
{
    return fifo_length(p_fifo);
}


