/* 
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * 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.
 * */

/*
 *  ======== EtbDrainer.c ========
 */
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Gate.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Memory.h>
#include <xdc/runtime/Startup.h>
#include <xdc/runtime/Types.h>
#include <xdc/runtime/Diags.h>
#include <xdc/runtime/Timestamp.h>
#include <ti/uiactools/runtime/IUIAPacketTransfer.h>
#include <ti/uiactools/runtime/UIAPacket.h>
#include <ti/ctools/etbLib/ETBInterface.h>

#include <stdio.h>


#ifdef xdc_target__isaCompatible_64P
#include <c6x.h>
#include <ti/ctools/etbLib/TIETB.c>
#else

static UInt32 DNUM=0;
//#include <ti/ctools/etbLib/CSETB.c>
#endif

#include <stdlib.h>
#include <string.h>

#define HDR_OFFSET_IN_WORDS 7        /* Size of the UIA trace packet header */
#define BYTES_IN_WORD 4

#include "package/internal/EtbDrainer.xdc.h"
/*
#define HDR_OFFSET_IN_WORDS 7        // Size of the UIA trace packet header /
#define BYTES_IN_WORD 4
#define MAU_TO_BITS32(mau)          ((mau) / sizeof(Bits32))
#define EDMA_BFR_CNT  2
#define C66x 1
#include <ti/ctools/etbLib/ETBAddr.h>
#include <ti/ctools/etbLib/edma_dev-c66xx.h>
 */
static int gNumLoops = 0;


extern UInt32 ETB_getATBMsgHdrPointer (int index);
extern void stm_config_for_etb(void);
extern 	void initDmaConfig(ETBHandle *etbHandle, DMAConfig *dmaConfig, UInt32 drainBufferAdrs, UInt32 drainBufSizeInWords);
extern void initEtbEvents(ETBHandle *etbHandle);

/*
 *  ======== EtbDrainer_getFreeSize =========
 */
SizeT EtbDrainer_getFreeSize(EtbDrainer_Object *obj)
{
	return (obj->end - obj->write);
}


/*
 *  ======== EtbDrainer_Module_startup ========
 */
Int EtbDrainer_Module_startup(Int phase)
{
	Int i;
	EtbDrainer_Object *obj;

	/*
	 *  Loop over all instances of the EtbDrainer module
	 */
	for (i = 0; i < EtbDrainer_Object_count(); i++) {
		obj = EtbDrainer_Object_get(NULL, i);
		if (obj->primeFxn != NULL) {
			obj->buffer = (UInt32*)obj->primeFxn(obj);
			if (obj->buffer != NULL) {

				obj->write = obj->buffer + HDR_OFFSET_IN_WORDS;
				obj->end = obj->buffer
						+ (obj->packetSizeInMAUs/sizeof(UInt32));
			}
			obj->primeStatus = TRUE;

		}
	}

#ifdef xdc_target__isaCompatible_64P
	/* Start the timestamp */
	TSCL = 0;
#endif
	return (Startup_DONE);


}

/*
 *  ======== Instance_init =========
 *  TODO not completely tested.
 */
Int EtbDrainer_Instance_init(EtbDrainer_Object *obj,
		const EtbDrainer_Params *prms, Error_Block *eb)
{

	obj->etbSizeInWords = 0; /* initialized by ETBLib open call */
	obj->packetSizeInMAUs = prms->packetSizeInMAUs;
	obj->enabled = TRUE;
	obj->droppedSnapshots = 0;
	obj->snapshotNumber = 1;
	obj->serial = 1;
	obj->isFirstPacket = TRUE;
	obj->endpointNumber = prms->endpointNumber;
	if (obj->endpointNumber == 0xFF){
		obj->endpointNumber = DNUM;
	}
	obj->printDebugMessages = FALSE;
	obj->exchangeFxn = prms->exchangeFxn;
	obj->primeFxn = prms->primeFxn;
	obj->etbType = prms->etbType;
	obj->etbCoreId = prms->etbCoreId;
	if ((prms->drainBufSizeInMAUs % sizeof(Int32)) > 0){
		obj->drainBufSizeInWords = 1 + (prms->drainBufSizeInMAUs/sizeof(Int32));
	} else {
		obj->drainBufSizeInWords = (prms->drainBufSizeInMAUs/sizeof(Int32));
	}
	/* TODO: add error checking to cover if allocation fails */
	obj->drainBuf1 = Memory_alloc(prms->bufHeap, prms->drainBufSizeInMAUs, 32*sizeof(Int32), eb);
#ifdef USE_TWO_BUFFERS
	obj->drainBuf2 = Memory_alloc(prms->bufHeap, prms->drainBufSizeInMAUs, 32*sizeof(Int32), eb);
#endif
	obj->etbSizeInWords = 0; // this is initialized later in the code
	if (prms->etbType == EtbDrainer_EtbType_CPUTRACE){
		obj->traceHdrType = UIAPacket_HdrType_CPUTrace;
	} else {
		obj->traceHdrType = UIAPacket_HdrType_STMTrace;
	}
	return (0); /* status passed to finalize on error */
}

Void EtbDrainer_enableDebugMessages(EtbDrainer_Object *obj, Bool enable){
	obj->printDebugMessages = enable;
}
/*
 *  ======== EtbDrainer_Instance_finalize ========
 *  TODO not completely tested.
 */
Void EtbDrainer_Instance_finalize(EtbDrainer_Object *obj, Int status)
{
}


/*******************************************************************************
 * Public Function Definitions
 ******************************************************************************/



Bool EtbDrainer_init(EtbDrainer_Object *obj){
	/********************************************************************************
	 * Open ETB to receive STM data. Once ETB is opened successfully, ETB can
	 * can be enabled and disabled for "start capture" and "stop capture"
	 * respectively.
	 * Please note that SYS ETB ID needs to be passed in for STM collection. 0 for
	 *  core (ETM)
	 ********************************************************************************/
	eETB_Error  etbRet;
	ETB_errorCallback pETBErrCallBack =0;
	if (!obj->isInitialized){
		if (obj->endpointNumber == 0xFF){
			obj->endpointNumber = DNUM;
		}
		if (EtbDrainer_useEtbLib) {
			if (obj->etbType == EtbDrainer_EtbType_CPUTRACE){

				//TODO: cputrace_for_etb()
				etbRet = ETB_open(pETBErrCallBack, eETB_TI_Mode, obj->etbCoreId, (ETBHandle **)&obj->etbHandle, &obj->etbSizeInWords);

			} else { /* STM */
				stm_config_for_etb();
				etbRet = ETB_open(pETBErrCallBack, eETB_TI_Mode, SYS_ETB, (ETBHandle **)&obj->etbHandle, &obj->etbSizeInWords);
			}

			if(etbRet != eETB_Success)
			{
				return(FALSE);
			}


			initDmaConfig((ETBHandle *)obj->etbHandle, (DMAConfig *)&obj->dmaConfig,(UInt32)obj->drainBuf1,obj->drainBufSizeInWords);
			initEtbEvents((ETBHandle *)obj->etbHandle);
			ETB_config_dma((ETBHandle *)obj->etbHandle, (DMAConfig *)&obj->dmaConfig);



			/****************************************************************************
			 * Enable ETB to capture STM data.
			 ****************************************************************************/
			/* Enable ETB receiver */
			etbRet = ETB_enable((ETBHandle *)obj->etbHandle, 0);
		} else {
			if (obj->etbType == EtbDrainer_EtbType_STMTRACE){
				stm_config_for_etb();
			}
			etbRet = BufferMgr_open(pETBErrCallBack, obj->etbType, obj->etbCoreId, &obj->etbHandle, &obj->etbSizeInWords);
		}


		if (etbRet == eETB_Success){
			obj->isInitialized = TRUE;
		}
	}
	return (etbRet == eETB_Success);
}
/*
 *  ======== EtbDrainer_enable ========
 */
Bool EtbDrainer_enable(EtbDrainer_Object *obj)
{
	Bool prev;
	IArg key;

	key = Gate_enterSystem();

	prev = obj->enabled;
	obj->enabled = TRUE;

	Gate_leaveSystem(key);

	return (prev);
}

/*
 *  ======== EtbDrainer_disable ========
 */
Bool EtbDrainer_disable(EtbDrainer_Object *obj)
{
	Bool prev;
	IArg key;

	key = Gate_enterSystem();

	prev = obj->enabled;
	obj->enabled = FALSE;

	Gate_leaveSystem(key);

	return (prev);
}


/*
 * ======== getNumDropped =========
 * returns the number of dropped events for this logger instance
 * TODO getStats instead? Add to IUIATransfer?
 */
Int EtbDrainer_getNumDropped(EtbDrainer_Object *obj)
{
	return (obj->droppedSnapshots);
}

/*
 * ======== EtbDrainer_getTransferType ========
 *  Returns whether the logger events can be sent over lossy transports or
 *  requires reliable transport
 // TODO need to see if this makes sense...
 */
IUIAPacketTransfer_TransferType EtbDrainer_getTransferType(
		EtbDrainer_Object *obj)
{
	return(obj->transferType);
}



/*
 * ======== EtbDrainer_isEmpty ========
 * Returns true if the transfer buffer has no unread data
 */
Bool EtbDrainer_isEmpty(EtbDrainer_Object *obj)
{
	Bool result;

	if (obj->write == (obj->buffer + HDR_OFFSET_IN_WORDS)) {
		result = TRUE;
	}
	else {
		result = FALSE;
	}

	return (result);
}

/*
 * ======== EtbDrainer_isEmpty ========
 * Returns true if the transfer buffer has no unread data
 */
Bool EtbDrainer_isFirstPacketFlagSet(EtbDrainer_Object *obj)
{
	return (obj->isFirstPacket);
}




/*
 *  ======== EtbDrainer_flush ========
 */
Void EtbDrainer_sendPacket(EtbDrainer_Object *obj)
{
	Bits32 pktLength;
	UInt32 adrs;
	int i;
	if ((obj->buffer != NULL)&&(obj->isInitialized)){
		pktLength = (Bits32)((obj->write - obj->buffer) * BYTES_IN_WORD);
		/* If there is data in the buffer */
		if (obj->write
				> (obj->buffer + HDR_OFFSET_IN_WORDS)) {
			/* Set UIA packet length and sequence number */
			UIAPacket_setEventLength((UIAPacket_Hdr*)obj->buffer,pktLength);
			UIAPacket_setSequenceCount((UIAPacket_Hdr*)obj->buffer,
					obj->serial);
			UIAPacket_initTraceHdrFields((UIAPacket_Hdr7 *)obj->buffer, obj->traceHdrType,obj->endpointNumber,
					obj->isFirstPacket,obj->tracePktDownCount,obj->snapshotNumber);
			if (obj->printDebugMessages){
				printf("Packet Sequence Number=%d: obj->isFirstPacket = %d. obj->tracePktDownCount = %d\n",
						obj->serial,obj->isFirstPacket,obj->tracePktDownCount);
				printf("PktHdr.isFirstPkt = 0x%x PktHdr.tracePktDownCount=0x%x\n",
						UIAPacket_getFirstPktFlag((UIAPacket_Hdr7 *)obj->buffer),
						UIAPacket_getTracePktDownCount((UIAPacket_Hdr7 *)obj->buffer));
				adrs = (UInt32)obj->buffer;
				for (i=0;i<7;i++){
					printf("   Hdr[%d] = 0x%x (address= 0x%x)\n",i,*(UInt32*)adrs,adrs);
					adrs += 4;
				}
			}
			/*
			 *  If there is empty space at the end of the buffer, to let UIA know it should ignore this we
			 *  add a 32 bit Invalid UIA header with the length of the empty space.
			 */
			if (pktLength < obj->packetSizeInMAUs){
				UIAPacket_setInvalidHdr(obj->write,
						(obj->end - obj->write) * BYTES_IN_WORD);
			}
			/* Set the module write ptr to NULL to prevent log calls in exchange */
			obj->write = NULL;

			/* Send filled buffer to exchange function */
			obj->buffer = (UInt32*)obj->exchangeFxn((Ptr)obj,(Ptr)obj->buffer);

			/* Update ptrs to new buffer */
			obj->write = obj->buffer + HDR_OFFSET_IN_WORDS;
			obj->end =	obj->buffer	+ (obj->packetSizeInMAUs/sizeof(UInt32));
			obj->serial++;
			if (obj->printDebugMessages){
				printf("New packet: serial=%d, address = 0x%x\n",obj->serial,(UInt32)obj->buffer);
			}
		}
	}
}

/*
 *  ======== EtbDrainer_Prime =========
 */
Bool EtbDrainer_prime(EtbDrainer_Object *obj, Ptr buffer)
{
	if (obj->primeStatus == FALSE) {
		obj->buffer = (UInt32*)buffer;

		obj->write = (UInt32*)buffer + HDR_OFFSET_IN_WORDS;
		obj->end = (UInt32*)buffer + obj->packetSizeInMAUs/sizeof(UInt32);
		obj->primeStatus = TRUE;//EtbDrainer_init(obj);
		return (obj->primeStatus);
	}
	return (FALSE);
}



/*
 * ======== EtbDrain_readyToSend ========
 * returns true if the ETB drain buffer contains unsent data
 *
 */
Bool EtbDrainer_readyToSend(EtbDrainer_Object *obj){
	return (obj->tracePktDownCount > 0);
}
/*
 * ======== EtbDrain_poll ========
 * checks if the ETB drain buffer is over half full and, if so, sends out the data
 *
 */
UInt32 EtbDrainer_poll(EtbDrainer_Object *obj){
	UInt32 bfrThreshold;
	eETB_Error err = eETB_Success;
	ETBStatus status;
	Int index;
	UInt32 maxReadSize = obj->packetSizeInMAUs - (HDR_OFFSET_IN_WORDS + 1)*BYTES_IN_WORD;
	if (!obj->isInitialized){
		EtbDrainer_init(obj);
	}
	if ((obj->tracePktDownCount == 0)&&(obj->tracePktUpCount == 0)){
		status.availableWords = 0;
		if (EtbDrainer_useEtbLib) {
			err = ETB_status((ETBHandle *)obj->etbHandle, &status);
			if(err != eETB_Success)
			{
				/* ETB_status error */
				if (obj->printDebugMessages){
					printf("%d: ETB status error = %d\n",gNumLoops++,err);
				}
				return((UInt32)err);
			}

			if (obj->printDebugMessages){
				printf("%d: status.availableWords = %d\n",gNumLoops,status.availableWords);
			}
			/* Set the buffer threshold value to the last update before the buffer is
			 *  filled by the EDMA. The availableWords value returned from the ETB_status
			 *  call is updated on a etbSize/2 boundary.
			 */
			bfrThreshold = (UInt32)(obj->drainBufSizeInWords/2 - (obj->etbSizeInWords/2));
			if(status.availableWords >= bfrThreshold)
			{

				/* Flush the STM and ETB, then flush the DMA to transfer
				 *  any remaining data from the ETB that hasn't reached the half or
				 *  full thresholds.
				 */
				err = ETB_flushStop((ETBHandle *)obj->etbHandle);
				if(err != eETB_Success)
				{
					/* Threshold ETB_flushStop error */
					if (obj->printDebugMessages){
						printf("%d: ETB flushStop error = %d\n",gNumLoops,err);
					}
					return((UInt32)err);
				}

				index = (obj->transferNumber & 1);

				/* first buffer in use. */
				obj->atbMsgHdrPointer[index] = ETB_getATBMsgHdrPointer(index);//(*((volatile uint32_t*)STM_CONFIG_ATB_MSG_HEAD)) >> 16;

				err = ETB_flush_dma((ETBHandle *)obj->etbHandle, (DMAStatus *)&obj->dmaStatus[index]);
				if (obj->printDebugMessages){
					printf("%d: AFTER ETB_flush_dma: status.availableWords = %d\n",gNumLoops,obj->dmaStatus[index].availableWords);
				}
				if (err == eETB_Overflow){
					// TODO: throw away the data
					if (obj->printDebugMessages){
						printf("%d: ETB flush_dma bfr1 error = eETB_Overflow\n",gNumLoops);
					}

				} else if(err != eETB_Success) 	{
					/* ETB_flush_dma bfr1 error */
					if (obj->printDebugMessages){
						printf("%d: ETB flush_dma bfr1 error = %d\n",gNumLoops,err);
					}
					return((UInt32)err);
				}


				/* Loop through the necessary number of packets to read the data
				 *  from the ETB drain buffer.
				 * - 16 1kB packets.
				 * After the packet has been successfully read, it is written to
				 *  the specified output file.
				 */
				status.availableWords = obj->dmaStatus[index].availableWords;
				if (obj->printDebugMessages){
					printf("EtbDrainer_transferETBData: status.availableWords = %d\n",status.availableWords);
				}
				obj->tracePktDownCount = ((status.availableWords * BYTES_IN_WORD) / maxReadSize);
				obj->tracePktUpCount = 0;
				obj->isFirstPacket = TRUE;
				if (((status.availableWords * BYTES_IN_WORD)%maxReadSize) == 0){
					obj->tracePktDownCount--;
				}
				if (obj->etbType == EtbDrainer_EtbType_STM){
					obj->tracePktDownCount++; /* add one extra packet to carry the STM config data */
				}
				obj->snapshotNumber++;
				if (obj->transferNumber != obj->snapshotNumber ){
					obj->droppedSnapshots++;
				}
				/* Set DMA status to specific buffer's status parameters */
				ETB_setDmaStatus((ETBHandle *)obj->etbHandle, (DMAStatus *)&obj->dmaStatus[index]);

			} else {
				status.availableWords = EtbHook_getNumAvailableWords(obj->etbHandle, obj->etbType, &obj->drainBuf1);
				if(status.availableWords > 0)
				{
					if (obj->printDebugMessages){
						printf("EtbDrainer_transferETBData: status.availableWords = %d\n",status.availableWords);
					}
					obj->tracePktDownCount = ((status.availableWords * BYTES_IN_WORD) / maxReadSize);
					obj->tracePktUpCount = 0;
					obj->isFirstPacket = TRUE;
					if (((status.availableWords * BYTES_IN_WORD)%maxReadSize) == 0){
						obj->tracePktDownCount--;
					}
					if (obj->etbType == EtbDrainer_EtbType_STM){
						obj->tracePktDownCount++; /* add one extra packet to carry the STM config data */
					}
					obj->snapshotNumber++;
					if (obj->transferNumber != obj->snapshotNumber ){
						obj->droppedSnapshots++;
					}

				}
			}
		}
	}
	return((UInt32)err);
}
/****************************************************************************************
 * Status of the STM - this is required to decode the compressed data
 ****************************************************************************************/
Void EtbDrainer_transferSTMConfig(EtbDrainer_Object *obj)
{
	/* ATB Message Header Pointer
	 *  Value stored from the ATB_POINTER register to provide information to determine
	 *  how to interpret the ETB data.
	 */
	int index = obj->snapshotNumber & 1;

	// first word is the value read for the transfer that is being uploaded
	*obj->write++ = ETB_getATBMsgHdrPointer(index) ; //(obj->atbMsgHdrPointer[index] & 0x0FFFF) | (obj->dmaStatus[index].isWrapped << 16);
	index = (index+1) & 1;
	// second word is the value for the previous (or following) transfer.  Can be used to detect changes in status.
	*obj->write++ = ETB_getATBMsgHdrPointer(index); //(obj->atbMsgHdrPointer[index] & 0x0FFFF) | (obj->dmaStatus[index].isWrapped << 16);
	EtbDrainer_sendPacket(obj);
	return;
}

/****************************************************************************************
 * Read and Transfer ETB data
 * move the binary data to PC host via event packets for further
 * decoding and analysis
 ****************************************************************************************/
Bool EtbDrainer_transferData(EtbDrainer_Object *obj, UInt32 maxNumPackets)
{
	eETB_Error  etbRet;
	uint32_t retSize=0;
	UInt32 maxReadSize = obj->packetSizeInMAUs - (HDR_OFFSET_IN_WORDS + 1)*BYTES_IN_WORD;
	int32_t pktCnt;
	int32_t index = ((obj->snapshotNumber-1) & 1);
	Bool done = FALSE;
	uint32_t numWordsTransferred = 0;
	eETB_Error err = eETB_Success;

	if((obj->buffer != NULL)&&((obj->tracePktDownCount > 0)||(obj->tracePktUpCount > 0)))
	{
		/* Loop through the necessary number of packets to read the data
		 *  from the ETB drain buffer.
		 * - 16 1kB packets.
		 * After the packet has been successfully read, it is written to
		 *  the specified output file.
		 */

		pktCnt = 0;

		while ((!done)&&(pktCnt < maxNumPackets)) {

			etbRet = ETB_read((ETBHandle *)obj->etbHandle, obj->write,
					maxReadSize/sizeof(Int32),(obj->tracePktUpCount*maxReadSize)/sizeof(Int32),
					maxReadSize/sizeof(Int32), &retSize);
			numWordsTransferred += retSize;
			if(etbRet != eETB_Success) {
				if (obj->printDebugMessages){
					printf("EtbDrainer_transferETBData: ETB_read error = %d\n",etbRet);
				}
				return(FALSE);
			}
			obj->write += retSize;
			if ((obj->tracePktDownCount == 0)&&(obj->etbType == EtbDrainer_EtbType_STM)){
				/* the last packet needs to contain the STM configuration data */
				EtbDrainer_transferSTMConfig(obj);
			} else {
				EtbDrainer_sendPacket(obj);
			}
			obj->isFirstPacket = FALSE;
			pktCnt++;
			if (obj->tracePktDownCount == 0){
				// Finished uploading the capture buffer.
				// Re-configure the DMA and re-enable the ETB
				done = TRUE;
				obj->tracePktUpCount = 0;
				/* Configure the EMDA for the other buffer, only need to update the address,
				 *  the initial values in the configuration structure stay the same.
				 */
#ifdef USE_TWO_BUFFERS
				if (obj->usingBuffer1){
					obj->dmaConfig.dbufAddress = (UInt32)obj->drainBuf2;
					obj->usingBuffer1 = FALSE;
					if (obj->printDebugMessages){
						printf("%d: Configuring DMA to drain  into Buffer2 (0x%x)\n",gNumLoops,(UInt32)obj->drainBuf2);
					}
				} else {
#endif
					obj->dmaConfig.dbufAddress = (UInt32)obj->drainBuf1;
					obj->usingBuffer1 = TRUE;
					if (obj->printDebugMessages){
						printf("%d: Configuring DMA to drain  into Buffer1 (0x%x)\n",gNumLoops,(UInt32)obj->drainBuf1);
					}
#ifdef USE_TWO_BUFFERS
				}
#endif
				ETB_config_dma((ETBHandle *)obj->etbHandle, (DMAConfig *)&obj->dmaConfig);

				err = ETB_enable((ETBHandle *)obj->etbHandle , 0);
				if(err != eETB_Success)
				{
					/* ETB_enable bfr1 error */
					if (obj->printDebugMessages){
						printf("%d: ETB enable bfr1 error = %d\n",gNumLoops,err);
					}

					return((UInt32)err);
				}
				if (obj->printDebugMessages){
					printf("%d: ETB_config_dma and ETB_enable status ok for transferNumber = %d\n",gNumLoops,obj->transferNumber);
				}

			} else {
				if (obj->printDebugMessages){
					printf("pktCnt=%d: numWordsTransferred = %d out of %d\n",
						obj->tracePktUpCount,(obj->tracePktUpCount*maxReadSize)/sizeof(Int32),obj->dmaStatus[index].availableWords);
				}
				obj->tracePktDownCount--;
				obj->tracePktUpCount++;
			}

		}

	}
	return(TRUE);
}


/*
 *  @(#) ti.uia.runtime; 1, 0, 0, 2,1; 11-17-2011 19:34:26; /db/vtree/library/trees/uia/uia-c26/src/ xlibrary

 */

