/*
 * StmLibrary.C
 *
 * STM Library API Implementation 
 *
 * Copyright (C) 2009, 2010 Texas Instruments Incorporated - http://www.ti.com/ 
 * 
 * 
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>              // The library uses C99 exact-width integer types
#include "StmLibrary.h"
#include "StmSupport.h"


#if 0
//Note: the contents of the handle is private to the library and is subject to change with revision

#ifdef _CIO
struct _STMHandle
{
    FILE *       pLogFileHdl;
    STMBufObj    BufIOInfo;

};
#else
struct _STMHandle
{
    uint32_t ulBaseAddress;
    uint32_t chResolution;
    STMXport_callback pCallBack;
    bool          BufIOEnable;
    bool          optimized_prinf;
    bool *        pUnOptPrintfMap;
#ifndef _COMPACT
    STMBufObj     BufIOInfo;
#endif
    int           BufUsed;
    STMMsgObj*    pHeadMsgObj;
};
#endif
#endif

static bool STMisOpen = false;
#ifdef _CIO

static char * STM_FrmtStringTop; 
static char * STM_FrmtStringHdr;
static char * STM_FrmtStringMsg1; 
static char * STM_FrmtStringMsg;

static char * STM_FrmtStringTop_STDIO = "Master ID  Chan Num  Status                  Message/Data\n";
static char * STM_FrmtStringHdr_STDIO = "%-10.10s   %-3.3d     %-22.22s  ";
static char * STM_FrmtStringMsg1_STDIO = "0x%8.8X\n";
static char * STM_FrmtStringMsg_STDIO = "                                             0x%8.8X\n";

static char * STM_FrmtStringTop_FILEIO = "Master ID,Chan Num,Status,Message,Data\n";
static char * STM_FrmtStringHdr_FILEIO = "%s,%d,%s,";
static char * STM_FrmtStringMsg1_FILEIO = ",0x%8.8X\n";
static char * STM_FrmtStringMsg_FILEIO = ",,,,0x%8.8X\n";
#endif

#if defined(_COMPACT) || defined(_CIO)
// Compact and CIO builds uses a pre-allocated handle object to avoid malloc 
STMHandle STMHandleObj;
#endif

#ifdef _DEBUG
unsigned int STMXport_ByteCnt = 0;
#endif

eSTM_STATUS STMXport_getVersion(STMHandle* pSTMHandle, uint32_t * pSTMLibMajorVersion, uint32_t * pSTMLibMinorVersion)
{
#ifdef _DEBUG
	VALIDATE_NULL_VALUE(pSTMHandle);
	VALIDATE_NULL_VALUE(pSTMLibMajorVersion);
	VALIDATE_NULL_VALUE(pSTMLibMinorVersion);	 
#endif

	*pSTMLibMajorVersion = STMLIB_MAJOR_VERSION;
	*pSTMLibMinorVersion = STMLIB_MINOR_VERSION;	

	return eSTM_SUCCESS;
}

#ifndef _CIO
STMHandle* STMXport_open( STMBufObj * pSTMBufObj, STMConfigObj * pSTMConfigObj)
#else
STMHandle* STMXport_open(STMBufObj * pSTMBufObj)
#endif

{
	STMHandle *pSTMHandle = NULL;

#ifdef _CIO
	if ( NULL == pSTMBufObj) {
	    //Error - CIO version requires buffer object to define filename and master id, return NULL
		return pSTMHandle;
	}
#endif
//#if defined(_COMPACT) && !defined(_CIO)
#if !defined(_DMA) && !defined(_CIO)
	if ( NULL != pSTMBufObj) {
	    //Error - Versions not supporting DMA do not allow opening for Buffered IO, return NULL
		return pSTMHandle;
	}
#endif
	if ( NULL == pSTMConfigObj ) {
        //Error - Must call STMXport_open with a valid pSTMConfigObj pointer.
        return pSTMHandle;
    }
       
    //If interface already open return NULL handle
	if ( false == STMisOpen )  
	{
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO) )
		//Map the pyhsical STM memory map to a virtural address
        void * vSTM_BaseAddress = cTools_memMap(  pSTMConfigObj->STM_BaseAddress, 256*(pSTMConfigObj->STM_ChannelResolution));
        if ( NULL == vSTM_BaseAddress ) {
			return pSTMHandle;	//Return NULL handle on mapping error
		}
#endif
#ifdef _STM
		//Allocate space for interface handle

		pSTMHandle = (STMHandle *) cTools_memAlloc(sizeof(STMHandle));
		if (NULL != pSTMHandle)
		{
			// Save parameters to interface handle
			pSTMHandle->ulBaseAddress =(uint32_t)vSTM_BaseAddress;
            pSTMHandle->chResolution = pSTMConfigObj->STM_ChannelResolution;

//#ifndef _COMPACT
#ifdef _DMA			
			// Decide if blocking or non-blocking
			if ( NULL != pSTMBufObj) {

				//Non-blocking so check pSTMBufObj parameters
				if (    ( 0 == pSTMBufObj->maxBufSize)
					 || ( pSTMBufObj->DMAChan_0 > MAX_DMA_CHANNEL )
					 || ( pSTMBufObj->DMAChan_1 > MAX_DMA_CHANNEL )
					 || ( pSTMBufObj->DMAIrq > MAX_DMA_IRQ ) )
				{
					cTools_memFree ( pSTMHandle );
					return NULL;
				} 

				//save non-blocking parameters to interface handle
				pSTMHandle->BufIOEnable = true;
				pSTMHandle->BufIOInfo =  * pSTMBufObj;
				pSTMHandle->BufUsed = 0;
				pSTMHandle->pHeadMsgObj = NULL;

				if ( true == pSTMHandle->BufIOInfo.usingDMAInterrupt )
				{
					//Set the DMA channel's enable interrupt
                    uint32_t DMA_BaseAddr = pSTMHandle->BufIOInfo.DMA4_BaseAddress;
					* (uint32_t *)DMA_ChIntCntl(pSTMHandle->BufIOInfo.DMAChan_0) = DMA_FRAME_COMPLETE;
					
					//Enable the selected IRQ signal
					* (uint32_t *)DMA_IrqEnable(pSTMHandle->BufIOInfo.DMAIrq) = 1 << pSTMHandle->BufIOInfo.DMAChan_0;

				}

			}
			else 
			{
				//save blocking parameters to interface handle
				pSTMHandle->BufIOEnable = false;
			}
#else
            pSTMHandle->BufIOEnable = false;
#endif
            pSTMHandle->pCallBack = pSTMConfigObj->pCallBack;
            pSTMHandle->optimized_prinf =  pSTMConfigObj->optimized_prinf;
            pSTMHandle->pUnOptPrintfMap = NULL;

			STMisOpen = true;

		} //End of - if (NULL != pSTMHandle)
#endif
#if defined(_COMPACT) && !defined(_CIO)
		//Utilize pre-allocated handle object
		pSTMHandle = &STMHandleObj;
			
		// Save parameters to interface handle
        STMHandleObj.pCallBack = pSTMConfigObj->pCallBack;
		STMHandleObj.ulBaseAddress = (uint32_t)vSTM_BaseAddress;
		STMHandleObj.chResolution = (uint32_t)pSTMConfigObj->STM_ChannelResolution; 
        STMHandleObj.optimized_prinf = false;
        STMHandleObj.pUnOptPrintfMap = NULL;
        

		//Force to blocking mode
		STMHandleObj.BufIOEnable = false;
		STMisOpen = true;
#endif
#ifdef _CIO
		//Utilize pre-allocated handle object
		pSTMHandle = &STMHandleObj;

        //Callbacks disabled for CIO mode
        STMHandleObj.CallBack = 0;
		STMHandleObj.BufIOInfo = * pSTMBufObj;
		if ( NULL == pSTMBufObj->pFileName )
		{
			STMHandleObj.pLogFileHdl = stdout;
			
			STM_FrmtStringTop = STM_FrmtStringTop_STDIO; 
			STM_FrmtStringHdr = STM_FrmtStringHdr_STDIO;
			STM_FrmtStringMsg1 = STM_FrmtStringMsg1_STDIO; 
			STM_FrmtStringMsg = STM_FrmtStringMsg_STDIO;	
		}
		else {		     
			char * fileMode = ( false == pSTMBufObj->fileAppend ) ? "w" : "a";
			STMHandleObj.pLogFileHdl = fopen( pSTMBufObj->pFileName, fileMode );
			if ( NULL == STMHandleObj.pLogFileHdl )
			{
				//Could not open file so return NULL
				return NULL;
			}

			STM_FrmtStringTop = STM_FrmtStringTop_FILEIO; 
			STM_FrmtStringHdr = STM_FrmtStringHdr_FILEIO;
			STM_FrmtStringMsg1 = STM_FrmtStringMsg1_FILEIO; 
			STM_FrmtStringMsg = STM_FrmtStringMsg_FILEIO;
		}
			
		if ( 0 > fprintf(STMHandleObj.pLogFileHdl, STM_FrmtStringTop) )
		{
			//Could not write to file so return NULL
			return NULL;
		}
		
		STMisOpen = true;
#endif
					
	} //End of - if ( false == STMisOpen )

	return pSTMHandle;
}

eSTM_STATUS STMXport_printfV(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, va_list arg_addr)
{
    eSTM_STATUS retStatus = eSTM_SUCCESS;
    retStatus = STM_printfV(pSTMHandle, chNum, pMsgString, arg_addr);
    return retStatus;

}

eSTM_STATUS STMXport_printf(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, ... )
{
#if ( defined(_CIO) || defined(_STM) ) && !defined(_COMPACT)    
    va_list arg_addr;
    eSTM_STATUS retStatus = eSTM_SUCCESS;
    
    va_start(arg_addr, pMsgString);
    retStatus = STM_printfV(pSTMHandle, chNum, pMsgString, arg_addr);
    va_end(arg_addr);
    return retStatus;
#endif
#ifdef _COMPACT
    //This code included in Compact Build
//    return eSTM_ERROR_INVALID_FUNC;
    RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_INVALID_FUNC);
#endif      
}

eSTM_STATUS STM_printfV(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, va_list arg_addr)
{
	eSTM_STATUS returnStatus = eSTM_SUCCESS;
//#ifdef _STM
#if defined(_STM) && !defined(_COMPACT)
	int32_t iHdrWordCnt = 1;					//Minimum is one word 
	int32_t iBufWordCnt = 1;        			//Minimum is one word for formatted string pointer
    int32_t iBufByteCnt = 0;                    //Only used for un-optimized %s case
    int32_t iBufWordCntAdj = 0;                 //Only used for un-optimized %s case
	uint32_t *pOutBuffer;                       //Pointer to STM output buffer
    bool * pMapBuffer;                          //Pointer to a Map Buffer for the un-optimized printf case
	const char* pTemp;

	//////////////////////////////////////////////////////////////////
	// Check all function parameters and return error if necessary  //
	//////////////////////////////////////////////////////////////////
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }
    
	if ( ( NULL == pMsgString ) || ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);	
	} 

	//////////////////////////////////////////////////////////////////
	// Figure out the buffer size required and allocate it          //
	//  on the heap.											    //
	//////////////////////////////////////////////////////////////////
	{
		const char * pConvChar = pMsgString;
		const char * pPrevConvChar = NULL;	
		
		//Scan pMsgString for the number of conversion characters (%)
		while (1) {
			pConvChar = strchr(pConvChar, '%');
			if ( NULL != pConvChar ) 
			{
				bool bExitFlag = true;

				// For the single "%" case - we know there is at least 1 word to save off
				pPrevConvChar = pConvChar;
				iBufWordCnt++;

				//Search for the conversion character
				pTemp = pConvChar;
				bExitFlag = true;
				while (bExitFlag)
				{
					pTemp++;
					if (('\0' != *pTemp) && (NULL != pTemp))
					{
						char formatCode = *pTemp;
						bExitFlag = false;
						switch (formatCode)
						{
							case 'h': case 'd': case'u': case'i': case 'c': case 'o': case 'x': case 'X':
                            case 's':
									bExitFlag = false;
									break;
							case 'l':
							case 'L':
									if (!( 'l' == (char)(*(pTemp+1))
										|| 'f' == (char)(*(pTemp+1)) 
										|| 'e' == (char)(*(pTemp+1))
										|| 'E' == (char)(*(pTemp+1))
										|| 'g' == (char)(*(pTemp+1))
										|| 'G' == (char)(*(pTemp+1)) ) )
									{
										//Not a leagal case so during the second pass we will error out
										//Don't need to repeat the code here.
										bExitFlag = false;
										break;
									}
									// All valid double and uint32_t uint32_t cases fall through
							case 'e': case 'f': case 'g': case 'E': case 'F': case 'G': 
									/* Float will be treated as double (64 bits) in va_arg macro */
									iBufWordCnt++;
									bExitFlag = false;
									break;
							case '%':
									if (( pTemp - pPrevConvChar ) == 1 )
									{
										//Double '%' case
										pPrevConvChar = NULL; 
										iBufWordCnt--;	
									}
									bExitFlag = false;
									break;		
						}/* end of switch */
					}/* if  */
					else break; //Reached the end of the conversion string
				}/* while */

				pConvChar = pTemp++;
			}
			else break;		
		}
		 
		//Add room for the header. If number of words for message > OST_SMALL_MSG then 2 words needed, else 1 word needed 
		iHdrWordCnt += ( iBufWordCnt > OST_SMALL_MSG ) ? 1 : 0;
		iBufWordCnt += iHdrWordCnt;  

		//If buffered IO need to check the buffer accounting to make sure there is enough heap
		if ( true == pSTMHandle->BufIOEnable ) 
		{
			if ( (pSTMHandle->BufUsed + (iBufWordCnt * sizeof(uint32_t))) > pSTMHandle->BufIOInfo.maxBufSize )
			{
				RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_BUF_ALLOCATION);
			}	
		}

		//Allocate enough memory for both the header and the message
		pOutBuffer = (uint32_t*) cTools_memAlloc(iBufWordCnt * sizeof(uint32_t));
		if (NULL == pOutBuffer)
		{
			RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_HEAP_ALLOCATION);
		}

		if ( true == pSTMHandle->BufIOEnable ) 
		{
			pSTMHandle->BufUsed += iBufWordCnt * sizeof(uint32_t);
		}
  
        //If printf optimization is disabled we must create a map to
        //indicate where the %s pointers are in the message list 
        if ( false == pSTMHandle->optimized_prinf )      
        {
            pMapBuffer = (bool *) cTools_memAlloc(iBufWordCnt * sizeof(bool));
            if (NULL == pMapBuffer)
            {
                cTools_memFree(pOutBuffer);
                RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_HEAP_ALLOCATION);
            }
            
            pSTMHandle->pUnOptPrintfMap = pMapBuffer;
            
        }

	}
	//////////////////////////////////////////////////////////////////
	// Put format string values in msg buffer                       //
	//////////////////////////////////////////////////////////////////
	{
		const char* pTemp;
		uint32_t  *pOutBufTemp, *pBufPtr, *tempPtr;	
		int32_t  tempArgValueInt;
		uint32_t  tempArgValueUint;
		uint64_t tempArgValue64;
		double tempArgValueDouble;
		char bExitFlag = 1;
        bool * pMapBufferTmp = pMapBuffer;
        
        if ( false == pSTMHandle->optimized_prinf )
        {
             *pMapBufferTmp++ = false;          // OST header is not %s 
             if ( 1 < iHdrWordCnt )
                *pMapBufferTmp++ = false;       // And the count word if present
             *pMapBufferTmp++ = false;          // Format string is not %s 
        }
         
		//Offset the header
		pOutBufTemp = pOutBuffer + iHdrWordCnt; 

		pBufPtr = pOutBufTemp;		
		pTemp = pMsgString;

		/* store the address of string pointer as the first element in output buffer */
		*pBufPtr = (uint32_t)pMsgString; 
		pBufPtr++;

		/* now walk though the remaining string. The end of string should be a " symbol as well */
		while (('\0' != *pTemp) && (NULL != pTemp))
		{
			if ('%' == *pTemp)
			{
				bExitFlag = 1;
				returnStatus = eSTM_ERROR_STRING_FORMAT;
				while (bExitFlag)
				{
					pTemp++;
					if (NULL != pTemp)
					{
						char formatCode = (char)(*pTemp);
						bExitFlag = 0;
						switch (formatCode)
						{
							//int (32-bits) cases
							case 'h':
									//The format conversion promotes shorts to ints
									//Fall through to the next case for processing
									if ( !( 'd' == (char)(*(pTemp+1))
										 || 'i' == (char)(*(pTemp+1))
										 || 'o' == (char)(*(pTemp+1))
									     || 'u' == (char)(*(pTemp+1))
									     || 'x' == (char)(*(pTemp+1))
									     || 'X' == (char)(*(pTemp+1))  ) ) 							
									{
										// Must be an un-supported format so error out
										break;
									}
									//Valid int case so fall through
							case 'd': case'u': case'i': case 'c': case 'o': case 'x': case 'X':
                            case 's':
									tempArgValueInt = va_arg(arg_addr,int);
									*pBufPtr = (uint32_t)tempArgValueInt;

                                    //For the un-optimized case we need to fill in the %s map
                                    //and figure out how many bytes are in the %s string so we
                                    // can adjust the OST header byte count.
                                    if ( false == pSTMHandle->optimized_prinf )
                                    {
                                        if ( 's' == formatCode ) { 
                                            * pMapBufferTmp++ = true;
                                            iBufWordCntAdj++;
                                            iBufByteCnt += strlen((char *)*pBufPtr)+1;
                                        }   
                                        else
                                        {
                                            * pMapBufferTmp++ = false;
                                        }
                                    }                                    

									pBufPtr++;								
									returnStatus = eSTM_SUCCESS;

									break;
							//uint32_t (32-bit) & uint32_t uint32_t cases
							case 'l':
						
									/* this is the uint32_t data type (32 bits) */
									if (    'd' == (char)(*(pTemp+1))
										 || 'i' == (char)(*(pTemp+1))
										 || 'o' == (char)(*(pTemp+1))
									     || 'u' == (char)(*(pTemp+1))
									     || 'x' == (char)(*(pTemp+1))
									     || 'X' == (char)(*(pTemp+1))  )							
									{
										tempArgValueUint = va_arg(arg_addr,uint32_t);
										*pBufPtr = tempArgValueUint;
										pBufPtr++;
										returnStatus = eSTM_SUCCESS;
                                        
                                        //for the un-optimized case we need to fill in the %s map
                                        if ( false == pSTMHandle->optimized_prinf )
                                        {
                                            *pMapBufferTmp++ = false;   
                                        }  
                                        
									}
									if ( 'l' == (char)(*(pTemp+1)) )
									{
										tempArgValue64 = va_arg(arg_addr,uint64_t);
										tempPtr = (uint32_t*)&tempArgValue64;
										*pBufPtr++ = *tempPtr++;
#ifdef C55XP_STM
										//for DSPs the uint32_t uint32_t type is 40 bits
										*pBufPtr++ = 0x000000FF & *tempPtr;
#else 
										*pBufPtr++ = *tempPtr;
#endif
										returnStatus = eSTM_SUCCESS;
                                        
                                        //for the un-optimized case we need to fill in the %s map
                                        if ( false == pSTMHandle->optimized_prinf )
                                        {
                                            *pMapBufferTmp++ = false;
                                            *pMapBufferTmp++ = false;   
                                        }                                          
                                        											
									} 
									//Fall through and test %lf ... cases which are questionable for ANSI C
							//double ( 64-bits only) cases
							case 'L':
									/* this is the double data type (64 bits)*/
									if ( !( 'f' == (char)(*(pTemp+1))
									     || 'e' == (char)(*(pTemp+1))
									     || 'g' == (char)(*(pTemp+1))
									     || 'E' == (char)(*(pTemp+1))
									     || 'G' == (char)(*(pTemp+1))) )

									{
										// Must be an un-supported format so error out
										break;
									}
									//Valid double case so fall through
							case 'e': case 'f': case 'g': case 'E': case 'G': 
									/* Float will be treated as double (64 bits) in va_arg macro */
									tempArgValueDouble = va_arg(arg_addr,double);
									tempPtr = (uint32_t*)&tempArgValueDouble;
									
									//TI Compiler pointing to MS word first
									tempArgValueUint = *tempPtr++;
									*pBufPtr++ = *tempPtr;
									*pBufPtr++ = tempArgValueUint;

									returnStatus = eSTM_SUCCESS;
                                    
                                    //For the un-optimized case we need to fill in the %s map
                                    if ( false == pSTMHandle->optimized_prinf )
                                    {
                                        *pMapBufferTmp++ = false;
                                        *pMapBufferTmp++ = false;   
                                    }   

									break;

							//Cases we skip
							case '.': case '+': case '-': case ' ': case '#': case '*':
							case '0': case '1': case '2': case '3': case '4': 
							case '5': case '6': case '7': case '8': case '9': 
									 /* skip these formatting characters. */
									 bExitFlag = 1;
									 returnStatus = eSTM_SUCCESS;
									 break;
							case '%':
									 bExitFlag = 1;
									 break;		
						}/* end of switch */
					}/* if  */
				}/* while */
				/* return failure immediately if the number of variables do not match */
				if (returnStatus != eSTM_SUCCESS)
				{

                    if ( false == pSTMHandle->optimized_prinf )
                    {
                        cTools_memFree(pMapBuffer);   
                    } 
					cTools_memFree(pOutBuffer);
					RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);
				}
			}
			pTemp++;
		}/* end of while loop */
	}

	//////////////////////////////////////////////////////////////////
	// Add the header and dump to STM module                        //
	//////////////////////////////////////////////////////////////////
	if (returnStatus == eSTM_SUCCESS)
	{
		int32_t bytesInHeader;
		uint32_t msgByteCount = (iBufWordCnt - iHdrWordCnt) * STM_WORD_SIZE; 	
        uint32_t protocol = ( false == pSTMHandle->optimized_prinf ) ? OST_PROTOCOL_PRINTF_UNOPTIMIZED: OST_PROTOCOL_PRINTF;

        if ( false == pSTMHandle->optimized_prinf )
        {
            //Adjust the msgByteCount by the number of bytes in each %s string.
            //Note: We still pass the original iBufWordCnt to STM_putBufCPU() because
            //      this number is used to walk the %s map buffer (pMapBuffer)
            msgByteCount -= (iBufWordCntAdj * STM_WORD_SIZE);
            msgByteCount += iBufByteCnt;
        }

        Build_OST_Header(protocol, msgByteCount, (uint32_t*)pOutBuffer, &bytesInHeader);

#ifdef _DMA
		if ( true == pSTMHandle->BufIOEnable ) 
		{
		    //Non-blobking case use the DMA
			bool DMASingleAccessMode = false;
			returnStatus = STM_putDMA(pSTMHandle, chNum, pOutBuffer, iBufWordCnt, eWord, DMASingleAccessMode, pSTMHandle->pCallBack);
		}
		else
#endif
		{
			//Blocking case, ok to use the CPU
			returnStatus = STM_putBufCPU(pSTMHandle, chNum, NULL, 0, pOutBuffer, iBufWordCnt, eWord);
			cTools_memFree(pOutBuffer);
            
            if ( false == pSTMHandle->optimized_prinf )
            {
                cTools_memFree(pMapBuffer);
                pSTMHandle->pUnOptPrintfMap = NULL;
            }
		}					
	}
	
#endif
#ifdef _COMPACT
	//This code included in Compact Build
	returnStatus =  eSTM_ERROR_INVALID_FUNC;
#endif
#if defined(_CIO) && !defined(_COMPACT)

	if (   ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_printf(...)" ) )
	    || ( 0 > vfprintf(pSTMHandle->pLogFileHdl, pMsgString, arg_addr) )
		|| ( 0 > fprintf (pSTMHandle->pLogFileHdl, "\n") ) )
	{
	 	returnStatus = eSTM_ERROR_CIO_ERROR;
	}
       
#endif

    RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);
}

eSTM_STATUS STMXport_putMessage(STMHandle* pSTMHandle, int32_t chNum, const char* pMsg, int32_t iMsgByteCount)
{ 
	eSTM_STATUS returnStatus = eSTM_SUCCESS;

//#ifdef _STM
#if defined(_STM) && !defined(_COMPACT)
#ifdef _DMA
	if ( true == pSTMHandle->BufIOEnable )
	{

		int32_t iHdrWordCnt = 1;					//Minimum is one word 
		int32_t iBufWordCnt = iMsgByteCount/eWord;  //Minimum is one word for formatted string pointer
		int32_t bytesInHeader = 0;
		uint32_t * pOutBuf;
		uint32_t * pOutBufTemp;
		bool oddWordFlag = false;
		bool DMASingleAccessMode = false;

		//Check for extra bytes
		if ( ( iMsgByteCount % eWord ) > 0 ) {
			 iBufWordCnt++;
			 oddWordFlag = true;
		}
		iHdrWordCnt += ( iMsgByteCount > OST_SMALL_MSG ) ? 1 : 0;
		iBufWordCnt += iHdrWordCnt;

		//make sure we will not exceed our heap quota
		if ( (pSTMHandle->BufUsed + (iBufWordCnt * sizeof(uint32_t))) > pSTMHandle->BufIOInfo.maxBufSize )
		{
			RETURN_CALLBACK(pSTMHandle->pCallBack,eSTM_ERROR_BUF_ALLOCATION);
		}	

		pOutBuf = (uint32_t * )cTools_memAlloc(iBufWordCnt*eWord);
		if (NULL == pOutBuf)
		{
			RETURN_CALLBACK(pSTMHandle->pCallBack,eSTM_ERROR_HEAP_ALLOCATION);
		}

		pSTMHandle->BufUsed += iBufWordCnt * sizeof(uint32_t);

		//Initialize the last word in the buffer to zero
		if ( true == oddWordFlag )
		{
			pOutBuf[iBufWordCnt-1] = 0;
		}

		Build_OST_Header((uint32_t)OST_PROTOCOL_BYTESTREAM, iMsgByteCount, pOutBuf, &bytesInHeader);
		pOutBufTemp = pOutBuf + iHdrWordCnt;
		Compose_OST_MSG(pMsg, iMsgByteCount, NULL, 0, (char *)pOutBufTemp);

		returnStatus = STM_putDMA(pSTMHandle, chNum, pOutBuf, iBufWordCnt, eWord, DMASingleAccessMode, pSTMHandle->pCallBack);

	}
	else
#endif
	{
		int32_t bytesInHeader = 0;
		uint32_t  OST_Header[2]={0};

		Build_OST_Header((uint32_t)OST_PROTOCOL_BYTESTREAM, iMsgByteCount, (uint32_t*)OST_Header, &bytesInHeader);
		returnStatus = STM_putMsgCPU(pSTMHandle, chNum, (void *)OST_Header, bytesInHeader, (void *)pMsg, iMsgByteCount);

	}

#endif
#ifdef _COMPACT 
	//This code included in Compact Build
	returnStatus =  eSTM_ERROR_INVALID_FUNC;	
#endif

//    RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

#if defined(_CIO) && !defined(_COMPACT)
	{
		int32_t fprintfErr = 0;
		uint32_t data;
		bool firstTime = true;
		const char * pMsgTmp = pMsg;

		if ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_putMsg(...)") )
		{
			returnStatus = eSTM_ERROR_CIO_ERROR;
		}

        do 
		{  
			data = (0 < iMsgByteCount--) ? *pMsgTmp++ : 0;
			data |= (0 < iMsgByteCount--) ? *pMsgTmp++ << 8 : 0;
			data |= (0 < iMsgByteCount--) ? *pMsgTmp++ << 16: 0;
			data |= (0 < iMsgByteCount--) ? *pMsgTmp++ << 24: 0;

			if ( true == firstTime )
			{
				fprintfErr = fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg1, data );
			}
			else
			{
				fprintfErr = fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg, data );
			}
			if ( 0 > fprintfErr )
			{
				returnStatus = eSTM_ERROR_CIO_ERROR;
				break;
			}
			firstTime = false;
		}
		while ( 0 < iMsgByteCount); 

	}

//	RETURN_CALLBACK(pCallBack,returnStatus);
#endif
    return returnStatus;
}

eSTM_STATUS STMXport_putMsg(STMHandle* pSTMHandle, int32_t chNum, const char* pMsg, int32_t iMsgByteCount)
{ 
    eSTM_STATUS returnStatus = eSTM_SUCCESS;

    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }
    
    if ( ( NULL == pMsg ) || ( 0 == iMsgByteCount ) 
         || ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
    {
        RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);    
    }

    returnStatus = STMXport_putMessage(pSTMHandle, chNum, pMsg, iMsgByteCount);
    RETURN_CALLBACK(pSTMHandle->pCallBack,returnStatus);
}

eSTM_STATUS STMExport_putMeta(STMHandle* pSTMHandle, const char* pMsg, int32_t iMsgByteCount)
{     
    eSTM_STATUS returnStatus = eSTM_SUCCESS;
    int32_t chNum = 255;
    
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }
    
    if ( ( NULL == pMsg ) || ( 0 == iMsgByteCount ) )
    {
        RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);    
    }

    returnStatus = STMXport_putMessage(pSTMHandle, chNum, pMsg, iMsgByteCount);
    RETURN_CALLBACK(pSTMHandle->pCallBack,returnStatus);
}

eSTM_STATUS STMXport_putBuf(STMHandle* pSTMHandle, int32_t chNum, void* pDataBuf, eSTMElementSize elementSize, int32_t elementCount)
{
	uint32_t bufAlignment;
	eSTM_STATUS returnStatus = eSTM_SUCCESS;

    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

	if ( ( NULL == pDataBuf ) || ( 0 == elementCount ) 
	     || ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

	//Check address alignment
	bufAlignment = AddressAlignmentChecker((uint32_t)pDataBuf);
	switch (elementSize)
	{
		case eShort:
			if ( ( eByteAlign == bufAlignment) || ( eShortAndByteAlign ==  bufAlignment) )
			{
				RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
			}
			break;
		case eWord:
			if ( ( eByteAlign == bufAlignment) || ( eShortAndByteAlign ==  bufAlignment) || ( eShortAlign == bufAlignment ) )
			{
				RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
			}
			break;
	} 

//#ifdef _STM
//#if defined(_STM) && !defined(_COMPACT)
#if defined(_STM) && defined(_DMA)
	if ( true == pSTMHandle->BufIOEnable )
	{
		int32_t iHdrByteCnt = eWord;
		int32_t msgByteCount = elementSize * elementCount;								//Minimum is one word 
		int32_t iBufByteCnt = msgByteCount;     
		int32_t bytesInHeader = 0;
		int32_t numElements = 0;
		uint32_t * pOutBuf;
		uint32_t * pOutBufTemp;
		bool DMASingleAccessMode = true;

		iHdrByteCnt += ( iBufByteCnt > OST_SMALL_MSG ) ? eWord : 0;
		iBufByteCnt += iHdrByteCnt;

		//make sure we will not exceed our heap quota
		if ( (pSTMHandle->BufUsed + iBufByteCnt) > pSTMHandle->BufIOInfo.maxBufSize )
		{
			RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_BUF_ALLOCATION);
		}	

		pOutBuf = (uint32_t * )cTools_memAlloc(iBufByteCnt);
		if (NULL == pOutBuf)
		{
			RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_HEAP_ALLOCATION);
		}

		pSTMHandle->BufUsed += iBufByteCnt;

		Build_OST_Header((uint32_t)OST_PROTOCOL_MSGSTREAM, msgByteCount, pOutBuf, &bytesInHeader);
		pOutBufTemp = (uint32_t *)((char *)pOutBuf + iHdrByteCnt);
		Compose_OST_MSG(pDataBuf, msgByteCount, NULL, 0, (char *)pOutBufTemp);

		numElements = elementCount + iHdrByteCnt/elementSize;		
		returnStatus = STM_putDMA(pSTMHandle, chNum, pOutBuf, numElements, elementSize, DMASingleAccessMode, pSTMHandle->pCallBack);

	}
	else
#endif
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO) )
	{

		register uint32_t msgByteCount = elementSize * elementCount;
		register int32_t bytesInHeader = 0;
		register uint32_t OST_Header1 = 0;
		uint32_t  OST_Header2[2]={0,0};

		if ( msgByteCount < OST_SHORT_HEADER_LENGTH_LIMIT )
		{
			OST_Header1 = Build_CompactOST_Header((uint32_t)OST_PROTOCOL_MSGSTREAM, msgByteCount );
			bytesInHeader = 4;
			returnStatus = STM_putBufCPU(pSTMHandle, chNum, (void *) OST_Header1, bytesInHeader, pDataBuf, elementCount, elementSize);		

		}
		else {
			Build_ExtendedOST_Header((uint32_t)OST_PROTOCOL_MSGSTREAM, msgByteCount, OST_Header2);
			bytesInHeader = 8;
			returnStatus = STM_putBufCPU(pSTMHandle, chNum, (void *) OST_Header2, bytesInHeader, pDataBuf, elementCount, elementSize);		
		}
	}
#endif
#ifdef _CIO
	{
		int32_t fprintfErr = 0;
		int32_t iElementIndex;
		uint32_t data=0;
		bool firstTime = true;
		unsigned char * pBufByte = pDataBuf;
		uint16_t * pBufShort = pDataBuf;
		uint32_t * pBufInt = pDataBuf;

		if ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_putBuf(...)") )
		{
			returnStatus = eSTM_ERROR_CIO_ERROR;
		}

		for (iElementIndex = 0; iElementIndex < elementCount; iElementIndex++)
		{
			switch (elementSize)
			{

				case eByte:
					data = *pBufByte++;
					break;

				case eShort:
					data = *pBufShort++;
					break;

				case eWord:
					data = *pBufInt++;
					break;	
			} //End of switch

			if ( true == firstTime )
			{
				fprintfErr = fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg1, data );
			}
			else
			{
				fprintfErr = fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg, data );
			}
			if ( 0 > fprintfErr )
			{
				returnStatus = eSTM_ERROR_CIO_ERROR;
				break;
			}
			firstTime = false;


		} //End of for
	}
#endif
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}


// Warning - Blocking function only, No callback support
// Optimized to send a single word msg (OST Header + 32-bit data) as fast as possible
eSTM_STATUS STMXport_putWord(STMHandle* pSTMHandle, int32_t chNum, uint32_t data)
{

	eSTM_STATUS returnStatus = eSTM_SUCCESS;
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_MSGSTREAM | 4;

	//Check for errors
	if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }
    
    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

#ifdef _DEBUG
    STMXport_ByteCnt += 8;
#endif
	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;

	//Xport the Data
	*((uint32_t *) ulEndAddress) = data;
#endif
#ifdef _CIO
		if (  ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_putWord(...)") )
			||( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg1, (uint32_t)data ) ) )
		{
			returnStatus = eSTM_ERROR_CIO_ERROR;
		}	
#endif
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}

eSTM_STATUS STMXport_putShort(STMHandle* pSTMHandle, int32_t chNum, uint16_t data)
{
	eSTM_STATUS returnStatus = eSTM_SUCCESS;
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_MSGSTREAM | 4;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }
    	
    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}
    
#ifdef _DEBUG
    STMXport_ByteCnt += 6;
#endif
	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;

	//Xport the Data
	*((unsigned short *) ulEndAddress) = data;
#endif
#ifdef _CIO
		if (  ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_putShort(...)") )
			||( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg1, (unsigned short)data ) ) )
		{
			returnStatus = eSTM_ERROR_CIO_ERROR;
		}	
#endif
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);


}

eSTM_STATUS STMXport_putByte(STMHandle* pSTMHandle, int32_t chNum, uint8_t data)
{

	eSTM_STATUS returnStatus = eSTM_SUCCESS;

#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_MSGSTREAM | 4;


	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

#ifdef _DEBUG
    STMXport_ByteCnt += 5;
#endif
	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;

	//Xport the Data
	*((unsigned char *) ulEndAddress) = data;
#endif
#ifdef _CIO
		if (  ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_putByte(...)") )
			||( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringMsg1, (unsigned char)data ) ) )
		{
			returnStatus = eSTM_ERROR_CIO_ERROR;
		}	
#endif
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}

eSTM_STATUS STMXport_logMsg(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, ...)
{
	eSTM_STATUS returnStatus = eSTM_SUCCESS;
//#ifdef _STM
#if defined(_STM) && !defined(_COMPACT)
	register volatile uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF;

	char firstTime = '0';
	char * pLastConvChar = &firstTime;
	const char * pConvChar = pMsgString;
	int iBufWordCnt = 0;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Figure out the number of variables in the format string
	while ( (pConvChar = strchr(pConvChar, '%')) != NULL) {

		if ( pLastConvChar+1 != pConvChar ) {
			pLastConvChar = (char *)pConvChar;		
			iBufWordCnt++;

		}
		else {
			//Duplicate % so start over
			pLastConvChar = &firstTime;
			//Must remove first % since there is a duplicate
			iBufWordCnt--;
		}
		pConvChar++;

	}

	//Add one for the format string
	iBufWordCnt++;

#ifdef _DEBUG
    STMXport_ByteCnt += (1+iBufWordCnt)*4;
#endif

	//Check that the format string plus the number of variables do not exceed the OST header limit
	if ( iBufWordCnt < OST_SHORT_HEADER_LENGTH_LIMIT) {
		 OST_Header |= iBufWordCnt;
	} 
	else {
		returnStatus = eSTM_ERROR_PARM;
	}

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;	


	if ( 1 == iBufWordCnt ) {

		//Xport the Data
		*((uint32_t *) ulEndAddress) = (uint32_t)pMsgString;
	}
	else {
		va_list arg_addr;		
		int argValue;
		 
		va_start(arg_addr, pMsgString);
		
		//Export the pointer to the format string and adjust iBufWordCnt
		*((uint32_t *) ulMsgAddress) = (uint32_t)pMsgString;
		iBufWordCnt--;

		if ( iBufWordCnt > 1 ) {
			do {
				argValue = va_arg(arg_addr,int);
				*((uint32_t *) ulMsgAddress) = argValue;
			} while (--iBufWordCnt != 1);
		}
		
		//One last word to transfer to the end address
		argValue = va_arg(arg_addr,int);
		*((uint32_t *) ulEndAddress) = argValue;

		va_end(arg_addr);
	}
	
#endif
#ifdef _COMPACT
	//This code included in Compact Build
	returnStatus =  eSTM_ERROR_INVALID_FUNC;	
#endif

    RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

#if defined(_CIO) && !defined(_COMPACT)
	va_list args;

	va_start(args, pMsgString);
	if (   ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_logMsg(...)") )
	    || ( 0 > vfprintf(pSTMHandle->pLogFileHdl, pMsgString, args) )
	    || ( 0 > fprintf (pSTMHandle->pLogFileHdl, "\n") ) )
	{
		returnStatus = eSTM_ERROR_CIO_ERROR;
	}
	va_end(args);
	 
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);
    
#endif
}

#ifndef _INLINE
eSTM_STATUS STMXport_logMsg0(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString)
{

	eSTM_STATUS returnStatus = eSTM_SUCCESS;
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF | 1;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

#ifdef _DEBUG
    STMXport_ByteCnt += 8;
#endif

	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;	

	//Xport the Data
	*((uint32_t *) ulEndAddress) = (uint32_t)pMsgString;
#endif
#ifdef _CIO
	fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_logMsg0(...)");
	fprintf (pSTMHandle->pLogFileHdl, pMsgString );
	fprintf (pSTMHandle->pLogFileHdl, "\n");
#endif	
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}
#endif

eSTM_STATUS STMXport_logMsg1(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, uint32_t data)
{
	eSTM_STATUS returnStatus = eSTM_SUCCESS;
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register volatile uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF | 2;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

#ifdef _DEBUG
    STMXport_ByteCnt += 12;
#endif

	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;	

	//Xport the Data
	*((uint32_t *) ulMsgAddress) = (uint32_t)pMsgString;

	*((uint32_t *) ulEndAddress) = (uint32_t)data;
#endif
#ifdef _CIO
	if (   ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_logMsg1(...)") )
		|| ( 0 > fprintf (pSTMHandle->pLogFileHdl, pMsgString, data ) )
		|| ( 0 > fprintf (pSTMHandle->pLogFileHdl, "\n") ) )
	{
		returnStatus = eSTM_ERROR_CIO_ERROR;
	}
#endif	
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}

eSTM_STATUS STMXport_logMsg2(STMHandle* pSTMHandle, int32_t chNum, const char* pMsgString, uint32_t data0, uint32_t data1)
{
	eSTM_STATUS returnStatus = eSTM_SUCCESS;
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
	register volatile uint32_t ulMsgAddress = 0;
	register uint32_t ulEndAddress = 0;
	register uint32_t OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF | 3;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

    if ( ( chNum < 0 ) || ( chNum > STM_MAX_CHANNEL ) )
	{
		RETURN_CALLBACK(pSTMHandle->pCallBack, eSTM_ERROR_PARM);
	}

#ifdef _DEBUG
    STMXport_ByteCnt += 16;
#endif

	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;	

	//Xport the Data
	*((uint32_t *) ulMsgAddress) = (uint32_t)pMsgString;

	*((uint32_t *) ulMsgAddress) = (uint32_t)data0;

	*((uint32_t *) ulEndAddress) = (uint32_t)data1;
#endif
#ifdef _CIO
	if (   ( 0 > fprintf (pSTMHandle->pLogFileHdl, STM_FrmtStringHdr, pSTMHandle->BufIOInfo.pMasterId, chNum, "STMXport_logMsg2(...)") )
		|| ( 0 > fprintf (pSTMHandle->pLogFileHdl, pMsgString, data0, data1 ) )
		|| ( 0 > fprintf (pSTMHandle->pLogFileHdl, "\n") ) )
	{
	 	returnStatus = eSTM_ERROR_CIO_ERROR;
	}
#endif	
	RETURN_CALLBACK(pSTMHandle->pCallBack, returnStatus);

}

eSTM_STATUS STMXport_getBufInfo(STMHandle* pSTMHandle, uint32_t * msgCnt, uint32_t * curMsgBufSize)
{
//#ifdef _STM
//#if defined(_STM) && !defined(_COMPACT)
#if defined(_STM) && defined(_DMA)
	eSTM_STATUS retValue = eSTM_SUCCESS;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

	if (true == pSTMHandle->BufIOEnable)
	{
		//Initalize a pointer to head of message object link list 
		STMMsgObj * pTmpMsgObj = pSTMHandle->pHeadMsgObj;
		
		//Set amount of memory allocated 
		*curMsgBufSize = pSTMHandle->BufUsed;

		//Initialize outstanding message count
		*msgCnt = ( (pTmpMsgObj != NULL) && (false == pTmpMsgObj->DMA_posted) ) ? 1 : 0;

		//Walk the message object link list and count the number of outstanding messages
		if ( pTmpMsgObj != NULL )
		{
			while ( pTmpMsgObj->pNextMsg != NULL )
			{
				(*msgCnt)++;
				pTmpMsgObj = pTmpMsgObj->pNextMsg;
			}
		}
		//Get the current DMA state
		retValue = DMA_checkStatus(pSTMHandle);
	}
	else
	{
		*curMsgBufSize = 0;
		*msgCnt = 0;	
	}

	return retValue;
#endif
//#if defined(_CIO) || defined(_COMPACT)
#if defined(_CIO) || !defined(_DMA)
	return eSTM_ERROR_INVALID_FUNC;
#endif
}

eSTM_STATUS STMXport_flush(STMHandle* pSTMHandle)
{
	eSTM_STATUS retValue = eSTM_SUCCESS;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

//#ifdef _STM
//#if defined(_STM) && !defined(_COMPACT)
#if defined(_STM) && defined(_DMA)
	//If interface open for blocking, then there is nothing to flush
	if ( false == pSTMHandle->BufIOEnable )
	{
		return retValue;
	}

	//If DMA is interrupt driven, simply wait until no messages in the link and DMA
	// status is eSTM_SUCCESS
	if ( true == pSTMHandle->BufIOInfo.usingDMAInterrupt )
	{
		while ( NULL != pSTMHandle->pHeadMsgObj){
			//break out if we ever see a DMA error
			retValue = DMA_checkStatus(pSTMHandle);
			if ( retValue <= -1 )
			{
				break;
			}
		};
	}
	else
	{
		//Make sure there is a msg at the head
		while (NULL != pSTMHandle->pHeadMsgObj) 
		{
			//Must wait for the DMA unit to complete the current operation
			do 
			{
				retValue = DMA_checkStatus(pSTMHandle);
			}while( eSTM_PENDING == retValue);

			if ( NULL != pSTMHandle->pHeadMsgObj->pCallBack )
			{
				//If the callback is not NULL call it
				pSTMHandle->pHeadMsgObj->pCallBack(__FUNCTION__,retValue);	
			}
				
			if ( eSTM_SUCCESS == retValue )
			{
				//Start the next message
				DMA_serviceNextMsg(pSTMHandle);

			}
			else
			{
				//Detected an error
				break;
			}
		}
		
		//else retValue has an error that needs to be reported
	}
#endif
#ifdef _CIO
	if ( 0 != fflush(pSTMHandle->pLogFileHdl) )
	{
		retValue = eSTM_ERROR_CIO_ERROR;
	}

#endif

	return retValue;
}

eSTM_STATUS STMXport_close(STMHandle* pSTMHandle)
{
	eSTM_STATUS retValue = eSTM_SUCCESS;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
    cTools_memUnMap((void *)pSTMHandle->ulBaseAddress, 256*pSTMHandle->chResolution);
#endif

#ifdef _CIO
	if ( 0 != fclose(pSTMHandle->pLogFileHdl) )
	{
		retValue = eSTM_ERROR_CIO_ERROR;
	}

#endif

#ifdef _STM
	if (NULL != pSTMHandle)
	{
		cTools_memFree(pSTMHandle);
	}
#endif

	STMisOpen = false;

	return retValue;
}

#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))

inline uint32_t Compose_Address(uint32_t ulBaseAddr, int32_t chNum, uint32_t size, eAddressType addrType)
{
	uint32_t tsLocation = 0;

	tsLocation = ( addrType == eTiming ) ? size/2 : 0;
	 
	return (uint32_t) (ulBaseAddr + (size*(uint32_t)chNum)+ tsLocation);		
}

eSTM_STATUS STM_putBufCPU(STMHandle * pSTMHandle, int32_t chNum, void * pHdrBuf, int32_t iHdrByteCnt, void * pMsgBuf, uint32_t iElementCnt, eSTMElementSize iElementSize)
{
	volatile uint32_t ulMsgAddress = 0;
	uint32_t ulEndAddress = 0;
	uint32_t iElementIndex;
	uint32_t * pTempWordPtr;
	uint16_t * pTempShortPtr;
	uint8_t * pTempBytePtr; 

	ulMsgAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution,eRegular);
	ulEndAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution,eTiming);

#ifdef _STM
    if (( false == pSTMHandle->optimized_prinf ) && ( NULL != pSTMHandle->pUnOptPrintfMap))
    {
        // Special case for un-optimized printf
        bool * pStrMap = pSTMHandle->pUnOptPrintfMap;
        
        pTempWordPtr = (uint32_t *)pMsgBuf;
        for (iElementIndex = 0; iElementIndex < iElementCnt; iElementIndex++)
        {   
            if ( true == *pStrMap++ )
            {
                char * pStr = (char *)* pTempWordPtr;
                char data;
                do {
                    data = *pStr++;
                    if ( ( iElementIndex == iElementCnt-1 ) && ('\0' == data) )
                    {
                        *((unsigned char *) ulEndAddress) = data;
                    }
                    else
                    {
                        *((unsigned char *) ulMsgAddress) = data;
                    }
                }while( '\0' != data);
            }
            else
            {

                if ( iElementIndex == iElementCnt-1 )
                {
                    *((uint32_t *) ulEndAddress) = * pTempWordPtr;
                }
                else
                {
                    *((uint32_t *) ulMsgAddress) = * pTempWordPtr;
                }
            }
            pTempWordPtr++;                       
        }  
    }
    else
#endif
    {
        // Normal case for this function
     
        // If the header pointer is not null and the header
        //  word count is greater than 0, send the header.
        // Else (header word count 0 or header pointer null)
        //  then it's assumed the header is contained in the message.
     
        if (4 == iHdrByteCnt  ) 
        {
            *((uint32_t *) ulMsgAddress) = (uint32_t)pHdrBuf;  
        
        }
        if ( 8 == iHdrByteCnt  ) 
        {
            *((uint32_t *) ulMsgAddress) = * (uint32_t *)pHdrBuf;
            *((uint32_t *) ulMsgAddress) = * (((uint32_t *)pHdrBuf)+1);
        }   

    	switch (iElementSize)
    	{
    
    		case eByte:
    			pTempBytePtr = (uint8_t *)pMsgBuf;
    			for (iElementIndex = 0; iElementIndex < (iElementCnt-1); iElementIndex++)
    			{	 
    				*((uint8_t *) ulMsgAddress) = * pTempBytePtr;
    				pTempBytePtr++;
    			}
    
    			*((uint8_t *) ulEndAddress) = * pTempBytePtr;
    #ifdef _DEBUG
                STMXport_ByteCnt += iHdrByteCnt + iElementCnt;
    #endif
    			break;
    
    		case eShort:
    			pTempShortPtr = (uint16_t *)pMsgBuf;
    			for (iElementIndex = 0; iElementIndex < (iElementCnt-1); iElementIndex++)
    			{	 
    				*((uint16_t *) ulMsgAddress) = * pTempShortPtr;
    				pTempShortPtr++;
    			}
    
    			*((uint16_t *) ulEndAddress) = * pTempShortPtr;
    #ifdef _DEBUG
                STMXport_ByteCnt += iHdrByteCnt + (iElementCnt*2);
    #endif
    			break;
    
    		case eWord:
    			pTempWordPtr = (uint32_t *)pMsgBuf;
    			for (iElementIndex = 0; iElementIndex < (iElementCnt-1); iElementIndex++)
    			{	 
    				*((uint32_t *) ulMsgAddress) = * pTempWordPtr;
    				pTempWordPtr++;
    			}
    
    			*((uint32_t *) ulEndAddress) = * pTempWordPtr;
    #ifdef _DEBUG
                STMXport_ByteCnt += iHdrByteCnt + (iElementCnt*4);
    #endif
    			break;	
    	}
    }
	return eSTM_SUCCESS;
}
#endif

#ifdef _STM
eSTM_STATUS STM_putMsgCPU(STMHandle * pSTMHandle, int32_t chNum, void * pHdrBuf, int32_t iHdrByteCnt, void * pMsgBuf, uint32_t iMsgByteCnt)
{
	volatile uint32_t ulMsgAddress = 0;
	uint32_t ulEndAddress = 0;
	uint32_t iElementIndex;
	uint32_t * pTempWordPtr;
	uint16_t * pTempShortPtr;
	uint8_t * pTempBytePtr;
	void * pTempBuf;
	uint32_t bufByteCnt;
	uint32_t bufAlignment;

#ifdef _DEBUG
    STMXport_ByteCnt += iHdrByteCnt + iMsgByteCnt;
#endif
	 
	ulMsgAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution,eRegular);
	ulEndAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution,eTiming);

	// If the header pointer is not null and the header
	//  word count is greater than 0, send the header.
	// Else (header word count 0 or header pointer null)
	//  then it's assumed the header is contained in the message.
	if ( ( 0 != iHdrByteCnt ) && ( NULL != pHdrBuf ) )
	{
		uint32_t iHdrWrdCnt = iHdrByteCnt/eWord;
		for (iElementIndex = 0; iElementIndex < iHdrWrdCnt; iElementIndex++)
		{ 
			*((uint32_t *) ulMsgAddress) = * (uint32_t *)pHdrBuf;
		}
	}

	// Process the front end of the message
	bufAlignment = AddressAlignmentChecker((uint32_t)pMsgBuf);
	pTempBuf = pMsgBuf;
	bufByteCnt = iMsgByteCnt;
	switch (bufAlignment)
	{
		//Note on the fron end the alignment enums are reversed from backend
		// eShortAndByte - need to transfer 1 byte to achive word alignment
		// eByte - need to transfer 1 byte and then a short to achive word alignment
		// eShort - same as backend
		// eWord - same as backend
		case eShortAndByteAlign:
			//Fall through to the byte case 
		case eByteAlign:
			if ( bufByteCnt > 1 )
			{
				pTempBytePtr = (uint8_t *)pMsgBuf;
		 
				*((uint8_t *) ulMsgAddress) = * pTempBytePtr;
				pTempBytePtr++;

				pTempBuf = (void *)pTempBytePtr;

				bufByteCnt -= eByte;
			}

			if (eShortAndByteAlign == bufAlignment) break;

			//If eByte case fall through to eShort case
		case eShortAlign:
			if ( bufByteCnt > 2 ) 
			{
				pTempShortPtr = (uint16_t *)pTempBuf;
		 
				*((uint16_t *) ulMsgAddress) = * pTempShortPtr;
				pTempShortPtr++;

				pTempBuf = (void *)pTempShortPtr;

				bufByteCnt -=eShort;
			}

			break;
	}

	// Process the whiole number of eWords
	{
		uint32_t wordCnt;
		uint32_t remBytes = bufByteCnt % eWord;
		if ( 0 == remBytes )
		{
			//Must leave one word to terminate the STM message 
			wordCnt = (bufByteCnt/eWord) - 1;
		}
		else
		{
			//Since there are some byte remainder
			wordCnt = (bufByteCnt/eWord);
		}
		
		pTempWordPtr = (uint32_t *)pTempBuf;
		for (iElementIndex = 0; iElementIndex < wordCnt; iElementIndex++)
		{	 
			*((uint32_t *) ulMsgAddress) = * pTempWordPtr;
			pTempWordPtr++;
			bufByteCnt -= eWord;
		}

		pTempBuf = (void *)pTempWordPtr;
		  
		//Check for the case where there are 3 bytes left on a word boundary
		if ( bufByteCnt == 3 )
		{
				pTempShortPtr = (uint16_t *)pTempBuf;

				*((uint16_t *) ulMsgAddress) = * pTempShortPtr;
				pTempShortPtr++;
				pTempBuf = (void *)pTempShortPtr;
				bufByteCnt -= eShort;	
		}
	}

	//Process the end of the message

	// Byte count must be 1, 2 or 4 at this point
	// and aligned to the proper address.
	switch (bufByteCnt)
	{
		case eByte:
			pTempBytePtr = (uint8_t *)pTempBuf;
 
			*((uint8_t *) ulEndAddress) = * pTempBytePtr;
			break;

		case eShort:
			pTempShortPtr = (uint16_t *)pTempBuf;

			*((uint16_t *) ulEndAddress) = * pTempShortPtr;
			break;

		case eWord:
			pTempWordPtr = (uint32_t *)pTempBuf;

			*((uint32_t *) ulEndAddress) = * pTempWordPtr;
			break;	
	}

	return eSTM_SUCCESS;
}
#endif

//#ifdef _STM
//#if defined(_STM) && !defined(_COMPACT)
#if defined(_STM) && defined(_DMA)
// All DMA support is removed in compact build mode
eSTM_STATUS STM_putDMA(STMHandle* pSTMHandle, int32_t chNum, void* pMsgBuf, uint32_t iElementCnt, eSTMElementSize iElementSize, bool DMASingleAccessMode,  STMXport_callback pCallBack)
{
	eSTM_STATUS retValue = eSTM_SUCCESS;

	//Even if the DMA unit is not busy must still put the message in the
	//link list of messages so we know what to do with the message when complete
	STMMsgObj * pMsgObj;
	int32_t msgObjBytes = sizeof(STMMsgObj);
	if ( (pSTMHandle->BufUsed + msgObjBytes) > pSTMHandle->BufIOInfo.maxBufSize )
	{
		return eSTM_ERROR_BUF_ALLOCATION;
	}
	
	pMsgObj = (STMMsgObj *)cTools_memAlloc(sizeof(STMMsgObj));
	if (NULL == pMsgObj )
	{
	    return eSTM_ERROR_HEAP_ALLOCATION;
	}

	pSTMHandle->BufUsed += msgObjBytes;
    
    //Fill in the message object  
	pMsgObj->pMsg = pMsgBuf;
	pMsgObj->elementCnt = iElementCnt;
	pMsgObj->elementSize = iElementSize;
	pMsgObj->chNum = chNum;
	pMsgObj->pCallBack = pCallBack;
	pMsgObj->pNextMsg = NULL;
	pMsgObj->DMA_SingleAccessMode = DMASingleAccessMode;
	pMsgObj->DMA_posted = false;

	//Put the message object in the link list
	if ( NULL == pSTMHandle->pHeadMsgObj )
	{
		// Put this message at the head of the link list
		 pSTMHandle->pHeadMsgObj = pMsgObj;
	}
	else {
		// Find the last message in the link list
		STMMsgObj * pTmpMsgObj = pSTMHandle->pHeadMsgObj;
		while ( pTmpMsgObj->pNextMsg != NULL )
		{
			pTmpMsgObj = pTmpMsgObj->pNextMsg;
		}
		//Found the end of the link
		pTmpMsgObj->pNextMsg = pMsgObj;

	}
			 
	//the DMA channel is not busy can post the pending message
	retValue = DMA_checkStatus(pSTMHandle);
	if ( eSTM_SUCCESS == retValue ) 
	{
		//If the message at the head has not been posted
		if ( false == pSTMHandle->pHeadMsgObj->DMA_posted )
		{
			DMA_postMsg(pSTMHandle, pSTMHandle->pHeadMsgObj);
		}
		else if ( false == pSTMHandle->BufIOInfo.usingDMAInterrupt )
		{
		//If the message at the head has been posted

			if ( NULL != pSTMHandle->pHeadMsgObj->pCallBack )
			{
				//If the callback is not NULL call it
				pSTMHandle->pHeadMsgObj->pCallBack(__FUNCTION__, retValue);	
			}
			DMA_serviceNextMsg(pSTMHandle);	

		}

	}
	return retValue;
}


eSTM_STATUS DMA_checkStatus(STMHandle* pSTMHandle)
{

	int dmaCh1 = pSTMHandle->BufIOInfo.DMAChan_0;
    uint32_t DMA_BaseAddr = pSTMHandle->BufIOInfo.DMA4_BaseAddress;
	uint32_t DMA_chControl = *(uint32_t * )DMA_ChCntl(dmaCh1);
	uint32_t DMA_chStatus = *(uint32_t * )DMA_ChStatus(dmaCh1);
	uint32_t DMA_chErrors = DMA_chStatus & DMA_ERROR_MASK;
	eSTM_STATUS retValue = eSTM_SUCCESS;

	// If DMA is not enabled then return eSTM_SUCCESS
	// else since DMA is eabled check for error and pending cases
	if ( true == ( ( DMA_chControl & DMA_ENABLE) == DMA_ENABLE ) ) 
	{

		if ( ( 0 != DMA_chErrors ) && ( DMA_chStatus & DMA_FRAME_COMPLETE ) )
		{
			switch ( DMA_chErrors) {
				case DMA_SYSTEM_ERROR:
					retValue = eSTM_ERROR_SYSTEM;
					break;
				case DMA_MISSALIGND_ERROR:
					retValue = eSTM_ERROR_MISSALIGNED_ADDR;
					break;
				case DMA_SUPERVISOR_ERROR:
					retValue = eSTM_ERROR_SUPERVISOR;
					break;
				case DMA_SECURE_ERROR:
					retValue = eSTM_ERROR_SECURE;
					break;
				case DMA_TRASACTION_ERROR:
					retValue = eSTM_ERROR_TRANSACTION;
					break;					
			}
		}
		else if ( false == (DMA_chStatus & DMA_FRAME_COMPLETE))
		{
			// If no errors but DMA is busy return eSTM_PENDING
			retValue = eSTM_PENDING;
		}
		
		//if complete and no errors retValue already set to eSTM_SUCCESS		 
	}

	return retValue;
}

void DMA_serviceNextMsg(STMHandle* pSTMHandle)
{

	// Free the original message
	cTools_memFree(pSTMHandle->pHeadMsgObj->pMsg);
	pSTMHandle->BufUsed -= ( pSTMHandle->pHeadMsgObj->elementCnt * pSTMHandle->pHeadMsgObj->elementSize );

	// If the next message is not NULL post it to the DMA unit
	if ( NULL != pSTMHandle->pHeadMsgObj->pNextMsg )
	{
		//Get the next message
		STMMsgObj * pNextMsgObj = pSTMHandle->pHeadMsgObj->pNextMsg;

		//Free the current msg from the head of the link list
		cTools_memFree(pSTMHandle->pHeadMsgObj);
		pSTMHandle->BufUsed -= sizeof(STMMsgObj);
		
		//Update the head of the link list
		pSTMHandle->pHeadMsgObj = pNextMsgObj;

		//Post the message to the DMA
		DMA_postMsg(pSTMHandle, pSTMHandle->pHeadMsgObj);
	}
	else
	{
		//Free the current msg from the head of the link list
		cTools_memFree(pSTMHandle->pHeadMsgObj);
		pSTMHandle->BufUsed -= sizeof(STMMsgObj);
		//Update the head of the link list
		pSTMHandle->pHeadMsgObj = NULL;	
	}	

}

void DMA_postMsg(STMHandle* pSTMHandle, STMMsgObj * pMsgObj)
{
	uint32_t ulMsgAddress = 0;
	uint32_t ulEndAddress = 0;
    uint32_t DMA_BaseAddr = pSTMHandle->BufIOInfo.DMA4_BaseAddress;
	int32_t dmaCh1 = pSTMHandle->BufIOInfo.DMAChan_0;
	int32_t dmaCh2 = pSTMHandle->BufIOInfo.DMAChan_1;
	uint32_t ulDMA_ElemSize = 0;

	char * pTempPtr = (char *)pMsgObj->pMsg; //was char * pTempPtr = (char*)pMsgBuf;
	void * pMsgBuf = pMsgObj->pMsg;
	int32_t chNum = pMsgObj->chNum; 
	uint32_t iElementCnt = pMsgObj->elementCnt;
	eSTMElementSize iElementSize = pMsgObj->elementSize;
	bool DMASingleAccessMode = pMsgObj->DMA_SingleAccessMode;
	

	// This function assumes the calling routine has already determined the DMA is free
	ulMsgAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution, eRegular);
	ulEndAddress = Compose_Address(pSTMHandle->ulBaseAddress,chNum,pSTMHandle->chResolution, eTiming);

#if 0
	// Note - will want to eanble DMA to complete when Msuspend(EMU Suspend) set
	if ( DMAFirstTime ) {
		*(uint32_t * )DMA_OCPCntl |= 0x2; // Reset - will want to move this to open, although
			 							   // eventually the DMA reset should come from the calling app.

		*(uint32_t * )DMA_FIFO = (uint32_t)0x01010020; // May ned to move this to open
 		DMAFirstTime = 0;
	}
#endif
	pTempPtr += (iElementCnt -1)*iElementSize;

	//Default for ulDMA_ElemSize is 0 for eByte
	if ( eByte != iElementSize ) 
	{
		ulDMA_ElemSize = (eShort == iElementSize) ? 1: 2; // short is 1, word is 2
	}

	//Program channel for header and body (less one element)
	*(uint32_t * )DMA_ChCntl(dmaCh1) = 0x1000; //Do not increment destination address

	if ( true == DMASingleAccessMode )
	{
		*(uint32_t * )DMA_ChSrcDstPrms(dmaCh1) = 0x10000 | ulDMA_ElemSize; //Single access
	}
	else
	{
		*(uint32_t * )DMA_ChSrcDstPrms(dmaCh1) = 0x1E1C0 | ulDMA_ElemSize; //Burst reads/writes & pack
	}
 
	//	*(uint32_t * )DMA_ChElem(dmaChl) = (unsigned int)iByteWritten/4;
	*(uint32_t * )DMA_ChElem(dmaCh1) = iElementCnt-1;
	*(uint32_t * )DMA_ChFram(dmaCh1) = 1;
	*(uint32_t * )DMA_ChSrcAdd(dmaCh1) = (uint32_t)pMsgBuf;
	*(uint32_t * )DMA_ChDstAdd(dmaCh1) = ulMsgAddress;
	*(uint32_t * )DMA_ChLnkCntl(dmaCh1) = 0x8000 | (dmaCh2); //Link to next channel
	*(uint32_t * )DMA_ChStatus(dmaCh1) = 0xE; //Clear the end of frame status bit

	//Program next channel for end address xfer

	*(uint32_t * )DMA_ChCntl(dmaCh2) = 0x1000; //Do not increment destination address

	if ( true == DMASingleAccessMode )
	{
		*(uint32_t * )DMA_ChSrcDstPrms(dmaCh2) = 0x10000 | ulDMA_ElemSize; //Single access
	}
	else
 	{
		*(uint32_t * )DMA_ChSrcDstPrms(dmaCh2) = 0x1E1C0 | ulDMA_ElemSize; //Burst reads/writes & pack
	}

	*(uint32_t * )DMA_ChElem(dmaCh2) = (uint32_t)1;
	*(uint32_t * )DMA_ChFram(dmaCh2) = 1;
	*(uint32_t * )DMA_ChSrcAdd(dmaCh2) = (uint32_t)pTempPtr;
	*(uint32_t * )DMA_ChDstAdd(dmaCh2) = ulEndAddress;
	*(uint32_t * )DMA_ChLnkCntl(dmaCh2) = 0; //End of link
	*(uint32_t * )DMA_ChStatus(dmaCh2) = 0xE; //Clear the end of frame status bit

	*(uint32_t * )DMA_ChCntl(dmaCh1) |= 0x100; //Enable complete on EMUSuspend
	*(uint32_t * )DMA_ChCntl(dmaCh2) |= 0x100; //Enable complete on EMUSuspend

	*(uint32_t * )DMA_ChCntl(dmaCh1) |= 0x80; //Enable the transfer

	pSTMHandle->pHeadMsgObj->DMA_posted = true;	
}
#endif

eSTM_STATUS STMXport_DMAIntService(STMHandle* pSTMHandle)
{
//#ifdef _STM
//#if defined(_STM) && !defined(_COMPACT)
#if defined(_STM) && defined(_DMA)
	eSTM_STATUS retValue = eSTM_ERROR_INTDISABLED;
    uint32_t DMA_BaseAddr = pSTMHandle->BufIOInfo.DMA4_BaseAddress;
#ifdef _DEBUG
	VALIDATE_NULL_VALUE(pSTMHandle);
#endif
	//If interface open for blocking, then there should be no interrupts to service
	if ( false == pSTMHandle->BufIOEnable )
	{
		return retValue;
	}

	if ( true == pSTMHandle->BufIOInfo.usingDMAInterrupt )
	{
		//Get the current status
		eSTM_STATUS retValue = DMA_checkStatus(pSTMHandle);
			
		//If the IRQ status bit is not set then exit
		uint32_t dmaIrqStatus = *(uint32_t *)DMA_IrqStatus(pSTMHandle->BufIOInfo.DMAIrq);
		dmaIrqStatus = dmaIrqStatus & ( 1 << pSTMHandle->BufIOInfo.DMAChan_0);
		if (0 == dmaIrqStatus) {
			return (eSTM_ERROR_INTINVALID);
		}

		//Clear the IRQ status bit
		*(uint32_t *)DMA_IrqStatus(pSTMHandle->BufIOInfo.DMAIrq) = 1 << pSTMHandle->BufIOInfo.DMAChan_0;

		//If the message at the head has not been posted yet then this must be invalid
		if ( true != pSTMHandle->pHeadMsgObj->DMA_posted )
		{
			return (eSTM_ERROR_INTINVALID);
		}

		if ( NULL != pSTMHandle->pHeadMsgObj->pCallBack )
		{
			//If the callback is not NULL call it
			pSTMHandle->pHeadMsgObj->pCallBack(__FUNCTION__, retValue);	
		}
			
		// If DMA status is not busy (not pending and no errors)
		if ( eSTM_SUCCESS == retValue ) 
		{
			DMA_serviceNextMsg(pSTMHandle);	
		}		
	}

	return retValue;
#endif
//#if defined(_CIO) || defined(_COMPACT)
#if defined(_CIO) || !defined(_DMA)
	return eSTM_ERROR_INVALID_FUNC;
#endif
}

#ifdef _STM
void Build_OST_Header(uint32_t protocolID, uint32_t numberOfBytes, uint32_t *pReturnBuf, int32_t *pBufSizeInBytes)
{
		
	if (numberOfBytes >= OST_SHORT_HEADER_LENGTH_LIMIT)
	{
		*pReturnBuf = OST_VERSION | OST_ENTITY_ID | protocolID | OST_SHORT_HEADER_LENGTH_LIMIT;
		pReturnBuf++;
		*(pReturnBuf) = (numberOfBytes);
		*pBufSizeInBytes = 8; /* 8 bytes for the extended length header */
	}
	else
	{
		*pReturnBuf = OST_VERSION | OST_ENTITY_ID | protocolID | numberOfBytes;
		*pBufSizeInBytes = 4; /* 4 bytes for the normal header */
	}

	return;
}
#endif

#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO))
inline uint32_t Build_CompactOST_Header(uint32_t protocolID, uint32_t numberOfBytes )
{
	
	return OST_VERSION | OST_ENTITY_ID | protocolID | numberOfBytes;
	
}

inline Build_ExtendedOST_Header(uint32_t protocolID, uint32_t numberOfBytes, uint32_t *pReturnBuf)
{

	*pReturnBuf = (uint32_t)OST_VERSION | OST_ENTITY_ID | protocolID | OST_SHORT_HEADER_LENGTH_LIMIT;
	pReturnBuf++;
	*(pReturnBuf) = numberOfBytes;
	return;
}


void Compose_OST_MSG(const char *pInputBuf, int32_t iInputBufSize, const char *pOSTHeader, int32_t iHeaderSizeInByte, char *pReturnBuf)
{
	if ( 0 != iHeaderSizeInByte ) {
		memcpy(pReturnBuf, pOSTHeader, iHeaderSizeInByte);
		pReturnBuf += iHeaderSizeInByte;  /* we know that OST header is word aligned */
	}
	memcpy(pReturnBuf, pInputBuf, iInputBufSize); 
}

#endif
eAddrAlignment AddressAlignmentChecker(uint32_t addressValue)
{
	eAddrAlignment addressAlignment;

	if (addressValue % STM_WORD_SIZE == 0)
	{
		addressAlignment = eWordAlign;
	}
	else if (addressValue % STM_WORD_SIZE == eShortAndByteAlign)
	{
		addressAlignment = eShortAndByteAlign;
	}
	else if (addressValue % STM_WORD_SIZE == eShortAlign)
	{
		addressAlignment = eShortAlign;
	}
	else
	{	
		addressAlignment = eByteAlign;
	}

	return addressAlignment;
}

eSTM_STATUS STMExport_IntMsg (STMHandle * pSTMHandle, int32_t chNum, 
                              const char * pModuleName, const char * pDomainName,
                              const char * pDataClass, const char * pDataType,
                              const char * pDataMsg, uint32_t * pData)

{
#if defined(_STM) || ( defined(_COMPACT) && !defined(_CIO)) 	
	register volatile uint32_t ulMsgAddress = 0;
	register volatile uint32_t ulEndAddress = 0;
    register uint32_t OST_Header;

	//Check for errors
    if ( NULL == pSTMHandle )
    {
        return eSTM_ERROR_PARM;
    }

	if ( NULL != pData)
	{
		OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_INTERNALMSG | 24;
	}
	else
	{
		OST_Header = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_INTERNALMSG | 20;
	}

	//Calculate STM Addresses
    ulMsgAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum);
	ulEndAddress = pSTMHandle->ulBaseAddress + (pSTMHandle->chResolution * chNum) + (pSTMHandle->chResolution/2);

	//Xport the OST Header
	*((uint32_t *) ulMsgAddress) = OST_Header;

	//Xport the Data
	*((uint32_t *) ulMsgAddress) = (uint32_t)pModuleName;
	*((uint32_t *) ulMsgAddress) = (uint32_t)pDomainName;
	*((uint32_t *) ulMsgAddress) = (uint32_t)pDataClass;
	*((uint32_t *) ulMsgAddress) = (uint32_t)pDataType;
	
	if ( NULL != pData) 
	{
        *((uint32_t *) ulMsgAddress) = (uint32_t)pDataMsg;
		*((uint32_t *) ulEndAddress) = *pData;
	}
    else
    {
        *((uint32_t *) ulEndAddress) = (uint32_t)pDataMsg;
    }
	
    return eSTM_SUCCESS;
#endif
#if defined(_CIO)
    return eSTM_ERROR_INVALID_FUNC;
#endif
}


#if 0

//extern STMHandle * pgSTMHandle;
extern uint32_t STM_BaseAddress;
extern uint32_t STM_ChResolution;

//inline void STM_funcProfile(void (*addr)())
void STM_funcProfileEntry(const char * func)
{
// Note - this is a prototype. Final version will be hand assembly. 
// For CCS PC trace profile processing need decoder to put addr value in address field.       
// Prototype uses char * to function name, so function name shows up in message field.

// Must inline
// Must make this an atomic operation to retain thread safety since we are using a fixed channel
// Need to caclculate the ulMsgAddress & ulEndAddress in open and store in globals that are accessed from hook function
//    rather than making base address and resolution globals. Eliminates adddress calculations completly.
// Need to change PROTOCOL from OST_PROTOCOL_PRINTF to OST_PROTOCOL_FUNCENTRY & on exit OST_PROTOCOL_FUNCEXIT
// In a multithreaded system thread id is transported on the same channel but with a different header.
 

    register volatile int32_t chNum = 254;
    register volatile uint32_t ulMsgAddress = 0;
    register volatile uint32_t ulEndAddress = 0;
    
    //Disable interrupts
    
    //Transfer hook function address on channel 254
    
    ulMsgAddress = STM_BaseAddress + (STM_ChResolution * chNum);
    ulEndAddress = STM_BaseAddress + (STM_ChResolution * chNum) + (STM_ChResolution/2);   

    //Export OST Header
//    *((uint32_t *) ulMsgAddress) =  OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_INTERNALMSG | 8;  
    *((uint32_t *) ulMsgAddress) = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF | 1;  
    //Export data with timestamp
//    *((uint32_t *) ulEndAddress) = (uint32_t)addr;
    *((uint32_t *) ulEndAddress) = (uint32_t)func;
    
    //Enable interrupts
}

void STM_funcProfileExit(const char * func)
{
// Note - this is a prototype. Final version will be hand assembly. 
// For CCS PC trace profile processing need decoder to put addr value in address field.       
// Prototype uses char * to function name, so function name shows up in message field.

    register volatile int32_t chNum = 253;
    register volatile uint32_t ulMsgAddress = 0;
    register volatile uint32_t ulEndAddress = 0;
    
    //Disable interrupts
    
    //Transfer hook function address on channel 254
    
    ulMsgAddress = STM_BaseAddress + (STM_ChResolution * chNum);
    ulEndAddress = STM_BaseAddress + (STM_ChResolution * chNum) + (STM_ChResolution/2);   

    //Export OST Header
//    *((uint32_t *) ulMsgAddress) =  OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_INTERNALMSG | 8;  
    *((uint32_t *) ulMsgAddress) = OST_VERSION | OST_ENTITY_ID | (uint32_t)OST_PROTOCOL_PRINTF | 1;  
    //Export data with timestamp
//    *((uint32_t *) ulEndAddress) = (uint32_t)addr;
    *((uint32_t *) ulEndAddress) = (uint32_t)func;
    
    //Enable interrupts
}

#endif
