/*
 * Copyright 2017-2020 NXP
 * This software is owned or controlled by NXP and may only be used strictly
 * in accordance with the applicable license terms.  By expressly accepting
 * such terms or by downloading, installing, activating and/or otherwise using
 * the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms.  If you do not agree to
 * be bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software.
 */

#ifndef AUDIO_RINGBUFFER_H_
#define AUDIO_RINGBUFFER_H_

/**
 * @defgroup KL_MODULES_AUDIOSERVICE_RINGBUF Audio ringbuffer
 * @ingroup KL_MODULES_AUDIOSERVICE
 * Audio ringbuffer initializes and uses a Ring buffer for transferring audio between USB and NxH via DMA.
 * This is a sub module of @ref KL_MODULES_AUDIOSERVICE audio
 *
 * @warning
 * This module does not implement a mutex to access the ringbuffer, so it's up to the user to decide whether he needs it.
 * @{
 */

#include <stdint.h>

/**
 * @brief Callback function that gets called when the filling level exceeds its margins.
 * @param Filling the filling value that triggered the callback.
 * @param pCtxt extra context that can be passed along with the callback.
 */
typedef void (*pphRingBuffer_FillingWarningCb_t)(uint32_t Filling, void *pCtxt);

/**
 * @brief Ring buffer configuration.
 */
typedef volatile struct {
    volatile uint8_t *pWritePointer;                    /**< Pointer to the write address of Ring buffer */
    volatile uint8_t *pReadPointer;                     /**< Pointer to the read address of Ring buffer */
    uint32_t StartAddress;                              /**< Initial address of Ring buffer */
    uint32_t EndAddress;                                /**< Ending address of Ring buffer */
    uint32_t BufferSize;                                /**< Size of Ring buffer */
    uint32_t FillingMargin;                             /**< Margin used for the @ref pphRingBuffer_FillingWarningCb_t */
    pphRingBuffer_FillingWarningCb_t pFillingWarningCb; /**< Callback function for the filling warning */
    void *pFillingWarningCbCtxt;                        /**< Extra context that can be passed to the callback */
} phRingBuffer_t;

/**
 * @brief Initialize the ring buffer.
 * @pre Memory should be allocated before calling this function.
 * @param spRingBuffer pointer to the ring buffer.
 * @param pStartAddress pointer to the beginning of the start address.
 * @param BufferSize ring buffer size in bytes.
 */
void audio_ringbuffer_Init(phRingBuffer_t *spRingBuffer, uint8_t *pStartAddress, uint32_t BufferSize);

/**
 * @brief Configure the given callback function to be called when the ring buffer filling margin is
 *        exceeded (overflow or underflow). The given margin is symmetrical (i.e. identical for overflow and underflow).
 * @param spRingBuffer pointer to the ring buffer.
 * @param Margin ring buffer filling margin in bytes to detect overflow or underflow.
 * @param pCb callback function to be called when the margin is exceeded.
 * @param pContext extra context to be passed to the callback function.
 */
void audio_ringbuffer_ConfigureFillingWarning(phRingBuffer_t *spRingBuffer, uint32_t Margin, pphRingBuffer_FillingWarningCb_t pCb,
                                              void *pContext);

/**
 * @brief Write SizeOfDataToWrite of bytes from pDataIn to the spRingBuffer and perform overflow/underflow warning check.
 *
 * @note This function also fills zeros at the LSB of spRingBuffer to convert data from DataInFormat to RingBufferFormat.
 *       Zero filling happens based on the difference between the RingBufferFormat and DataInFormat.
 *       The RingBufferFormat must be greater than or equal to the DataInFormat.
 *
 * @param spRingBuffer pointer to the ring buffer that will be written to .
 * @param pDataIn pointer to the buffer that will be copied from.
 * @param SizeOfDataToWrite size of the data that will be written in bytes.
 * @param DataInFormat data format of pDataIn buffer.
 * @param RingBufferFormat data format of spRingBuffer.
 */
void audio_ringbuffer_Write(phRingBuffer_t *spRingBuffer, uint8_t *pDataIn, uint32_t SizeOfDataToWrite,
                            const uint8_t DataInFormat, const uint8_t RingBufferFormat);

/**
 * @brief Read pDataOut of bytes from the spRingBuffer to the pDataOut and perform overflow/underflow warning check.
 *
 * @param spRingBuffer pointer to the ring buffer that will be read.
 * @param pDataOut pointer to the buffer that will be copied to.
 * @param DataToRead size of the data that will be read in bytes
 */
void audio_ringbuffer_Read(phRingBuffer_t *spRingBuffer, uint8_t *pDataOut, uint32_t DataToRead);

/**
 * @brief Resets the ring buffer to start address
 *
 * @param spRingBuffer pointer to the ring buffer.
 */
void audio_ringbuffer_Reset(phRingBuffer_t *spRingBuffer);

/**
 * @brief Return the current space in use, in bytes.
 *
 * @param spRingBuffer pointer to the ring buffer.
 * @return current space in use (bytes).
 */
uint32_t audio_ringbuffer_GetFilling(phRingBuffer_t *spRingBuffer);

/** @} */

#endif /* AUDIO_RINGBUFFER_H_ */
