/******************************************************************************
Copyright (c) 2007 Analog Devices, Inc.  All Rights Reserved.  This software is
proprietary and confidential to Analog Devices, Inc. and its licensors.
*******************************************************************************

$Revision: 1.1 $
$Date: 2008/03/27 03:02:10 $
$LastChangedBy: sto $

Project:    Common Components
Title:      Circular Buffer Utility Module
Author:     DWP

Description:
            This module provides utility functions to manage circular byte buffers

References:
            none

******************************************************************************/
#include "circular_buffer.h"

#ifdef USE_USBIO
#include "usb_fileio.h"
#endif

/******************************************************************************
**          #defines
******************************************************************************/


/******************************************************************************
**          Typedefs/Enumerations
******************************************************************************/


/******************************************************************************
**          Local variables
******************************************************************************/


/******************************************************************************
**          Local function declaration
******************************************************************************/


/******************************************************************************
**          Function Definitions
******************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Input buffering
// Reads the input from the specified file pointer.
// Returns the number of bytes read (added to the buffer)
// the emphasis of this function is readability
int fread_cbuffer(cbuffer_t *cbuf, unsigned int num_bytes, FILE *src)
{
    unsigned int fill_index, fill_length, filled=0;
    int gap, size;

    // limit number of bytes to be read to top up the circular buffer 
    fill_length = cbuf->length - cbuf->data_length;
    if (num_bytes > fill_length)
        num_bytes = fill_length;
    
    size = sizeof(unsigned char);
    
    // work out where to fill from
    fill_index = cbuf->data_offset + cbuf->data_length;
    if (fill_index >= cbuf->length) fill_index -= cbuf->length;
    
    if ((fill_index + num_bytes) <= cbuf->length)
    {
        // Simple Fill
        if (num_bytes)
#ifdef USE_USBIO        
            filled = usbio_fread(&(cbuf->base[fill_index]), num_bytes, src);
#else            
            filled = fread(&(cbuf->base[fill_index]), size, num_bytes, src);
#endif

    }
    else
    {
        // Wrapping Fill
        gap = cbuf->length - fill_index;
        // fill at end of the physical buffer
#ifdef USE_USBIO
		filled = usbio_fread(&(cbuf->base[fill_index]), gap, src);
#else        
        filled = fread(&(cbuf->base[fill_index]), size, gap, src);
#endif
        if (filled == gap)
        {
    	    // fill at start of the physical buffer
#ifdef USE_USBIO
            filled += usbio_fread(cbuf->base, num_bytes-gap, src);
#else            
            filled += fread(cbuf->base, size, num_bytes-gap, src);
#endif
        }
    }
    
    cbuf->data_length += filled;
    return filled;
}

///////////////////////////////////////////////////////////////////////////////
// Input buffering
// Fills the circular buffer from the specified file pointer.
// Returns the number of bytes read (added to the buffer)
int fill_cbuffer(cbuffer_t *cbuf, FILE *src)
{
	int bytes_read = 0;
    int read_request;
    
    /* work out how many bytes required to fill the circular buffer */
    read_request = cbuf->length - cbuf->data_length; 
    
#ifdef USE_USBIO	
    /* round the read request to multiple of 4 bytes to workaround USBIO fread bug 
        to avoid corrupting unconsumed input buffer data 
    */
    read_request &= 0xFFFFFFFC; 
#endif    

    if (read_request > 0)
    {
     	bytes_read = fread_cbuffer(cbuf, read_request, src);
 	}
    return (bytes_read);

}

///////////////////////////////////////////////////////////////////////////////
// discards used data by simply marking the used data as empty.
int advance_cbuffer(cbuffer_t *cbuf, unsigned int len)
{

    if (cbuf->data_length > len)
    {
        cbuf->data_length -= len;
        cbuf->data_offset += len;
        while (cbuf->data_offset >= cbuf->length)
        {
            cbuf->data_offset -= cbuf->length;
        }
    }
    else    // gracefully handle too large values of len
    {
        len = cbuf->data_length; // only remove what is available in the buffer
        cbuf->data_length = 0;
        cbuf->data_offset = 0;
    }

    return len;
}

///////////////////////////////////////////////////////////////////////////////
// flushes all data in the buffer.
void flush_cbuffer(cbuffer_t *cbuf)
{
    cbuf->data_offset = 0;
    cbuf->data_length = 0;
}

///////////////////////////////////////////////////////////////////////////////
// initialise circular buffer structure
void initialise_cbuffer(cbuffer_t *cbuf, unsigned char *buffer, unsigned int buf_len)
{
    cbuf->base = buffer;
    cbuf->length = buf_len;
    cbuf->data_offset = 0;
    cbuf->data_length = 0;
}


/*
**
** EOF: $HeadURL: svn://dingofiles.spd.analog.com/audio/trunk/common/demo/framework/BFinUtils/Audio_Player/circular_buffer.c $
**
*/
