/* 
 * 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.
 * */

/*
 *  ======== LoggerSTM.c ========
 */

#include <xdc/runtime/Error.h>
#include <xdc/runtime/Gate.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Diags.h>
#include <ti/uia/runtime/LoggerTypes.h>
#include <xdc/runtime/Memory.h>
#include <xdc/runtime/Startup.h>
#include <xdc/runtime/Types.h>
#include <xdc/runtime/Timestamp.h>
#include <ti/uiactools/runtime/EventHdr.h>
#include <ti/uia/runtime/IUIATransfer.h>
#include <ti/ctools/stmLib/StmLibrary.h>
#include <xdc/runtime/Text.h>
#include <ti/uiactools/runtime/StmEvents.h>
#include <stdint.h>

#include "package/internal/LoggerSTM.xdc.h"
#ifdef xdc_target__isaCompatible_64P
#include <c6x.h>
#else
static UInt32 DNUM=0;
#endif

#define TIMESTAMP                   LoggerSTM_isTimestampEnabled
#define BITS8_IN_EVENTHDR           8
#define BITS8_IN_TIMESTAMP          ((TIMESTAMP & 1) << 3)
#define BITS8_IN_WRITEMEMORY        24
#define BITS8_IN_NUM_ARGS_0         0
#define BITS8_IN_NUM_ARGS_1         4
#define BITS8_IN_NUM_ARGS_2         8
#define BITS8_IN_NUM_ARGS_4         16
#define BITS8_IN_NUM_ARGS_8         32
// BITS8_TO_BITS32(BITS8_IN_EVENTHDR+BITS8_IN_WRITEMEMORY+BITS8_IN_TIMESTAMP)
// = (8 + 24 + (8 or 0))/4 = 10 words if timestamp enabled, else 8 words
#define NUM_WORDS_IN_MEMORYRANGE_EVENT_BUF1 (12)

#define BITS8_TO_BITS32(bits8)      ((bits8) / 4)
#define BITS32_TO_BITS8(bits32)     ((bits32) * 4)
#define MAU_TO_BITS32(mau)          ((mau) / sizeof(Bits32))
#define MAU_TO_BITS32_ROUND_UP(mau) (MAU_TO_BITS32((mau) + sizeof(Bits32) - 1))
#define BITS32_TO_MAU(bits32)       ((bits32) * sizeof(Bits32))
#define BITS8_TO_MAU(bits8)         (BITS32_TO_MAU(BITS8_TO_BITS32(bits8)))
#define MAU_TO_BITS8(mau)           (BITS32_TO_BITS8(MAU_TO_BITS32(mau)))


#ifndef STM_BaseAddress
UInt32 STM_BaseAddress;       /* 0x54100000 for 4K channel boandaries */
#endif
#ifndef STM_ChannelResolution
Int STM_ChannelResolution;    /* 0x1000 for 4K */
#endif

//UInt32 DMA4_BaseAddress = 0x4700A000;    /* DMA4 base address from ARM address space*/
STMHandle* ti_uiactools_runtime_LoggerSTM_stmHandle;
STMConfigObj ti_uiactools_runtime_LoggerSTM_stmConfigObject;


//STMHandle ti_uiactools_runtime_LoggerSTM_stmObject;



/* helper functions */
Bool LoggerSTM_lazyInit(LoggerSTM_Object *obj);
STMEventHandle LoggerSTM_writeHdr(void *obj, STMHandle* pSTMHandle, Types_ModuleId mid, Int numArgs);
Void LoggerSTM_writeToSTM(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, Int numArgs,
		IArg a1, IArg a2, IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8);
Bool LoggerSTM_filterOutEvent(xdc_runtime_Diags_Mask mask);

/*
 *  ======== LoggerSTM_instanceStartup ========
 */
Void LoggerSTM_instanceStartup(LoggerSTM_Object *obj) {
	obj->enabled = TRUE;
}

/*
 *  ======== Log_Module_startup ========
 */
Int LoggerSTM_Module_startup(Int phase) {
	Int i;
	module->sequenceNum = 1;
	module->isInitialized = FALSE;
#ifndef STM_BaseAddress
	STM_BaseAddress = (UInt32)module->stmBaseAdrs;
#else
	module->stmBaseAdrs = STM_BaseAddress;
#endif
#ifndef STM_ChannelResolution
	STM_ChannelResolution = module->stmChannelResolution;
#else
	module->stmChannelResolution = STM_ChannelResolution;
#endif
	ti_uiactools_runtime_LoggerSTM_stmConfigObject.STM_BaseAddress = (UInt32)module->stmBaseAdrs;
	ti_uiactools_runtime_LoggerSTM_stmConfigObject.STM_ChannelResolution = module->stmChannelResolution;
	ti_uiactools_runtime_LoggerSTM_stmConfigObject.pCallBack = NULL;     /*!< This is a pointer to a callback function that if not NULL is
                                                     called on completion of most API functions */
	ti_uiactools_runtime_LoggerSTM_stmConfigObject.optimized_prinf = false;       /*!< If "true" STMXport_printf will generate optimized STM messages.
                                                     This currently only affects the %%s case of a printf format string.
                                                     If optimized_printf is true only a pointer to the %%s constant char
                                                     string is transported.
                                                     If optimized_printf is false, the complete "C" sting (null terminated)
                                                     byte buffer pointed to by %%s is transported.  */

	if (module->endpointId == 0xFFFF){
		module->endpointId = DNUM;
	}

	/* loop over all "permanent" instances and initialize them */
	for (i = 0; i < LoggerSTM_Object_count(); i++) {
		LoggerSTM_instanceStartup(LoggerSTM_Object_get(NULL, i));
	}

	return (Startup_DONE);
}

/*
 *  ======== Instance_init =========
 */
Int LoggerSTM_Instance_init(LoggerSTM_Object *obj,
		const LoggerSTM_Params *prms, Error_Block *eb) {
	obj->enabled = TRUE;
	// maxEventSizeInBits32 determines the length of the wraparound copy
	// area that follows the circular buffer
	obj->maxEventSizeInBits32 = MAU_TO_BITS32(prms->maxEventSize);
	return (0); /* status passed to finalize on error */
}

/*
 *  ======== LoggerSTM_Instance_finalize ========
 */
Void LoggerSTM_Instance_finalize(LoggerSTM_Object *obj, Int status) {
	STMXport_close (ti_uiactools_runtime_LoggerSTM_stmHandle);
}

/*
 *  ======== LoggerSTM_enable ========
 */
Bool LoggerSTM_enable(LoggerSTM_Object *obj) {
	Bool prev = obj->enabled;
	obj->enabled = TRUE;
	return (prev);
}

/*
 *  ======== LoggerSTM_disable ========
 */
Bool LoggerSTM_disable(LoggerSTM_Object *obj) {
	Bool prev = obj->enabled;
	obj->enabled = FALSE;
	return (prev);
}

/*
 *  ======== LoggerSTM_setSTMAdrs ========
 *
 * @param(adrs) the base address for the STM channel that events are to be written to
 */
Void LoggerSTM_setSTMAdrs(Ptr adrs){
	module->stmBaseAdrs = adrs;
#ifndef _CIO
	ti_uiactools_runtime_LoggerSTM_stmConfigObject.STM_BaseAddress = (UInt32)adrs;
#endif
#ifndef STM_BaseAddress
	STM_BaseAddress = (UInt32)adrs;
#endif
}
/*
 *  ======== LoggerSTM_getSTMAdrs ========
 */
Ptr LoggerSTM_getSTMAdrs(){
#ifndef _CIO
	return((Ptr)(UInt)ti_uiactools_runtime_LoggerSTM_stmConfigObject.STM_BaseAddress);
#endif
}

/*
 *  ======== setSTMChannelRangeMin ========
 *  Sets the lowest STM channel number that events are to be written to
 */
Void LoggerSTM_setSTMChannelRangeMin(LoggerSTM_Object *obj, Bits8 chanNum){
	obj->stmChannelRangeMin = chanNum;
	if (obj->stmChannel < chanNum){
		obj->stmChannel = chanNum;
	}
}

/*
 *  ======== getSTMChannelRangeMin ========
 *  Gets the lowest STM channel number that events are to be written to
 */
Bits8 LoggerSTM_getSTMChannelRangeMin(LoggerSTM_Object *obj){
	return((Bits8)(0x0FF & obj->stmChannelRangeMin));
}

/*
 *  ======== setSTMChannelRangeMax ========
 *  Sets the lowest STM channel number that events are to be written to
 */
Void LoggerSTM_setSTMChannelRangeMax(LoggerSTM_Object *obj, Bits8 chanNum){
	obj->stmChannelRangeMax = chanNum;
	if (obj->stmChannel > chanNum){
		obj->stmChannel = chanNum;
	}
}

/*
 *  ======== getSTMChannelRangeMax ========
 *  Gets the lowest STM channel number that events are to be written to
 */
Bits8 LoggerSTM_getSTMChannelRangeMax(LoggerSTM_Object *obj){
	return((Bits8)(0x0FF & obj->stmChannelRangeMax));
}

/*
 *  ======== setProcessId ========
 *  Sets the active process ID to log with the event (default is 0)
 */
Void LoggerSTM_setProcessId(UInt32 value){
	module->processId = value;
}

/*
 * ======== getTransferType ========
 * Returns whether the logger events can be sent over lossy transports or requires reliable transport
 */
ti_uia_runtime_IUIATransfer_TransferType LoggerSTM_getTransferType(LoggerSTM_Object *obj){
	return(ti_uia_runtime_IUIATransfer_TransferType_LOSSY);
}

/*
 * ======== isEmpty ========
 * Returns true if the transfer buffer has no unread data
 */
Bool LoggerSTM_isEmpty(LoggerSTM_Object *obj){
	return(true);
}

/*
 * ======== getContents =========
 * Fills buffer that is passed in with unread data, up to size bytes in length.
 */
Bool LoggerSTM_getContents(LoggerSTM_Object *obj, Ptr hdrBuf, UInt size, /* out */UInt *cpSize){
	return(false);
}

/*
 *  ======== LoggerSTM_filterOutEvent ========
 *  Returns TRUE if the event should be filtered out.
 *  TODO - Might be more clearly written as 'passesFilter'?
 */
Bool LoggerSTM_filterOutEvent(xdc_runtime_Diags_Mask mask)
{
	/*
	 * If filtering for the event's diags category is currently
	 * set to level1...
	 */
	if (LoggerSTM_module->level1 & mask) {
		/* If the event is lower than level1, filter it out. */
		return(Diags_compareLevels(Diags_getLevel(mask), Diags_LEVEL1));
	}
	/*
	 * If filtering for the event's diags category is currently
	 * set to level2...
	 */
	else if (LoggerSTM_module->level2 & mask) {
		/* If the event is lower than level2, filter it out. */
		return(Diags_compareLevels(Diags_getLevel(mask), Diags_LEVEL2));
	}
	/*
	 * If filtering for the event's diags category is currently
	 * set to level3...
	 */
	else if (LoggerSTM_module->level3 & mask) {
		/* If the event is lower than level3, filter it out. */
		return(xdc_runtime_Diags_compareLevels(xdc_runtime_Diags_getLevel(mask),
				xdc_runtime_Diags_LEVEL3));
	}
	/*
	 * Otherwise, the filter level must be level4, which means that events of
	 * all levels should be logged.
	 */
	else {
		return (FALSE);
	}
}
/*
 * ======== lazyInit =========
 * Helper function to avoid having to statically initialize STM
 *
 * returns FALSE if the STM initialization failed.
 */
Bool LoggerSTM_lazyInit(LoggerSTM_Object *obj){
	if (obj == NULL) {
		xdc_runtime_Error_raiseX(NULL, ti_uiactools_runtime_LoggerSTM_Module__id__C, NULL, 0, xdc_runtime_Error_E_generic, (xdc_IArg)"LoggerSTM Object == NULL. Create policy error?", 0);
		return FALSE;
	}
	LoggerSTM_Module_startup(0);
	/* First parameter: A pointer to a STMBufObj. To enable blocking IO pSTMBufObj must be NULL.*/
	ti_uiactools_runtime_LoggerSTM_stmHandle = STMXport_open(NULL,&ti_uiactools_runtime_LoggerSTM_stmConfigObject);

	if (ti_uiactools_runtime_LoggerSTM_stmHandle != NULL){
		module->isInitialized = TRUE;
		STMXport_getVersion( ti_uiactools_runtime_LoggerSTM_stmHandle, &module->majorVersion, &module->minorVersion );
		return TRUE;
	} else {
		return FALSE;
	}
}

/*
 *  ======== writeToSTM =========
 *  Helper function
 */
Void LoggerSTM_writeToSTM(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, Int numArgs,
		IArg a1, IArg a2, IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8) {
	IArg key;
	Types_Timestamp64 tstamp;
	int i = 0;
	int chanNum;
	int numBytes;
	UInt32 intData1[6];
	UInt32 intData2[8];
	int dataSize1Bits32 = 6;
	int dataSize2Bits32 = numArgs;

	/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
	key = Gate_enterSystem();
	chanNum = obj->stmChannel++;
	if (obj->stmChannel > obj->stmChannelRangeMax){
		obj->stmChannel = obj->stmChannelRangeMin;
	}
	module->sequenceNum++;

	Timestamp_get64(&tstamp);
	Gate_leaveSystem(key);

	/* TODO: once DVT can handle out-of-order events, re-enable interrupts here instead of after the STM write...     */
	/*    Gate_leaveSystem(key);                              */

	/*  hdr = ti_uiactools_runtime_LoggerSTM_getOSTHeader((Int) numBytes); */
	numBytes = (numArgs+6)*sizeof(Bits32);
	intData1[i++] = EventHdr_genEventHdrWord1(numBytes,
			(int)module->sequenceNum, EventHdr_HdrType_EventWithTimestampAndEndpointId);
	intData1[i++] = tstamp.lo;
	intData1[i++] = tstamp.hi;
	intData1[i++] = module->endpointId & EventHdr_ENDPOINTID_MASK;
	intData1[i++] = module->processId;
	intData1[i] = ((evt) & 0xffff0000) | mid;
	i = 0;
	intData2[i++] = a1;
	intData2[i++] = a2;
	intData2[i++] = a3;
	intData2[i++] = a4;
	intData2[i++] = a5;
	intData2[i++] = a6;
	intData2[i++] = a7;
	intData2[i] = a8;

	// STMXport_putBuf (ti_uiactools_runtime_LoggerSTM_stmHandle, chanNum, (void *)intData, eWord, numBytes/sizeof(UInt32));
	STMXport_putTwoBufs(ti_uiactools_runtime_LoggerSTM_stmHandle, chanNum, (void *)intData1, eWord, dataSize1Bits32, (void *)intData2, eWord, dataSize2Bits32);

}

/*
 *  ======== LoggerSTM_getInstanceId ========
 */
UInt16 LoggerSTM_getInstanceId(LoggerSTM_Object *obj)
{
	return ((UInt16)0);
}

/*
 *  ======== LoggerSTM_getPriority ========
 */
IUIATransfer_Priority LoggerSTM_getPriority(LoggerSTM_Object *obj)
{
	return (IUIATransfer_Priority_STANDARD);
}

/*
 *  ======== LoggerSTM_setPriority ========
 */
Void LoggerSTM_setPriority(LoggerSTM_Object *obj, IUIATransfer_Priority priority)
{
}
/*
 *  ======== LoggerSTM_getMaxLength ========
 */
SizeT LoggerSTM_getMaxLength(LoggerSTM_Object *obj)
{
	return (0);
}

/*
 *  ======== write0 =========
 *  Write an event with no arguments
 */
Void LoggerSTM_write0(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid) {
	int chanNum;
	IArg key;

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	if (!LoggerSTM_isStringOutputModeEnabled)	{
		LoggerSTM_writeToSTM(obj, evt, mid, 0, 0,0,0,0,0,0,0,0);
	} else {

		/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
		key = Gate_enterSystem();
		chanNum = obj->stmChannel++;
		if (obj->stmChannel > obj->stmChannelRangeMax){
			obj->stmChannel = obj->stmChannelRangeMin;
		}
		module->sequenceNum++;
		Gate_leaveSystem(key);
		LoggerSTM_printToSTM(chanNum,evt,0,0,0,0,0,0,0,0);
	}
}

/*
 *  ======== write1 =========
 *  Write an event with one argument
 */
Void LoggerSTM_write1(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, IArg a1) {
	int chanNum;
	IArg key;

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	if (!LoggerSTM_isStringOutputModeEnabled)	{
		LoggerSTM_writeToSTM(obj, evt, mid, 1, a1,0,0,0,0,0,0,0);
	} else {

		/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
		key = Gate_enterSystem();
		chanNum = obj->stmChannel++;
		if (obj->stmChannel > obj->stmChannelRangeMax){
			obj->stmChannel = obj->stmChannelRangeMin;
		}
		module->sequenceNum++;
		Gate_leaveSystem(key);
		LoggerSTM_printToSTM(chanNum,evt,a1,0,0,0,0,0,0,0);
	}


}

/*
 *  ======== write2 =========
 *
 *  Odd serial numbers indicate a new record, even serial numbers indicate
 *  an "extension" to the previous record.  0 is a sentinal for no record,
 *  but only if it doesn't follow a -1 (0xffffffff).  If a serial number
 *  of 0 follows a serial number of 0xffffffff, it's an extension, otherwise
 *  it's a "no record".
 */
Void LoggerSTM_write2(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, IArg a1, IArg a2) {
	int chanNum;
	IArg key;

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	if (!LoggerSTM_isStringOutputModeEnabled)	{
		LoggerSTM_writeToSTM(obj, evt, mid, 2, a1,a2,0,0,0,0,0,0);
	} else {

		/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
		key = Gate_enterSystem();
		chanNum = obj->stmChannel++;
		if (obj->stmChannel > obj->stmChannelRangeMax){
			obj->stmChannel = obj->stmChannelRangeMin;
		}
		module->sequenceNum++;
		Gate_leaveSystem(key);
		LoggerSTM_printToSTM(chanNum,evt,a1,a2,0,0,0,0,0,0);
	}

}

/*  ======== write4 =========
 *
 *  Odd serial numbers indicate a new record, even serial numbers indicate
 *  an "extension" to the previous record.  0 is a sentinal for no record,
 *  but only if it doesn't follow a -1 (0xffffffff).  If a serial number
 *  of 0 follows a serial number of 0xffffffff, it's an extension, otherwise
 *  it's a "no record".
 */

Void LoggerSTM_write4(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, IArg a1, IArg a2,
		IArg a3, IArg a4){
	int chanNum;
	IArg key;

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	if (!LoggerSTM_isStringOutputModeEnabled)	{
		LoggerSTM_writeToSTM(obj, evt, mid, 4, a1,a2,a3,a4,0,0,0,0);
	} else {

		/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
		key = Gate_enterSystem();
		chanNum = obj->stmChannel++;
		if (obj->stmChannel > obj->stmChannelRangeMax){
			obj->stmChannel = obj->stmChannelRangeMin;
		}
		module->sequenceNum++;
		Gate_leaveSystem(key);
		LoggerSTM_printToSTM(chanNum,evt,a1,a2,a3,a4,0,0,0,0);
	}

}

/*  ======== write8 =========
 *
 *  Odd serial numbers indicate a new record, even serial numbers indicate
 *  an "extension" to the previous record.  0 is a sentinal for no record,
 *  but only if it doesn't follow a -1 (0xffffffff).  If a serial number
 *  of 0 follows a serial number of 0xffffffff, it's an extension, otherwise
 *  it's a "no record".
 */
Void LoggerSTM_write8(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid, IArg a1, IArg a2,
		IArg a3, IArg a4, IArg a5, IArg a6, IArg a7, IArg a8) {
	int chanNum;
	IArg key;

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	if (!LoggerSTM_isStringOutputModeEnabled)	{
		LoggerSTM_writeToSTM(obj, evt, mid, 8, a1,a2,a3,a4,a5,a6,a7,a8);
	} else {

		/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
		key = Gate_enterSystem();
		chanNum = obj->stmChannel++;
		if (obj->stmChannel > obj->stmChannelRangeMax){
			obj->stmChannel = obj->stmChannelRangeMin;
		}
		module->sequenceNum++;
		Gate_leaveSystem(key);
		LoggerSTM_printToSTM(chanNum,evt,a1,a2,a3,a4,a5,a6,a7,a8);
	}

}

/*  ======== writeMemoryRange =========
 *  logs a range of consecutive memory values.
 *
 *  Breaks up large blocks into a series of smaller blocks in order to limit the
 *  maximum amount of time that interrupts are disabled.
 */
Void LoggerSTM_writeMemoryRange(LoggerSTM_Object *obj, xdc_runtime_Log_Event evt, Types_ModuleId mid,
		UInt32 snapshotId, IArg fileName, IArg lineNum, IArg fmt, IArg startAdrs, UInt32 lengthInMAUs) {

	volatile STMEventHandle stmEventHandle;
	Types_Timestamp64 tstamp;
	Int i;
	IArg key;
	SizeT eventSizeBits32;
	SizeT dataSizeBits32;
	Ptr pAdrs = (Ptr)startAdrs;
	SizeT headerSizeBits32;
	SizeT lenAdjustedBits32;
	Int numRecords;
	int chanNum;
	UInt32 intData[NUM_WORDS_IN_MEMORYRANGE_EVENT_BUF1];

	if ((obj == NULL) || (!module->isInitialized)){
		if (!LoggerSTM_lazyInit(obj))
			return;
	}
	/*
	 * If event level filtering is enabled, and the event isn't a high enough
	 * level, drop the record and return.
	 */
	if (LoggerSTM_filterByLevel) {
		if (LoggerSTM_filterOutEvent(Log_getMask(evt))) {
			return;
		}
	}

	/* keep the time that interrupts are disabled to a minimum - use different STM channels for thread safety   */
	key = Gate_enterSystem();
	chanNum = obj->stmChannel++;
	if (obj->stmChannel > obj->stmChannelRangeMax){
		obj->stmChannel = obj->stmChannelRangeMin;
	}
	module->sequenceNum++;

	Timestamp_get64(&tstamp);
	Gate_leaveSystem(key);
	headerSizeBits32 = NUM_WORDS_IN_MEMORYRANGE_EVENT_BUF1;
	lenAdjustedBits32 = MAU_TO_BITS32_ROUND_UP(lengthInMAUs);
	numRecords = (lenAdjustedBits32 / (obj->maxEventSizeInBits32 - headerSizeBits32)) + 1;

	for (i = 0; i < numRecords; i++) {
		if ((headerSizeBits32 + lenAdjustedBits32) > obj->maxEventSizeInBits32) {
			dataSizeBits32 = obj->maxEventSizeInBits32 - headerSizeBits32;
			lenAdjustedBits32 -= dataSizeBits32;
		}
		else {
			dataSizeBits32 = lenAdjustedBits32;
		}
		eventSizeBits32 = dataSizeBits32 + headerSizeBits32;

		/*  hdr = ti_uiactools_runtime_LoggerSTM_getOSTHeader((Int) numBytes); */
		intData[i++] = EventHdr_genEventHdrWord1(BITS32_TO_BITS8(eventSizeBits32),
				(int)module->sequenceNum, EventHdr_HdrType_EventWithSnapshotIdAndTimestampAndEndpointId);
		intData[i++] = tstamp.lo;
		intData[i++] = tstamp.hi;
		intData[i++] = module->endpointId & EventHdr_ENDPOINTID_MASK;
		intData[i++] = module->processId;

		intData[i++] = ((evt) & 0xffff0000) | mid;
		intData[i++] = fileName;
		intData[i++] = lineNum;
		intData[i++] = snapshotId;
		intData[i++] = (Bits32)pAdrs;
		intData[i++] = (((BITS32_TO_MAU(dataSizeBits32) & 0x0FFFF)<<16) |
				(lengthInMAUs & 0x0FFFF));
		intData[i] = fmt;

		STMXport_putTwoBufs(ti_uiactools_runtime_LoggerSTM_stmHandle, chanNum, (void *)intData, eWord, headerSizeBits32, (void *)pAdrs, eWord, dataSizeBits32);


	} /* end for loop   */

}



/*
 *  ======== LoggerSTM_flushAll ========
 */
Void LoggerSTM_flushAll() {
}

/*
 *  ======== LoggerSTM_flushAllInternal ========
 */
Void LoggerSTM_flushAllInternal(Int stat) {
	LoggerSTM_flushAll();
}

/*
 *  ======== LoggerSTM_flush ========
 */
Void LoggerSTM_flush(LoggerSTM_Object *obj) {
}

/*
 *  ======== LoggerSTM_getNextEntry ========
 *  "atomically" read and clear the next entry in the log
 *
 *  Returns:
 *      0   - no entry in the log
 *      1,2 - read one or two complete entries (write4, write8)
 *      -1  - read one but there may be another
 */
Int LoggerSTM_getNextEntry(LoggerSTM_Object *obj, Log_EventRec *evtRec) {
	Int nEntries;
	nEntries = 0;
	return (nEntries);
}

/*
 *  ======== LoggerSTM_setFilterLevel ========
 *  Sets the filter level for the given diags level.
 *
 *  LoggerSTM maintains a separate filter level for every diags category.
 *  This is accomplished by maintaining three masks, one for each of the levels
 *  1 - 3, wich store the diags categories which are currently at that level.
 *  There is no mask for level4; if the diags category is not found in levels
 *  1-3, it is  assumed that the filtering level is level4.
 *
 *  This API is an instance function per the IFilterLogger interface, but
 *  LoggerSTM only maintains module-wide filter levels.
 *
 *  TODO - Should this be conditional on the 'filterByLevel' config?
 */
Void LoggerSTM_setFilterLevel(LoggerSTM_Object *obj,
		xdc_runtime_Diags_Mask mask,
		xdc_runtime_Diags_EventLevel filterLevel)
{
}

/*
 *  ======== LoggerSTM_getFilterLevel ========
 *  Returns the mask of diags categories which are set to the specified filter
 *  level.
 *
 *  This API is an instance function per the IFilterLogger interface, but
 *  LoggerSTM only maintains module-wide filter levels.
 */
Diags_Mask LoggerSTM_getFilterLevel(LoggerSTM_Object *obj,
		xdc_runtime_Diags_EventLevel level)
{
	return (0);
}

/*
 *  ======== LoggerSTM_reset ========
 */
Void LoggerSTM_reset(LoggerSTM_Object *obj)
{
}



