
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* file: Stream.h                                                  */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* description: Cross-Platform definition of stream I/O 		   */
/*              routines.                                          */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* Copyright (c) 2018 Acroname Inc. - All Rights Reserved          */
/*                                                                 */
/* This file is part of the BrainStem release. See the license.txt */
/* file included with this package or go to                        */
/* https://acroname.com/software/brainstem-development-kit         */
/* for full license details.                                       */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef _Stream_H_
#define _Stream_H_

#include "aDefs.h"
#include "aError.h"
#include "aFile.h"

/////////////////////////////////////////////////////////////////////
/// Platform Independent Stream Abstraction.

/** \defgroup aStream Stream Interface
 * \ref aStream "aStream.h" provides a platform independent stream abstraction for 
 * common I/O streams. Provides facilities for creating and destroying
 * as well as writing and reading from streams.
 */


/////////////////////////////////////////////////////////////////////
/// Typedef #aStreamRef Opaque reference to stream primitive.
typedef void* aStreamRef;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Low level operation proc defs for I/O streams.  These need to
 * be implimented for new stream types.
 */


/////////////////////////////////////////////////////////////////////
/// \defgroup StreamCallbacks (Stream Implementation Callbacks)
/// @{

/////////////////////////////////////////////////////////////////////
/// Typedef #aStreamGetProc.

/**
 * This callback is defined to read one byte from the concrete stream implementation.
 * \param pData The data Buffer to fill.
 * \param ref Opaque reference to concrete stream implementation.
 *
 * \return Function returns aErr values.
 * \retval aErrNone Successfully read the byte.
 * \retval aErrNotReady No bytes in stream to read.
 * \retval aErrEOF Reached the end of the stream.
 * \retval aErrIO An error encountered reading from stream.
 */
typedef aErr (*aStreamGetProc)(uint8_t* pData, void* ref);


/////////////////////////////////////////////////////////////////////
/// Typedef #aStreamPutProc.

/**
 * This callback is defined to write one byte to the concrete stream implementation.
 * \param pData The data Buffer to write.
 * \param ref opaque reference to concrete stream implementation.
 *
 * \return Function returns aErr values.
 * \retval aErrNone Successfully wrote the byte.
 * \retval aErrIO An error encountered reading from stream.
 */
typedef aErr (*aStreamPutProc)(const uint8_t* pData, void* ref);

/////////////////////////////////////////////////////////////////////
/// Typedef #aStreamDeleteProc.

/**
 * This callback is defined to destroy the concrete stream implementation.
 * \param ref opaque reference to concrete stream implementation.
 *
 * \return Function returns aErr values.
 * \retval aErrNone Successfully destroyed.
 * \retval aErrParam Invalid ref.
 */
typedef aErr (*aStreamDeleteProc)(void* ref);


/////////////////////////////////////////////////////////////////////
/// Typedef #aStreamWriteProc. (Optional)

/**
 * Optional multi-byte write for efficiency, not required..
 * \param pData The pointer to the data to write to the stream.
 * \param nSize The size of the data buffer in bytes.
 * \param ref Opaque reference to concrete stream implementation.
 *
 * \return Function returns aErr values.
 * \retval aErrNone Successfully destroyed.
 * \retval aErrIO An error encountered reading from stream.
 */
typedef aErr (*aStreamWriteProc)(const uint8_t* pData,
                                 const size_t nSize,
                                 void* ref);

////////////////////////////////////////////////////////////////////
/// @}


/////////////////////////////////////////////////////////////////////
/// Enum #aBaudRate.

/**
 * Accepted serial stream baudrates.
 */
typedef enum {
    aBAUD_2400, ///< 2400 baud
    aBAUD_4800, ///< 4800 baud
    aBAUD_9600, ///< 9600 baud
    aBAUD_19200, ///< 19,200 baud
    aBAUD_38400, ///< 38,400 baud
    aBAUD_57600, ///< 57,600 baud
    aBAUD_115200, ///< 115,200 baud
    aBAUD_230400 ///< 230,400 buad
} aBaudRate;

/////////////////////////////////////////////////////////////////////
/// Enum #aSerial_Bits.

/**
 * The accepted number of serial bits per byte.
 */
typedef enum {
    aBITS_8, ///< 8 bits
    aBITS_7 ///< 7 bits
} aSerial_Bits;


/////////////////////////////////////////////////////////////////////
/// Enum #aSerial_Stop_bits.

/**
 * The accepted number of serial stop bits.
 */
typedef enum {
    aSTOP_BITS_1, ///< 1 stop bit
    aSTOP_BITS_2 ///< 2 stop bits
} aSerial_Stop_bits;

#ifdef __cplusplus
extern "C" {
#endif
    
    
    /////////////////////////////////////////////////////////////////////
    /// Base Stream creation procedure.
    
    /**
     * Creates a Stream Reference.
     *
     * \param getProc - Callback for reading bytes from the underlying stream.
     * \param putProc - Callback for writing bytes to the underlying stream.
     * \param writeProc - Optional callback for optimized writing of multiple 
     *                    bytes.
     * \param deleteProc - Callback for safe destruction of underlying resource.
     * \param procRef - opaque reference to the underlying resource,
     *
     * \return Function returns aStreamRef on success and NULL on error.
     */
    aLIBEXPORT aStreamRef aStream_Create(aStreamGetProc getProc,
                                         aStreamPutProc putProc,
                                         aStreamWriteProc writeProc,
                                         aStreamDeleteProc deleteProc,
                                         const void* procRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a file input stream.
    
    /**
     * Creates a file input stream.
     *
     * \param pFilename - The filename and path of the file to read from.
     * \param pStreamRef - The resulting stream accessor for the input file.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrNotFound - The file to read was not found.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateFileInput(const char *pFilename,
                                            aStreamRef* pStreamRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a file output stream.
    
    /**
     * Creates a file output stream.
     *
     * \param pFilename - The filename and path of the file to write to.
     * \param pStreamRef - The resulting stream accessor for the output file.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateFileOutput(const char *pFilename,
                                             aStreamRef* pStreamRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a serial communication stream.
    
    /**
     * Creates a serial stream.
     *
     * \param pPortName - The portname of the serial device.
     * \param nBaudRate - The baudrate to connect to the device at.
     * \param parity - Whether serial parity is enabled.
     * \param bits - The number of bits per serial byte.
     * \param stop - The number of stop bits per byte.
     * \param pStreamRef - The resulting stream accessor for the serial device.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrConnection - The connection was unsuccessful.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateSerial(const char *pPortName,
                                         const aBaudRate nBaudRate,
                                         const bool parity,
                                         const aSerial_Bits bits,
                                         const aSerial_Stop_bits stop,
                                         aStreamRef* pStreamRef);
    
    /////////////////////////////////////////////////////////////////////
    /// Create a serial communication stream - COBS Encoded w/ Checksum
    
    /**
     * Creates a serial transport stream.
     *
     * \param pPortName - The portname of the serial device.
     * \param nBaudRate - The baudrate to connect to the device at.
     * \param parity - Whether serial parity is enabled.
     * \param bits - The number of bits per serial byte.
     * \param stop - The number of stop bits per byte.
     * \param pStreamRef - The resulting stream accessor for the serial device.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrConnection - The connection was unsuccessful.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateSerial_Packetized(const char *pPortName,
        const aBaudRate nBaudRate,
        const bool parity,
        const aSerial_Bits bits,
        const aSerial_Stop_bits stop,
        aStreamRef* pStreamRef);
    
    /////////////////////////////////////////////////////////////////////
    /// Create a TCP/IP socket stream.
    
    /**
     * Creates a TCP/IP socket stream.
     *
     * \param address - The IP4 address of the connection.
     * \param port - The TCP port to connect to.
     * \param pStreamRef - The resulting stream accessor for the TCP connection.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrConnection - The connection was unsuccessful.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateSocket(const uint32_t address,
                                         const uint16_t port,
                                         aStreamRef* pStreamRef);
    


    /////////////////////////////////////////////////////////////////////
    /// Create a client stream

    /**
     * Creates a client socket stream
     *
     * \param address - The IP4 address of the connection.
     * \param port - The port of the server to connect to.
     * \param pStreamRef - The resulting stream accessor for the client connection.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrConnection - The connection was unsuccessful.
     * \retval aErrParam - Bad input paremeter.
     * \retval aErrMemory - Unable to create resources. 
     */
    aLIBEXPORT aErr aStream_CreateClient(const uint32_t address,
                                         const uint16_t port,
                                         aStreamRef* pStreamRef);
    
    /////////////////////////////////////////////////////////////////////
    /// Create a stream accessor for a block of memory.
    
    /**
     * Creates a stream accessor for a block of allocated memory. Reads and
     * Writes like any other stream. The memory stream does not make a copy 
     * of the memory and doesn't free it but rather provides a stream layer to
     * access it.
     *
     * \param pMemory - a pointer to a block of memory.
     * \param size - The size of the block in bytes.
     * \param pStreamRef - The resulting stream accessor for the memory block.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrParam - The memory block is invalid.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateMemory(const aMemPtr pMemory,
                                         const size_t size,
                                         aStreamRef* pStreamRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a stream to a USB device.

    /**
     * Creates a BrainStem link stream to a USB based module.
     *
     * \param serialNum - The BrainStem serial number.
     * \param pStreamRef - The resulting stream accessor for the BrainStem 
     *                     module.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrNotFound - The brainstem device was not found.
     * \retval aErrIO - A communication error occurred.
     */
    aLIBEXPORT aErr aStream_CreateUSB(const uint32_t serialNum,
                                      aStreamRef* pStreamRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a stream buffer.
    
    /**
     * Creates a stream buffer.
     *
     * StreamBuffers are typically used to aggregate a bunch of output
     * into a single pile of bytes.  This pile can then be checked for
     * size or accessed as a single block of bytes using the
     * aStreamBuffer_Get call.  Finally, these bytes can then be read
     * back out of the buffer until it is empty when it will report an
     * error of aErrEOF.  While this stream is thread-safe for different
     * threads doing reads and writes, it is not the best candidate for
     * managing a pipe between threads.  Use the aStream_CreatePipe in
     * that scenario as it can be filled and emptied over and over which
     * is typically the use case for cross-thread pipes. 
     *
     * \param nIncSize - The Increment size to expand the buffer by when it 
     *                   becomes full.
     * \param pBufferStreamRef - The buffer stream resulting from the call.
     * 
     * \return Function returns aErr values.
     * \retval aErrNone - The buffer was successfully created.
     * \retval aErrResource - The resources were not available to create the buffer.
     */
    aLIBEXPORT aErr aStreamBuffer_Create(const size_t nIncSize,
                                         aStreamRef* pBufferStreamRef);
    
    
    
    /////////////////////////////////////////////////////////////////////
    /// Get the contents of the buffer.
    
    /**
     * Get the contents of the buffer.
     *
     * StreamBuffers are typically used to aggregate a bunch of output
     * into a single pile of bytes.  This pile can then be checked for
     * size or accessed as a single block of bytes using the
     * aStreamBuffer_Get call.  Finally, these bytes can then be read
     * back out of the buffer until it is empty when it will report an
     * error of aErrEOF.  While this stream is thread-safe for different
     * threads doing reads and writes, it is not the best candidate for
     * managing a pipe between threads.  Use the aStream_CreatePipe in
     * that scenario as it can be filled and emptied over and over which
     * is typically the use case for cross-thread pipes.
     *
     *
     * \param bufferStreamRef - The buffer stream resulting from the call.
     * \param aSize - The size of the buffered data in bytes.
     * \param ppData - The resulting buffer of the bytes.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - The buffer was successfully created.
     * \retval aErrParam - An invalid stream ref was given.
     */
    aLIBEXPORT aErr aStreamBuffer_Get(aStreamRef bufferStreamRef,
                                      size_t* aSize,
                                      uint8_t** ppData);
    
    /////////////////////////////////////////////////////////////////////
    /// Create a pipe buffered stream.
    
    /**
     * Get the contents of the buffer. Offers a pipe that is thread-safe 
     * for reading and writing between two different contexts.  Returns
     * aErrNotReady when data is not available on reads.  Expands a buffer 
     * internally to hold data when written to until it is read out (FIFO). 
     *
     * \param pBufferStreamRef - The buffered stream to create the pipe out of.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrParam - The bufferStream is invalid.
     */
    aLIBEXPORT aErr aStream_CreatePipe(aStreamRef* pBufferStreamRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Flush the cotents of the buffer.
    
    /**
     * Flushes the content of the buffer into the flushStream.
     *
     * \param bufferStreamRef - The buffered stream to flush.
     * \param flushStream - the stream to flush the buffer into.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - The flush succeeded.
     * \retval aErrParam - The bufferStream is invalid.
     * \retval aErrIO - IO error writing to flushStream.
     */
    aLIBEXPORT aErr aStreamBuffer_Flush(aStreamRef bufferStreamRef,
                                        aStreamRef flushStream);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a Logging stream.
    
    /**
     * Creates a stream which contains an upstream log stream and a downstream
     * log stream. The logging stream logs reads to the upstream log and writes
     * to the downstream log, while passing all data to and from the
     * pLogStreamRef.
     *
     * \param streamToLog - The reference to the stream to log.
     * \param upStreamLog - Log stream for reads.
     * \param downStreamLog - Log stream for writes.
     * \param pLogStreamRef - The logged stream reference.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful creation.
     * \retval aErrParam - The stream to log is invalid.
     * \return aErrIO - A communication error occurred creating the logging stream.
     */
    aLIBEXPORT aErr aStream_CreateLogStream(const aStreamRef streamToLog,
                                            const aStreamRef upStreamLog,
                                            const aStreamRef downStreamLog,
                                            aStreamRef* pLogStreamRef);
    
    
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * Stream Operations... READ and Write FLUSH....                           *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    
    
    /////////////////////////////////////////////////////////////////////
    /// Read a byte array record from a stream.
    
    /**
     * Read a byte array record from a stream.
     *
     * \param streamRef - The reference to the stream to read from.
     * \param pBuffer - byte array buffer to read into.
     * \param length - the length of the read buffer.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful read.
     * \retval aErrMode - The streamRef is not readable.
     * \retval aErrIO - An error occurred reading the data.
     */
    aLIBEXPORT aErr aStream_Read(aStreamRef streamRef,
                                 uint8_t* pBuffer,
                                 const size_t length);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Write a byte array to a Stream.
    
    /**
     * Write a byte array to a Stream.
     *
     * \param streamRef - The reference to the stream to write to.
     * \param pBuffer - byte array to write out to the stream.
     * \param length - the byte array length
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful write.
     * \retval aErrMode - The streamRef is not writable.
     * \retval aErrIO - An error occurred writing the data.
     */
    aLIBEXPORT aErr aStream_Write(aStreamRef streamRef,
                                  const uint8_t* pBuffer,
                                  const size_t length);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Read a byte array record from a stream with a record terminator.
    
    /**
     * Read a byte array record from a stream with a record terminator.
     *
     * \param streamRef - The reference to the stream to read from.
     * \param pBuffer - Byte array buffer to read into.
     * \param lengthRead - The length of the read buffer.
     * \param maxLength - The Maximum record length.
     * \param recordTerminator - The byte array representing the record terminator.
     * \param terminatorLength - The length of the record terminator.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful read.
     * \return aErrMode - The streamRef is not readable.
     * \return aErrIO - An error occurred reading the data.
     */
    aLIBEXPORT aErr aStream_ReadRecord(aStreamRef streamRef,
                                       uint8_t* pBuffer,
                                       size_t* lengthRead,
                                       const size_t maxLength,
                                       const uint8_t* recordTerminator,
                                       const size_t terminatorLength);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Write a byte array with a record terminator to a Stream.
    
    /**
     * Write a byte array with a record terminator to a Stream.
     *
     * \param streamRef - The reference to the stream to write to.
     * \param pBuffer - byte array to write out to the stream.
     * \param bufferLength - the byte array length
     * \param recordTerminator - the byte array representing the record terminator
     * \param terminatorLength - the length of the record terminator.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful write.
     * \retval aErrMode - The streamRef is not writable.
     * \retval aErrIO - An error occurred writing the data.
     */
    aLIBEXPORT aErr aStream_WriteRecord(aStreamRef streamRef,
                                        const uint8_t* pBuffer,
                                        const size_t bufferLength,
                                        const uint8_t* recordTerminator,
                                        const size_t terminatorLength);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Read a null terminated string from Stream.
    
    /**
     * Read a null terminated string from Stream.
     *
     * \param streamRef - The reference to the stream to read from.
     * \param pBuffer - Character array buffer to read into.
     * \param maxLength - The maximum length of the string.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful read.
     * \retval aErrMode - The streamRef is not readable.
     * \retval aErrIO - An error occurred reading the data.
     */
    aLIBEXPORT aErr aStream_ReadCString(aStreamRef streamRef,
                                        char* pBuffer,
                                        const size_t maxLength);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Write a null terminated string.
    
    /**
     * Write a null terminated string.
     *
     * \param streamRef - The reference to the stream to write to.
     * \param pBuffer - character array to write.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful write.
     * \retval aErrMode - The streamRef is not writable.
     * \retval aErrIO - An error occurred writing the data.
     */
    aLIBEXPORT aErr aStream_WriteCString(aStreamRef streamRef,
                                         const char* pBuffer);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Read a null terminated string with a record terminator to pBuffer.
    
    /**
     * Read a null terminated string with a record terminator to pBuffer.
     *
     * \param streamRef - The reference to the stream to read to.
     * \param pBuffer - character array to read to.
     * \param maxLength - The maximum number of characters to read.
     * \param recordTerminator - The record terminator to read to.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful read.
     * \retval aErrMode - The streamRef is not readable.
     * \retval aErrIO - An error occurred reading the data.
     */
    aLIBEXPORT aErr aStream_ReadCStringRecord(aStreamRef streamRef,
                                              char* pBuffer,
                                              const size_t maxLength,
                                              const char* recordTerminator);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Write a null terminated string with a record terminator to the stream.
    
    /**
     * Write a null terminated string with a record terminator to the stream.
     *
     * \param streamRef - The reference to the stream to be written to.
     * \param pBuffer - Null terminated string to write to the stream.
     * \param recordTerminator - The record terminator to write after the contents.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful write.
     * \retval aErrMode - The streamRef is not writable.
     * \retval aErrIO - An error occurred writing the data.
     */
    aLIBEXPORT aErr aStream_WriteCStringRecord(aStreamRef streamRef,
                                               const char* pBuffer,
                                               const char* recordTerminator);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Flush contents of inStream into outStream.
    
    /**
     * Flush the entire current content of the instream into the outstream.
     *
     * \param inStreamRef - The reference to the stream to be flushed into the outstream.
     * \param outStreamRef - The reference to the stream instream is flushed into.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - Successful Flush.
     * \retval aErrMode - The outstream is not writable or instream is not readable.
     * \retval aErrIO - An error occurred flushing the data.
     */
    aLIBEXPORT aErr aStream_Flush(aStreamRef inStreamRef,
                                  aStreamRef outStreamRef);
    
    /////////////////////////////////////////////////////////////////////
    /// Destroy a Stream.
    
    /**
     * Safely destroy a stream and deallocate the associated resources.
     *
     * \param pStreamRef - A pointer to a pointer of a valid streamRef. The StreamRef
     *                     will be set to NULL on successful destruction of the stream.
     *
     * \return Function returns aErr values.
     * \retval aErrNone - The stream was successfully destroyed.
     * \retval aErrParam - If the streamRef is invalid.
     */
    aLIBEXPORT aErr aStream_Destroy(aStreamRef* pStreamRef);
    
#ifdef __cplusplus
}
#endif

#endif /* _Stream_H_ */
