/****************************************************************************/
/* Copyright 2015-2016 MBARI                                                */
/****************************************************************************/
/* Summary  : Ring Buffer Routines for OASIS5 on PIC32MX470F512L            */
/* Filename : buffer.h                                                      */
/* Author   : Robert Herlien (rah)                                          */
/* Project  : OASIS Mooring Replacement (OASIS5)                            */
/* Revision: 1.0                                                            */
/* Created  : 07/13/2015                                                    */
/*                                                                          */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*                                                                          */
/****************************************************************************/
/* Modification History:                                                    */
/* Written by Mike Risi for Respirometer project in 2009                    */
/* Modified by Bob Herlien for SensorNode for xFOCE, May 2013               */
/* 13jul2015 rah - Modified for Oasis5 on PIC32MX                           */
/* 9nov2015 rah - Modified for Oasis5 on PIC24FJ                            */
/* 26jan2016 rah - Re-ported to PIC32MX470                                  */
/****************************************************************************/

#include "GenericTypeDefs.h"
#include "buffer.h"

/****************************************************************************/
/* You may be asking yourself, what's a generic ring buffer library doing	*/
/* in the PIC32 specific directory?  And are these routines thread safe?	*/
/*																			*/
/* These routines are used ONLY to handle the ring buffers for serial I/O	*/
/* on the PIC32.  If they were used generically, no, they're not			*/
/* thread-safe.  But used as intended, they're safe.						*/
/*																			*/
/* Each serial port, and hence buffer, is owned by exactly one thread --	*/
/* the OASIS5 driver thread for that port, which owns its serial semaphore.	*/
/* And for each port, they're used by just 2 entities:  the driver thread	*/
/* and the interrupt handler.  The foreground routines -- serGetByte and	*/
/* serPutByte -- disable the interrupt for that port before manipulating	*/
/* the buffer pointers.  This ensures that foreground and interrupt			*/
/* manipulation of the buffers are mutually exclusive.	Look at serial.c.	*/
/*																			*/
/* One potential hole is the console port, which is used for debugging.		*/
/* It may have a vulnerability to having multiple entities sending serial	*/
/* traffic.  I'll need to look into doing a thread-safe dbg_printf to that	*/
/* port.																	*/
/****************************************************************************/

/************************************************************************/
/* Function    : bufInit                                                */
/* Purpose     : Initialize a ByteBuffer                                */
/* Inputs      : ByteBuffer ptr, data ptr, size of buffer               */
/* Outputs     : None                                                   */
/************************************************************************/
void bufInit(ByteBuffer *bbp, unsigned char *dp, int size)
{
    bbp->startptr = dp;
    bbp->inptr = dp;
    bbp->outptr = dp;
    bbp->endptr = dp + size;
    bbp->size = size;
    bbp->occupied = 0;
}


/************************************************************************/
/* Function    : bufPut                                                 */
/* Purpose     : Put a char into a ByteBuffer                           */
/* Inputs      : Char to put, ByteBuffer ptr                            */
/* Outputs     : TRUE if successful, FALSE if buffer was full           */
/************************************************************************/
int bufPut(unsigned char b, ByteBuffer *bbp)
{
    if (bufIsFullP(bbp))
        return(FALSE);

    *bbp->inptr++ = b;
    bbp->occupied++;

    if (bbp->inptr >= bbp->endptr)
        bbp->inptr = bbp->startptr;
    
    return(TRUE);
}


/************************************************************************/
/* Function    : bufGet                                                 */
/* Purpose     : Get a char from a ByteBuffer                           */
/* Inputs      : Char ptr for resulting byte, ByteBuffer ptr            */
/* Outputs     : TRUE if successful, FALSE if buffer was empty          */
/************************************************************************/
int bufGet(unsigned char *b, ByteBuffer *bbp)
{
    if ( bufIsEmptyP(bbp) )
    {
        *b = 0;
        bufClear(bbp);
        return(FALSE);
    }

    *b = *bbp->outptr++;
    bbp->occupied--;

    if (bbp->outptr >= bbp->endptr)
        bbp->outptr = bbp->startptr;
    
    return(TRUE);
}


/************************************************************************/
/* Function    : bufClear                                               */
/* Purpose     : Clear a ByteBuffer                                     */
/* Inputs      : ByteBuffer ptr                                         */
/* Outputs     : None                                                   */
/************************************************************************/
void bufClear(ByteBuffer *bbp)
{
    bbp->inptr = bbp->startptr;
    bbp->outptr = bbp->startptr;
    bbp->occupied = 0;
}
