/**
 * 	\file 	main.cpp
 * 
 * 	\brief 	DSP side main routine for DSP Hello World application.
 * 			The DSP simply sets itself up, and then waits for a 
 * 			message from the ARM, to which it replies. 
 *
 *     o  0
 *     | /       Copyright (c) 2005-2010
 *    (CL)---o   Critical Link, LLC
 *      \
 *       O
 */

#include <std.h>
#include <tsk.h>
#include <stdio.h>
#include <string.h>

#include "core/cl_ipc_inbound.h"
#include "core/cl_ipc_outbound.h"

using namespace MityDSP;

// Forward declarations
void init();
void debugPrint(char *buffer);
int handleInboundMessage(void *apBuffer, uint32_t anLength, void *apUserArg) ;

// Object for sending debug messages (these are received and printed to stdout by tcDspApp)
tcCL_IPCOutbound* 	gpDebug;
// Object for sending GPPMSGQ1 messages that the ARM will receive
tcCL_IPCOutbound* 	gpOutbound;
// Object for receiving DSPMSGQ0 messages that the DSP will receive
tcCL_IPCInbound* 	gpInbound;

/**
 * 	Main routine. 
 */
int main(int argc, char* argv[])
{
	// initialize the DSPLink system
	tcCL_IPCInit::GetInstance();  
	
	// Launch an initialization task
   	TSK_Attrs* lpAttrs = new TSK_Attrs;
    *lpAttrs           = TSK_ATTRS;
    lpAttrs->name      = "Initialize";
    lpAttrs->stacksize = 8192*2;
    lpAttrs->priority  = 5;
   	TSK_create((Fxn)init,lpAttrs);
    
    return 0;
}
  
/**
 *	Initialize the inbound and outbound IPC objects. 
 * 
 * 	\return None.
 */
void init()
{  
	// Message to ARM core. 
	char lpReturnMessage[] = "DSP Initialization finished.";
	// Buffer for return message
	char* lpMessageBuffer = NULL;

	// Create the outbound debug link
	gpDebug = new tcCL_IPCOutbound("debug");

	// Create the inbound link for messages to the DSP
   	gpInbound = new tcCL_IPCInbound();

   	gpInbound->Open("DSPMSGQ0", 8);

	// Create the outbound controller for sending messages to the ARM
   	gpOutbound = new tcCL_IPCOutbound("GPPMSGQ1");

	if (NULL != gpInbound)
	{
		// Register a callback function to handle messages from the ARM
   		gpInbound->RegisterCallback(handleInboundMessage, (void*)NULL);
	}
	
	// Now that initialization is complete, let the ARM know with a message

	// Obtain a dsplink buffer for the return message
	lpMessageBuffer = (char*)gpOutbound->GetBuffer(strlen(lpReturnMessage) + 1); 
	
	// Make sure we received a valid buffer
	if (NULL != lpMessageBuffer)
	{
		// Copy our message to the buffer
		strcpy(lpMessageBuffer, lpReturnMessage);
	
		// Send the message back to the ARM
		gpOutbound->SendMessage(lpMessageBuffer, strlen(lpMessageBuffer)+1);
	}
}

/**
 * 	Callback function that handles messages from the ARM.
 * 
 * 	\param apBuffer		Pointer to message buffer.
 * 	\param anLength		Length of message.
 * 	\param apUserArg	Pointer to user defined argument
 * 
 * 	\return 0 on sucess. 
 */
int handleInboundMessage(void* apBuffer, uint32_t anLength, void* apUserArg) 
{
	int retval = 0;
	// The return message to the ARM
	char lpReturnMessage[] = "Hello Word. DSP Received Message = \'";
	// Buffer for return message
	char* lpMessageBuffer = NULL;
	
	// Obtain a dsplink buffer for the return message
	lpMessageBuffer = (char*)gpOutbound->GetBuffer(strlen(lpReturnMessage) + strlen((const char*)apBuffer) + 2); 
	
	// Make sure we received a valid buffer
	if (NULL != lpMessageBuffer)
	{
		// Copy our message to the buffer
		strcpy(lpMessageBuffer, lpReturnMessage);
		// Append the received message to the buffer
		strcpy((char*)&lpMessageBuffer[strlen(lpReturnMessage)], (const char *)apBuffer);
		// Null terminate the string
		lpMessageBuffer[strlen(lpMessageBuffer)+1] = 0;
		// Append the closing quotation
		lpMessageBuffer[strlen(lpMessageBuffer)] = '\'';
	
		// Send the message back to the ARM
		retval = gpOutbound->SendMessage(lpMessageBuffer, strlen(lpMessageBuffer)+1);
	}
	else
	{
		retval = -1;	
	}
	
	return retval;
}

/**
 * 	Function for sending debug messages to the ARM.
 * 
 * 	\param buffer	Null terminated string to be printed.
 * 
 * 	\return None. 
 */
void debugPrint(char* pMsg)
{
	// The length of the message to be sent
	int len = strlen(pMsg);
   	// Pointer to dsplink buffer where to write the message
	char* pBuffer;
	
	// Make sure the debug IPC outbound object has been initialized 
	if (gpDebug == NULL) 
		return;
	
	// Get a buffer for the message
	pBuffer = (char *)gpDebug->GetBuffer(len+1); 
	
	// Check that the buffer is valid
	if (pBuffer) 
	{
		// Copy the message to the buffer
		strcpy(pBuffer, pMsg);
		// Send the message
		gpDebug->SendMessage(pBuffer, len+1);
	}
}

