/**************************************************************
$Workfile:   elmdeferred.c  $
***************************************************************
**
** FIRMWARE, Copyright (C) 2000-2002
** Ikanos Communications, Fremont, CA
** All rights reserved. 
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of
** Ikanos Communication
**
$Revision: 1.1 $
$Date: 2006/10/16 04:34:50 $
***************************************************************/


/**************************************************************

	This file contains functions for 
		ELM related Apps:
		
**************************************************************/

#ifdef VTU_R

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

#include "ipos.h"
#include "appconfig.h"
#include "apperrCode.h"
#include "apposmacro.h"
#include "portmap.h"
#include "oamp.h"

#include "elmlocal.h"
#include "elmdeferred.h"

/* This struct MUST match the oamp_cb_msg struct in oampfuncs.c !! */

typedef	struct
{
	ipos_port_id	portId;
	U8		uid;
	int		status;
	int		cntRpt;			/* repeat counter	*/
	int		parLen;
	char		par[128];		/* parameters	*/
} oamp_cb_msg_elm;


/* OAMP job, except this one has no message (3rd argument NULL) */

static	int
cpeAckHandlerJob( ipos_elm_cpe *pCpePe, int status, void *par)
{
	int	errCode;
	U16	currBlkIdx;

	int	TXSPEED = 15;

	/* if NACK, send the data again	*/
	if(status!=IPOS_SUCCESS)
	{
	     /*printf( "cpeAckHandlerJob resending %d\n", pCpePe->currBlkIdx );*/
		 errCode= cpeSendDataPkt(pCpePe,&(pCpePe->currBlk),pCpePe->currBlkIdx);
		 return	errCode;
	}

	/* if ACK, advance the index:	*/
	iposTaskDelay(TXSPEED);					/* Speed adjustment	*/
	pCpePe->currBlkIdx++;

	while(pCpePe->currBlkIdx < pCpePe->lastBlkIdx+1)  /* index to the end	?	*/
	{
		currBlkIdx=pCpePe->currBlkIdx;		
		if(pCpePe->flgAck[currBlkIdx]>=0)
		{
			if(pCpePe->flgAck[currBlkIdx] > IPOSELM_DATABLK_RESEND)
			{
#ifdef ELM_DIAGNOSTIC_DEBUG
			   printf("\nIndx=%d, cnt=%d\n", currBlkIdx,pCpePe->flgAck[currBlkIdx]); 
#endif
				cpeErrorHandler(pCpePe, 0);
				return IPOS_ERROR;
			}

			cpeGetDataBlk(pCpePe);
			cpeSendDataPkt(pCpePe, &(pCpePe->currBlk), pCpePe->currBlkIdx);
			return	IPOS_SUCCESS;
		}

		pCpePe->currBlkIdx++;

	}
	
	/* if nothing to send: restart (effect is to resend unacknowledged packets) */
	if(pCpePe->currBlkIdx==pCpePe->lastBlkIdx+1)
	{
		cpeStart(pCpePe);			/* add job here?	*/
	}

	return	IPOS_SUCCESS;
}

int
submitJobCpeAckHandler( ipos_port_id pid, int status )
{
	ipos_elm_cpe	*pCpePe;

	pCpePe=iposELMGetCpePe( pid );

	if(pCpePe==NULL)
	{
#ifdef ELM_DIAGNOSTIC_DEBUG
		printf("Cannot locate CPE PE object for b%dp%d in submitJobCpeSendAckHandler\n",
			pid.bmeNum, pid.portNum );
#endif
		return( IPOS_ERROR );
	}

/* this goes to the non-blocking OAMP task ... */

	if (appOampJobAdd( 0, (appOampFunc) cpeAckHandlerJob, (U32) pCpePe, status, NULL ) !=
		IPOS_SUCCESS)
	{				/* no message buffer to free ... */
		return( IPOS_ERROR );
	}

	return( IPOS_SUCCESS );
}

static	void
getNewBmeEventLogJob(U32 arg1, U32 arg2, ipos_msg_buf *pBuf)
{
	oamp_cb_msg		*pMsg;
	ipos_port_id		 pid;
	int			 errCode;
	U8			 uid;
	U8			*eventLogAddr = NULL;
	U32			 thisEventLogSize, thisEventLogCheckSum;
	ipos_elm_cpe		*pCpePe = NULL;

	if(pBuf==NULL)
	{
#ifdef ELM_DIAGNOSTIC_DEBUG
		printf("Invalid msg buffer in getNewBMEEventLogJob\n");
#endif
		return;
	}

	pMsg=(oamp_cb_msg *) pBuf->pDataBuf;
	pid=pMsg->portId;
	uid=pMsg->uid;

	pCpePe = iposELMGetCpePe( pid );
	if (pCpePe != NULL)
	{
		eventLogAddr = pCpePe->addrEventLog;

	/* 4th argument says the BME is NOT hung.  Since we got this job from the BME
	   interface, that seems reasonable */

		errCode = iposGetBmeEventLog( pid.bmeNum, 
				eventLogAddr, DEFAULT_EVENT_LOG_SIZE,
				eELM_BME_IS_RESPONSIVE,
				uid, 0, NULL );
		thisEventLogSize = iposSizeofEventLog( eventLogAddr, DEFAULT_EVENT_LOG_SIZE );
		thisEventLogCheckSum = iposRFMGetCheckSum( eventLogAddr, thisEventLogSize );

		pCpePe->fileInfo.size = thisEventLogSize;
		pCpePe->fileInfo.checkSum = thisEventLogCheckSum;
	    /*printf( "getNewBmeEventLogJob, size: %ld, check sum: %ld\n",
		     pCpePe->fileInfo.size, pCpePe->fileInfo.checkSum
	    );*/
	}
	else
	{
#ifdef ELM_DIAGNOSTIC_DEBUG
		printf(
	    "Cannot get CPE PE object in getNewBmeEventLogJob for port b%dp%d\n",
	     pid.bmeNum, pid.portNum
		);
#endif
		thisEventLogSize = 0;
		thisEventLogCheckSum = 0;
		errCode = IPOS_ERROR;
	}

	iposELMCPEGetEventLogResp( pid, uid, errCode, thisEventLogSize, thisEventLogCheckSum );

	/* release the message	*/
	iposMsgFree(pBuf);
}

/* a new BME log should not be extracted in the context of a callback
   tests show it takes from 500 ms to 1 s for iposGetBmeEventLog to complete
   here an OAMP job is submitted, to the blocking OAMP task for the bme   */

/* two error returns:  no more ipos message buffers and failed to submit
   the OAMP job to the proper message queue				*/

int
submitJobNewBmeEventLog( int bmeNum, U8 uid )
{
	ipos_msg_buf	*pBuf;
	oamp_cb_msg_elm *pMsg;
	ipos_port_id	 pid;

	pBuf=iposMsgGet();
	if(pBuf==NULL)
	{
		printf("Failed to get a msg buffer in submitJobNewBmeEventLog\n");
		return( IPOS_ERROR );
	}

	pid.bmeNum = bmeNum;
	pid.portNum = 1;

	pBuf->len=sizeof(oamp_cb_msg_elm);
	
	pMsg=(oamp_cb_msg_elm *) pBuf->pDataBuf;
	pMsg->portId=pid;
	pMsg->uid=uid;
	pMsg->parLen=0;			/* pMsg->par is empty */
	pMsg->status=IPOS_SUCCESS;
	pMsg->cntRpt=0;

	if (appOampJobAdd( pid.bmeNum, getNewBmeEventLogJob, 0, 0, pBuf ) != IPOS_SUCCESS)
	{
		iposMsgFree(pBuf);
		return( IPOS_ERROR );
	}

	return( IPOS_SUCCESS );
}
#endif  /* VTU_R */
