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

/*
 *  ======== BufferUpload.c ========
 */

#include <xdc/std.h>

#include <xdc/runtime/Assert.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Types.h>
#include <xdc/runtime/Timestamp.h>
#include <xdc/runtime/Error.h>

#include <ti/uiactools/runtime/IUIAPacketTransfer.h>
#include <ti/uia/runtime/UIAPacket.h>
#include <ti/uia/runtime/ServiceMgr.h>

#include <ti/uia/runtime/LogSync.h>
#include "package/internal/BufferUpload.xdc.h"

#ifdef xdc_target__bigEndian
#define  ENDIANNESS UIAPacket_PayloadEndian_BIG
#else
#define  ENDIANNESS UIAPacket_PayloadEndian_LITTLE
#endif  

#ifdef xdc_target__isaCompatible_64P
#include <c6x.h>
#else
static UInt32 DNUM=0;
#endif
static Bool hasPrimeBeenCalled = FALSE;
static Bool ti_uiactools_services_BufferUpload_isNDKRunning = FALSE;

Bool BufferUpload_isDataTx();
/*
 *  ======== BufferUpload_swizzle ========
 *  Perform 32 bit swizzle if the endianness of payload in the packet
 *  is different than the target.
 */
UArg BufferUpload_swizzle(UIAPacket_Hdr *packet, UArg arg)
{
	if (UIAPacket_getPayloadEndianness(packet) == ENDIANNESS) {
		return (arg);
	}

	return (UIAPacket_swizzle(arg));
}   

/*
 *  ======== BufferUpload_sendEvents ========
 */
Void BufferUpload_sendEvents()
{
	UInt i;
	IUIAPacketTransfer_Handle hBufferPacketizer;
	UIAPacket_Hdr *packet;

	/*
	 *  Only send data to the host if the "start" command has been issued
	 *  or if the period was configured to a non-zero value.
	 */
//	if ((BufferUpload_module->txData == TRUE) ||(TRUE))  {
	if ((BufferUpload_module->txData == TRUE) ||(ti_uiactools_services_BufferUpload_isNDKRunning))  {
		/* Send up the logs in order of priority, from highest to lowest */
		for (i = 0; i < BufferUpload_module->numBufs; i++) {
			hBufferPacketizer = BufferUpload_module->hBufferPacketizers[i];

			// prime if needed
			if (!hasPrimeBeenCalled){
				/* Get a packet. */
				packet = ServiceMgr_getFreePacket(UIAPacket_HdrType_EventPkt,
						ServiceMgr_WAIT_FOREVER);
				IUIAPacketTransfer_prime(hBufferPacketizer,packet);
				hasPrimeBeenCalled = TRUE;
			}
			/*
			 *  Transfer the data.
			 */

			IUIAPacketTransfer_poll(hBufferPacketizer);
			if (IUIAPacketTransfer_readyToSend(hBufferPacketizer)){
				IUIAPacketTransfer_transferData(hBufferPacketizer,BufferUpload_maxNumConsecutivePackets);
			}

		}

	}
}





/*
 *  ======== BufferUpload_processCallback ========
 */
Void BufferUpload_processCallback(ServiceMgr_Reason reason, UIAPacket_Hdr *packet)
{
	if (reason == ServiceMgr_Reason_PERIODEXPIRED) {
		BufferUpload_sendEvents();
	}
	else if (reason == ServiceMgr_Reason_INCOMINGMSG) {
		BufferUpload_processMsg(packet);
	}
}

/*
 *  ======== BufferUpload_processMsg ========
 */
Void BufferUpload_processMsg(UIAPacket_Hdr *packet)
{
	Bool status;
	BufferUpload_Command cmdId;
	UArg arg0;
	UArg arg1;
	BufferUpload_Packet *resp;
	BufferUpload_Packet *cmd = (BufferUpload_Packet *)packet;
	UIAPacket_MsgType msgType = UIAPacket_MsgType_ACK;

	/* Grab a free packet */
	resp = (BufferUpload_Packet *)ServiceMgr_getFreePacket(UIAPacket_HdrType_Msg,
			ServiceMgr_WAIT_FOREVER);

	/* Extract the actual BufferUpload command */
	cmdId = (BufferUpload_Command)UIAPacket_getCmdId(packet);

	arg0 = BufferUpload_swizzle(packet, cmd->arg0);
	arg1 = BufferUpload_swizzle(packet, cmd->arg1);

	/* Log receipt of a command. */
	Log_write3(BufferUpload_LD_cmdRcvd, cmdId, arg0, arg1);

	/* Handle the command. */
	switch(cmdId) {
	case BufferUpload_Command_BUF_OFF:
		BufferUpload_disableBuffer(arg0);
		break;
	case BufferUpload_Command_BUF_ON:
		BufferUpload_enableBuffer(arg0);
		break;
	case BufferUpload_Command_GET_CPU_SPEED:
		BufferUpload_getCpuSpeed(resp);
		break;
	case BufferUpload_Command_RESET_BUF:
		BufferUpload_resetBuffer(arg0);
		break;
	case BufferUpload_Command_CHANGE_PERIOD:
		BufferUpload_changePeriod(arg0);
		break;
	case BufferUpload_Command_START_TX:
		BufferUpload_startDataTx();
		break;
	case BufferUpload_Command_STOP_TX:
		BufferUpload_stopDataTx();
		break;
	case BufferUpload_Command_BUF_OFF_ALL:
		BufferUpload_disableAllBuffers();
		break;
	case BufferUpload_Command_BUF_ON_ALL:
		BufferUpload_enableAllBuffers();
		break;
	case BufferUpload_Command_RESET_BUF_ALL :
		BufferUpload_resetAllBuffers();
		break;
	case BufferUpload_Command_SNAPSHOT_ALL:
		BufferUpload_snapshotAllBuffers(arg0, arg1);
		break;
	default:
		msgType = UIAPacket_MsgType_NACK_BAD_DATA;
		break;
	}

	/* ServiceMgr module fills in the src addresses */
	UIAPacket_initMsgHdr((UIAPacket_Hdr *)resp, ENDIANNESS,
			msgType, sizeof(BufferUpload_Packet),
			BufferUpload_SERVICEID, UIAPacket_getSequenceCount(packet),
			cmdId, UIAPacket_getTag(packet), UIAPacket_HOST, (~0));

	/* Send the response back to the host */
	status = ServiceMgr_sendPacket((UIAPacket_Hdr *)resp);
	if (status == FALSE) {
		ServiceMgr_freePacket((UIAPacket_Hdr *)resp);
	}
}


/*
 *  ======== BufferUpload_enableAllBuffers ========
 */
Void BufferUpload_enableAllBuffers()
{
	UInt i;

	for (i = 0; i < BufferUpload_module->numBufs; i++) {
		BufferUpload_enableBuffer(i);
	}
}

/*
 *  ======== BufferUpload_snapshotAllBuffers ========
 */
Void BufferUpload_snapshotAllBuffers(UArg reset, UArg waitPeriod)
{
	/*
    UInt logNum;        
    IUIAPacketTransfer_Handle hBufferPacketizer;

    BufferUpload_module->snapshot = TRUE;

    if ((Bool)reset == TRUE) {
        for (logNum = 0; logNum < BufferUpload_module->numBufs; logNum++) {

             Retrieve the hBufferPacketizer from the Agent's list.
            hBufferPacketizer = BufferUpload_module->etbs[logNum];
            IUIAPacketTransfer_reset(hBufferPacketizer);
        }
    }

    LogSync_writeSyncPoint();

    ServiceMgr_setPeriod(BufferUpload_SERVICEID, (UInt)waitPeriod);
	 */
}

/*
 *  ======== BufferUpload_enableEtb ========
 */
Void BufferUpload_enableBuffer(UArg log)
{
	UInt32 logNum = (UInt32) log;
	IUIAPacketTransfer_Handle hBufferPacketizer;

	if (logNum < BufferUpload_module->numBufs) {

		/* Retrieve the hBufferPacketizer from the Agent's list. */
		hBufferPacketizer = BufferUpload_module->hBufferPacketizers[logNum];

		IUIAPacketTransfer_enable(hBufferPacketizer);
	}
}

/*
 *  ======== BufferUpload_disableAllBuffers ========
 */
Void BufferUpload_disableAllBuffers()
{
	UInt i;

	for (i = 0; i < BufferUpload_module->numBufs; i++) {
		BufferUpload_disableBuffer(i);
	}
}

/*
 *  ======== BufferUpload_disableBuffer ========
 */
Void BufferUpload_disableBuffer(UArg log)
{
	UInt32 logNum = (UInt32) log;
	IUIAPacketTransfer_Handle hBufferPacketizer;

	if (logNum < BufferUpload_module->numBufs) {

		/* Retrieve the hBufferPacketizer from the Agent's list. */
		hBufferPacketizer = BufferUpload_module->hBufferPacketizers[logNum];

		IUIAPacketTransfer_disable(hBufferPacketizer);
	}
}

/*
 *  ======== BufferUpload_resetAllBuffers ========
 */
Void BufferUpload_resetAllBuffers()
{
	/*    UInt i;

    for (i = 0; i < BufferUpload_module->numBufs; i++) {
        BufferUpload_resetEtb(i);
    }*/
}

/*
 *  ======== BufferUpload_resetEtb ========
 */
Void BufferUpload_resetBuffer(UArg log)
{
	/*
    UInt32 logNum = (UInt32) log;
    IUIAPacketTransfer_Handle hBufferPacketizer;

    if (logNum < BufferUpload_module->numBufs) {

         Retrieve the hBufferPacketizer from the Agent's list.
        hBufferPacketizer = BufferUpload_module->etbs[logNum];

         Reset the hBufferPacketizer
        IUIAPacketTransfer_reset(hBufferPacketizer);

        LogSync_writeSyncPoint();
    }
	 */
}

/*
 *  ======== BufferUpload_changePeriod ========
 */
Void BufferUpload_changePeriod(UArg period)
{
	/* Store in module state */
	BufferUpload_module->period = period;

	/* Update the ServiceMgr module if BufferUpload_Command_START_TX was done. */
	if (BufferUpload_module->txData == TRUE) {
		ServiceMgr_setPeriod(BufferUpload_SERVICEID, (UInt)period);
	}
}

/*
 *  ======== BufferUpload_startDataTx ========
 */
Void BufferUpload_startDataTx()
{
	BufferUpload_module->txData = TRUE;
	ServiceMgr_setPeriod(BufferUpload_SERVICEID, BufferUpload_module->period);

	/*
	 * Etb a sync point event to ensure that there
	 * is enough info to interpret the event timestamps
	 * properly.
	 */
	LogSync_writeSyncPoint();
}

/*
 *  ======== BufferUpload_stopDataTx ========
 */
Void BufferUpload_stopDataTx()
{
	BufferUpload_module->txData = FALSE;

	/*
	 * Reset to initial value. If a different host starts a session,
	 * it should not inherit the previous host's period request.
	 */
	BufferUpload_module->period = BufferUpload_periodInMs;
	ServiceMgr_setPeriod(BufferUpload_SERVICEID, 0);

	/*
	 * Etb a sync point event so that all events logged
	 * from this point on will have enough info to
	 * interpret their timestamps properly
	 */
	LogSync_writeSyncPoint();
}

/*!
 * ====== isDataTx ========
 * returns true if DataTx is active
 */
Bool BufferUpload_isDataTx(){
	return(BufferUpload_module->txData || ti_uiactools_services_BufferUpload_isNDKRunning);
}
/*
 *  ======== BufferUpload_getCpuSpeed ========
 */
Void BufferUpload_getCpuSpeed(BufferUpload_Packet *resp)
{
	Types_FreqHz freq;

	/* Get the Timestamp frequency. */
	Timestamp_getFreq(&freq);

	resp->arg0 = freq.hi;
	resp->arg1 = freq.lo;
}

/*
 * bufferExchange callback for the EtbDrainer
 */
Ptr BufferUpload_packetBufferExchange(Ptr hBufferPacketizer, Ptr full)
{
	UIAPacket_Hdr *packet;
	Bool status;

	/* Send the the packet. */
	status = ServiceMgr_sendPacket(full);
	if (status == TRUE) {
		/* Track how many records sent for ROV. */
		BufferUpload_module->totalPacketsSent++;
	} else {
		ServiceMgr_freePacket(full);
	}

	/* Get another packet, initialize it's packet header and return it back to the Buffer Packetizer. */
	packet = ServiceMgr_getFreePacket(UIAPacket_HdrType_EventPkt,
			ServiceMgr_WAIT_FOREVER);
	EtbDrainer_initBuffer(packet,DNUM,0);
	return packet;
}
