/**************************************************************************
 *
 * Title: Functions that implement a circular single-reader single-writer
 *        buffer.
 *
 * Filename: circular_buffer.c
 *
 *
 * First used on: MPC5554
 *
 * Compiler:
 *
 * Creation date:		08/15/06
 * Date last modified:	$Author: B04496 $
 *
 * Copyright Freescale Semiconductor Inc
 * 2006 All Rights Reserved
 *
 * Notes :
 * <RELEVANT information only - leave blank if none>
 *
 *
 * Revision History :
 *   $Date: 2006/09/13 20:03:02 $
 *
 *
 *************************************************************************/

#include "RAppID_Blockset.h"

/* Description: Inserts new_item at the head of the buffer.
   Returns: 0 on success, -1 on error */
int add_item(circ_buff_t *buffer_ptr, uint8_t new_item)
{
  /* one empty spot then buffer is full */
  if (((buffer_ptr->head_idx + 1) % (CIRC_BUF_SIZE+1)) == buffer_ptr->tail_idx)
  {
    return -1;
  }
  else
  {
    buffer_ptr->circ_buffer[buffer_ptr->head_idx++] = new_item;
    buffer_ptr->head_idx %= (CIRC_BUF_SIZE+1);
  }

  return 0;
}

/* Description: Removes an item from the tail of the buffer.
   Returns: The item at the tail of the buffer, undefined if empty. */
int16_t remove_item(circ_buff_t *buffer_ptr)
{
  int16_t ret;

  /* buffer is not empty */
  if (buffer_ptr->head_idx != buffer_ptr->tail_idx)
  {
    ret = (int16_t)buffer_ptr->circ_buffer[buffer_ptr->tail_idx++];
    buffer_ptr->tail_idx %= (CIRC_BUF_SIZE+1);
  }
  else
  {
    ret = -1;
  }

  return ret;
}

int add_items(circ_buff_t *buffer_ptr, const uint8_t *pData, uint32_t numItems)
{
  uint32_t i;
  int16_t tmp_data;

  /* If adding more data than buffer size or none, return error. */
  if ((numItems > CIRC_BUF_SIZE) || (numItems == 0))
  {
    return -1;
  }
  /* Head is ahead of tail so check if you will cross the tail. */
  else if (buffer_ptr->head_idx > buffer_ptr->tail_idx)
  {
    if ((((buffer_ptr->head_idx + numItems) % (CIRC_BUF_SIZE+1)) >=
      buffer_ptr->tail_idx) && (((buffer_ptr->head_idx + numItems) %
       (CIRC_BUF_SIZE+1)) < buffer_ptr->head_idx))
    {
      return -1;
    }
  }
  /* Head is behind tail so check if you cross tail */
  else if (buffer_ptr->head_idx < buffer_ptr->tail_idx)
  {
    if ((buffer_ptr->head_idx + numItems) >= buffer_ptr->tail_idx)
    {
      return -1;
    }
  }

  /* Enough space to add all items to buffer. */
  for (i = 0; i < numItems; i++)
  {
    if (((buffer_ptr->head_idx + 1) % (CIRC_BUF_SIZE+1)) == buffer_ptr->tail_idx)
    {
      while (1);
    }

    buffer_ptr->circ_buffer[buffer_ptr->head_idx++] = pData[i];
    buffer_ptr->head_idx %= (CIRC_BUF_SIZE+1);
  }

  return 0;
}

uint32_t is_empty(circ_buff_t *buffer_ptr)
{
  return (buffer_ptr->head_idx == buffer_ptr->tail_idx);
}

uint32_t get_buffer_size(void)
{
  return CIRC_BUF_SIZE;
}

uint32_t get_head_idx(circ_buff_t *buffer_ptr)
{
  return buffer_ptr->head_idx;
}

uint32_t get_tail_idx(circ_buff_t *buffer_ptr)
{
  return buffer_ptr->tail_idx;
}

uint32_t get_data_start_address(circ_buff_t *buffer_ptr)
{
  return (uint32_t)&buffer_ptr->circ_buffer[buffer_ptr->tail_idx];
}

uint32_t get_num_items_to_send(circ_buff_t *buffer_ptr)
{
  uint32_t num_items;

  if (buffer_ptr->head_idx > buffer_ptr->tail_idx)
  {
    num_items = buffer_ptr->head_idx - buffer_ptr->tail_idx;
    buffer_ptr->dma_tail_idx = buffer_ptr->head_idx;
  }
  else if (buffer_ptr->tail_idx > buffer_ptr->head_idx)
  {
    num_items = (CIRC_BUF_SIZE+1) - buffer_ptr->tail_idx;
    buffer_ptr->dma_tail_idx = 0;
  }
  else
  {
    num_items = 0;
    buffer_ptr->dma_tail_idx = buffer_ptr->tail_idx;
  }

  return num_items;
}

void update_tail_idx(circ_buff_t *buffer_ptr)
{
  buffer_ptr->tail_idx = buffer_ptr->dma_tail_idx;
}
