/**
 *
 * \file
 *
 * \brief This module contains M2M host interface APIs implementation.
 *
 * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
 *
 * \asf_license_stop
 *
 */

#include "common/include/nm_common.h"
#include "driver/source/nmbus.h"
#include "bsp/include/nm_bsp.h"
#include "m2m_hif.h"
#include "driver/include/m2m_types.h"
#include "driver/source/nmasic.h"
#include "driver/include/m2m_periph.h"

#if (defined NM_EDGE_INTERRUPT)&&(defined NM_LEVEL_INTERRUPT)
#error "only one type of interrupt NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT"
#endif

#if !((defined NM_EDGE_INTERRUPT)||(defined NM_LEVEL_INTERRUPT))
#error "define interrupt type NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT"
#endif

#ifndef CORTUS_APP
#define NMI_AHB_DATA_MEM_BASE  0x30000
#define NMI_AHB_SHARE_MEM_BASE 0xd0000

#define WIFI_HOST_RCV_CTRL_0	(0x1070)
#define WIFI_HOST_RCV_CTRL_1	(0x1084)
#define WIFI_HOST_RCV_CTRL_2    (0x1078)
#define WIFI_HOST_RCV_CTRL_3    (0x106c)
#define WIFI_HOST_RCV_CTRL_4	(0x150400)
#define WIFI_HOST_RCV_CTRL_5	(0x1088)

typedef struct {
 	uint8 u8ChipMode;
 	uint8 u8ChipSleep;
 	uint8 u8HifRXDone;
 	uint8 u8Interrupt;
 	uint32 u32RxAddr;
 	uint32 u32RxSize;
	tpfHifCallBack pfWifiCb;
	tpfHifCallBack pfIpCb;
	tpfHifCallBack pfOtaCb;
	tpfHifCallBack pfSigmaCb;
	tpfHifCallBack pfHifCb;
	tpfHifCallBack pfCryptoCb;
	tpfHifCallBack pfSslCb;
}tstrHifContext;

volatile tstrHifContext gstrHifCxt;

static void isr(void)
{
	gstrHifCxt.u8Interrupt++;
#ifdef NM_LEVEL_INTERRUPT
	nm_bsp_interrupt_ctrl(0);
#endif
}
static sint8 hif_set_rx_done(void)
{
	uint32 reg;
	sint8 ret = M2M_SUCCESS;

	gstrHifCxt.u8HifRXDone = 0;
#ifdef NM_EDGE_INTERRUPT
	nm_bsp_interrupt_ctrl(1);
#endif
	ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0,&reg);
	if(ret != M2M_SUCCESS)goto ERR1;
	/* Set RX Done */
	reg |= NBIT1;
	ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0,reg);
	if(ret != M2M_SUCCESS)goto ERR1;
#ifdef NM_LEVEL_INTERRUPT
	nm_bsp_interrupt_ctrl(1);
#endif
ERR1:
	return ret;

}
/**
*	@fn			static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
*	@brief		WiFi call back function
*	@param [in]	u8OpCode
*					HIF Opcode type.
*	@param [in]	u16DataSize
*					HIF data length.
*	@param [in]	u32Addr
*					HIF address.
*	@param [in]	grp
*					HIF group type.
*	@author
*	@date
*	@version	1.0
*/
static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
{
#ifdef ARDUINO
	// Silence "unused" warning
	(void)u8OpCode;
	(void)u16DataSize;
	(void)u32Addr;
#endif
}
/**
*	@fn		NMI_API sint8 hif_chip_wake(void);
*	@brief	To Wakeup the chip.
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_chip_wake(void)
{
	sint8 ret = M2M_SUCCESS;
	if(gstrHifCxt.u8HifRXDone)
	{
		/*chip already wake for the rx not done no need to send wake request*/
		return ret;
	}
	if(gstrHifCxt.u8ChipSleep == 0)
	{
		if(gstrHifCxt.u8ChipMode != M2M_NO_PS)
		{
			ret = chip_wake();
			if(ret != M2M_SUCCESS)goto ERR1;
		}
		else
		{
		}
	}
	gstrHifCxt.u8ChipSleep++;
ERR1:
	return ret;
}
/*!
@fn	\
	NMI_API void hif_set_sleep_mode(uint8 u8Pstype);

@brief
	Set the sleep mode of the HIF layer.

@param [in]	u8Pstype
				Sleep mode.

@return
	The function SHALL return 0 for success and a negative value otherwise.
*/

void hif_set_sleep_mode(uint8 u8Pstype)
{
	gstrHifCxt.u8ChipMode = u8Pstype;
}
/*!
@fn	\
	NMI_API uint8 hif_get_sleep_mode(void);

@brief
	Get the sleep mode of the HIF layer.

@return
	The function SHALL return the sleep mode of the HIF layer.
*/

uint8 hif_get_sleep_mode(void)
{
	return gstrHifCxt.u8ChipMode;
}

/**
*	@fn		NMI_API sint8 hif_chip_sleep_sc(void);
*	@brief	To clear the chip sleep but keep the chip sleep
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_chip_sleep_sc(void)
{
	if(gstrHifCxt.u8ChipSleep >= 1)
	{
		gstrHifCxt.u8ChipSleep--;
	}
	return M2M_SUCCESS;
}
/**
*	@fn		NMI_API sint8 hif_chip_sleep(void);
*	@brief	To make the chip sleep.
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_chip_sleep(void)
{
	sint8 ret = M2M_SUCCESS;

	if(gstrHifCxt.u8ChipSleep >= 1)
	{
		gstrHifCxt.u8ChipSleep--;
	}
	
	if(gstrHifCxt.u8ChipSleep == 0)
	{
		if(gstrHifCxt.u8ChipMode != M2M_NO_PS)
		{
			ret = chip_sleep();
			if(ret != M2M_SUCCESS)goto ERR1;

		}
		else
		{
		}
	}
ERR1:
	return ret;
}
/**
*   @fn		NMI_API sint8 hif_init(void * arg);
*   @brief	To initialize HIF layer.
*   @param [in]	arg
*				Pointer to the arguments.
*   @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_init(void * arg)
{
#ifdef ARDUINO
	(void)arg; // Silence "unused" warning
#endif
	m2m_memset((uint8*)&gstrHifCxt,0,sizeof(tstrHifContext));
	nm_bsp_register_isr(isr);
	hif_register_cb(M2M_REQ_GROUP_HIF,m2m_hif_cb);
	return M2M_SUCCESS;
}
/**
*	@fn		NMI_API sint8 hif_deinit(void * arg);
*	@brief	To De-initialize HIF layer.
*    @param [in]	arg
*				Pointer to the arguments.
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/
sint8 hif_deinit(void * arg)
{
#ifdef ARDUINO
	(void)arg; // Silence "unused" warning
#endif
	sint8 ret = M2M_SUCCESS;
	ret = hif_chip_wake();
	m2m_memset((uint8*)&gstrHifCxt,0,sizeof(tstrHifContext));
	return ret;
}
/**
*	@fn		NMI_API sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize,
					   uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset)
*	@brief	Send packet using host interface.

*	@param [in]	u8Gid
*				Group ID.
*	@param [in]	u8Opcode
*				Operation ID.
*	@param [in]	pu8CtrlBuf
*				Pointer to the Control buffer.
*	@param [in]	u16CtrlBufSize
				Control buffer size.
*	@param [in]	u16DataOffset
				Packet Data offset.
*	@param [in]	pu8DataBuf
*				Packet buffer Allocated by the caller.
*	@param [in]	u16DataSize
				Packet buffer size (including the HIF header).
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize,
			   uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset)
{
	sint8		ret = M2M_ERR_SEND;
	volatile tstrHifHdr	strHif;

	strHif.u8Opcode		= u8Opcode&(~NBIT7);
	strHif.u8Gid		= u8Gid;
	strHif.u16Length	= M2M_HIF_HDR_OFFSET;
	if(pu8DataBuf != NULL)
	{
		strHif.u16Length += u16DataOffset + u16DataSize;
	}
	else
	{
		strHif.u16Length += u16CtrlBufSize;
	}
	ret = hif_chip_wake();
	if(ret == M2M_SUCCESS)
	{
		volatile uint32 reg, dma_addr = 0;
		volatile uint16 cnt = 0;
//#define OPTIMIZE_BUS 
/*please define in firmware also*/
#ifndef OPTIMIZE_BUS
		reg = 0UL;
		reg |= (uint32)u8Gid;
		reg |= ((uint32)u8Opcode<<8);
		reg |= ((uint32)strHif.u16Length<<16);
		ret = nm_write_reg(NMI_STATE_REG,reg);
		if(M2M_SUCCESS != ret) goto ERR1;

		reg = 0UL;
		reg |= NBIT1;
		ret = nm_write_reg(WIFI_HOST_RCV_CTRL_2, reg);
		if(M2M_SUCCESS != ret) goto ERR1;
#else
		reg = 0UL;
		reg |= NBIT1;
		reg |= ((u8Opcode & NBIT7) ? (NBIT2):(0)); /*Data = 1 or config*/
		reg |= (u8Gid == M2M_REQ_GROUP_IP) ? (NBIT3):(0); /*IP = 1 or non IP*/
		reg |= ((uint32)strHif.u16Length << 4); /*length of pkt max = 4096*/
		ret = nm_write_reg(WIFI_HOST_RCV_CTRL_2, reg);
		if(M2M_SUCCESS != ret) goto ERR1;
#endif
		dma_addr = 0;
		
		for(cnt = 0; cnt < 1000; cnt ++)
		{
			ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_2,(uint32 *)&reg);
			if(ret != M2M_SUCCESS) break;
			/*
			 * If it takes too long to get a response, the slow down to 
			 * avoid back-to-back register read operations.
			 */
			if(cnt >= 500) {
				if(cnt < 501) {
					M2M_INFO("Slowing down...\n");
				}
				nm_bsp_sleep(1);
			}
			if (!(reg & NBIT1))
			{
				ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_4,(uint32 *)&dma_addr);
				if(ret != M2M_SUCCESS) {
					/*in case of read error clear the DMA address and return error*/
					dma_addr = 0;
					goto ERR1;
				}
				/*in case of success break */
				break;
			}
		}

		if (dma_addr != 0)
		{
			volatile uint32	u32CurrAddr;
			u32CurrAddr = dma_addr;
			strHif.u16Length=NM_BSP_B_L_16(strHif.u16Length);
			ret = nm_write_block(u32CurrAddr, (uint8*)&strHif, M2M_HIF_HDR_OFFSET);
			if(M2M_SUCCESS != ret) goto ERR1;
			u32CurrAddr += M2M_HIF_HDR_OFFSET;
			if(pu8CtrlBuf != NULL)
			{
				ret = nm_write_block(u32CurrAddr, pu8CtrlBuf, u16CtrlBufSize);
				if(M2M_SUCCESS != ret) goto ERR1;
				u32CurrAddr += u16CtrlBufSize;
			}
			if(pu8DataBuf != NULL)
			{
				u32CurrAddr += (u16DataOffset - u16CtrlBufSize);
				ret = nm_write_block(u32CurrAddr, pu8DataBuf, u16DataSize);
				if(M2M_SUCCESS != ret) goto ERR1;
				u32CurrAddr += u16DataSize;
			}

			reg = dma_addr << 2;
			reg |= NBIT1;
			ret = nm_write_reg(WIFI_HOST_RCV_CTRL_3, reg);
			if(M2M_SUCCESS != ret) goto ERR1;
		}
		else
		{
			ret = hif_chip_sleep();
			M2M_DBG("Failed to alloc rx size %d\r",ret);
			ret = M2M_ERR_MEM_ALLOC;
			goto ERR2;
		}

	}
	else
	{
		M2M_ERR("(HIF)Fail to wakup the chip\n");
		goto ERR2;
	}
	/*actual sleep ret = M2M_SUCCESS*/
 	ret = hif_chip_sleep();
	return ret;
ERR1:
	/*reset the count but no actual sleep as it already bus error*/
	hif_chip_sleep_sc();
ERR2:
	/*logical error*/
	return ret;
}

#ifdef ARDUINO
volatile uint8 hif_small_xfer = 0;
#endif

/**
*	@fn		hif_isr
*	@brief	Host interface interrupt service routine
*	@author	M. Abdelmawla
*	@date	15 July 2012
*	@return	1 in case of interrupt received else 0 will be returned
*	@version	1.0
*/
static sint8 hif_isr(void)
{
	sint8 ret = M2M_SUCCESS;
	volatile uint32 reg;
	volatile tstrHifHdr strHif;

#ifdef ARDUINO
	ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, (uint32*)&reg);
#else
	ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, &reg);
#endif
	if(M2M_SUCCESS == ret)
	{
		if(reg & 0x1)	/* New interrupt has been received */
		{
			uint16 size;

			nm_bsp_interrupt_ctrl(0);
			/*Clearing RX interrupt*/
			reg &= ~NBIT0;
			ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0,reg);
			if(ret != M2M_SUCCESS)goto ERR1;
			gstrHifCxt.u8HifRXDone = 1;
			size = (uint16)((reg >> 2) & 0xfff);
			if (size > 0) {
				uint32 address = 0;
				/**
				start bus transfer
				**/
				ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_1, &address);
				if(M2M_SUCCESS != ret)
				{
					M2M_ERR("(hif) WIFI_HOST_RCV_CTRL_1 bus fail\n");
					nm_bsp_interrupt_ctrl(1);
					goto ERR1;
				}
				gstrHifCxt.u32RxAddr = address;
				gstrHifCxt.u32RxSize = size;
				ret = nm_read_block(address, (uint8*)&strHif, sizeof(tstrHifHdr));
				strHif.u16Length = NM_BSP_B_L_16(strHif.u16Length);
				if(M2M_SUCCESS != ret)
				{
					M2M_ERR("(hif) address bus fail\n");
					nm_bsp_interrupt_ctrl(1);
					goto ERR1;
				}
				if(strHif.u16Length != size)
				{
					if((size - strHif.u16Length) > 4)
					{
						M2M_ERR("(hif) Corrupted packet Size = %u <L = %u, G = %u, OP = %02X>\n",
							size, strHif.u16Length, strHif.u8Gid, strHif.u8Opcode);
						nm_bsp_interrupt_ctrl(1);
						ret = M2M_ERR_BUS_FAIL;
						goto ERR1;
					}
				}

				if(M2M_REQ_GROUP_WIFI == strHif.u8Gid)
				{
					if(gstrHifCxt.pfWifiCb)
						gstrHifCxt.pfWifiCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
					else
#ifdef ARDUINO
					{
#endif
						M2M_ERR("WIFI callback is not registered\n");
#ifdef ARDUINO
					}
#endif
				}
				else if(M2M_REQ_GROUP_IP == strHif.u8Gid)
				{
					if(gstrHifCxt.pfIpCb)
						gstrHifCxt.pfIpCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
					else
#ifdef ARDUINO
					{
#endif
						M2M_ERR("Scoket callback is not registered\n");
#ifdef ARDUINO
					}
#endif
				}
				else if(M2M_REQ_GROUP_OTA == strHif.u8Gid)
				{
					if(gstrHifCxt.pfOtaCb)
						gstrHifCxt.pfOtaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
					else
#ifdef ARDUINO
					{
#endif
						M2M_ERR("Ota callback is not registered\n");
#ifdef ARDUINO
					}
#endif
				}
				else if(M2M_REQ_GROUP_CRYPTO == strHif.u8Gid)
				{
					if(gstrHifCxt.pfCryptoCb)
						gstrHifCxt.pfCryptoCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);

					else
#ifdef ARDUINO
					{
#endif
						M2M_ERR("Crypto callback is not registered\n");
#ifdef ARDUINO
					}
#endif
				}
				else if(M2M_REQ_GROUP_SIGMA == strHif.u8Gid)
				{
					if(gstrHifCxt.pfSigmaCb)
						gstrHifCxt.pfSigmaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
					else
#ifdef ARDUINO
					{
#endif
						M2M_ERR("Sigma callback is not registered\n");
#ifdef ARDUINO
					}
#endif
				}
				else if(M2M_REQ_GROUP_SSL == strHif.u8Gid)
				{
				    if(gstrHifCxt.pfSslCb)
						gstrHifCxt.pfSslCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
				}
				else
				{
					M2M_ERR("(hif) invalid group ID\n");
					ret = M2M_ERR_BUS_FAIL;
					goto ERR1;
				}
#ifdef ARDUINO
				if(hif_small_xfer)
				{
					/*Pause SPI transfer*/
					return ret;
				}
#endif
				if(gstrHifCxt.u8HifRXDone)
				{
					M2M_ERR("(hif) host app didn't set RX Done <%u><%X>\n", strHif.u8Gid, strHif.u8Opcode);
					ret = hif_set_rx_done();
					if(ret != M2M_SUCCESS) goto ERR1;
				}
			}
			else
			{
				M2M_ERR("(hif) Wrong Size\n");
				ret = M2M_ERR_RCV;
				goto ERR1;
			}
		}
		else
		{
#ifndef WIN32
			M2M_ERR("(hif) False interrupt %lx",reg);
			ret = M2M_ERR_FAIL;
			goto ERR1;
#else
#endif
		}
	}
	else
	{
		M2M_ERR("(hif) Fail to Read interrupt reg\n");
		goto ERR1;
	}

ERR1:
	return ret;
}

#ifdef ARDUINO
void Socket_ReadSocketData_Small(void);
#endif

/**
*	@fn		hif_handle_isr(void)
*	@brief	Handle interrupt received from NMC1500 firmware.
*   @return     The function SHALL return 0 for success and a negative value otherwise.
*/

sint8 hif_handle_isr(void)
{
	sint8 ret = M2M_SUCCESS;	

#ifdef ARDUINO
	if(hif_small_xfer) {
		/*SPI protocol paused to allow small transfer*/
		Socket_ReadSocketData_Small();
		return ret;
	}
#endif

	while (gstrHifCxt.u8Interrupt) {
		/*must be at that place because of the race of interrupt increment and that decrement*/
		/*when the interrupt enabled*/
		gstrHifCxt.u8Interrupt--;
		while(1)
		{
			ret = hif_isr();
#ifdef ARDUINO
			if(hif_small_xfer) {
				return ret;
			}
#endif
			if(ret == M2M_SUCCESS) {
				/*we will try forever untill we get that interrupt*/
				/*Fail return errors here due to bus errors (reading expected values)*/
				break;
			} else {
				M2M_ERR("(HIF) Fail to handle interrupt %d try Again..\n",ret);
			}
		}
	}

	return ret;
}
/*
*	@fn		hif_receive
*	@brief	Host interface interrupt serviece routine
*	@param [in]	u32Addr
*				Receive start address
*	@param [out]	pu8Buf
*				Pointer to receive buffer. Allocated by the caller
*	@param [in]	u16Sz
*				Receive buffer size
*	@param [in]	isDone
*				If you don't need any more packets send True otherwise send false
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/
sint8 hif_receive(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz, uint8 isDone)
{
	sint8 ret = M2M_SUCCESS;
	if((u32Addr == 0)||(pu8Buf == NULL) || (u16Sz == 0))
	{
		if(isDone)
		{			
			/* set RX done */
			ret = hif_set_rx_done();
		}
		else
		{
			ret = M2M_ERR_FAIL;
			M2M_ERR(" hif_receive: Invalid argument\n");
		}
		goto ERR1;
	}

	if(u16Sz > gstrHifCxt.u32RxSize)
	{
		ret = M2M_ERR_FAIL;
		M2M_ERR("APP Requested Size is larger than the recived buffer size <%u><%lu>\n",u16Sz, gstrHifCxt.u32RxSize);
		goto ERR1;
	}
	if((u32Addr < gstrHifCxt.u32RxAddr)||((u32Addr + u16Sz)>(gstrHifCxt.u32RxAddr + gstrHifCxt.u32RxSize)))
	{
		ret = M2M_ERR_FAIL;
		M2M_ERR("APP Requested Address beyond the recived buffer address and length\n");
		goto ERR1;
	}
	
	/* Receive the payload */
	ret = nm_read_block(u32Addr, pu8Buf, u16Sz);
	if(ret != M2M_SUCCESS)goto ERR1;

	/* check if this is the last packet */
	if((((gstrHifCxt.u32RxAddr + gstrHifCxt.u32RxSize) - (u32Addr + u16Sz)) <= 0) || isDone)
	{
		/* set RX done */
		ret = hif_set_rx_done();
	}

ERR1:
	return ret;
}

/**
*	@fn		hif_register_cb
*	@brief	To set Callback function for every compantent Component
*	@param [in]	u8Grp
*				Group to which the Callback function should be set.
*	@param [in]	fn
*				function to be set
*    @return		The function shall return ZERO for successful operation and a negative value otherwise.
*/

sint8 hif_register_cb(uint8 u8Grp,tpfHifCallBack fn)
{
	sint8 ret = M2M_SUCCESS;
	switch(u8Grp)
	{
		case M2M_REQ_GROUP_IP:
			gstrHifCxt.pfIpCb = fn;
			break;
		case M2M_REQ_GROUP_WIFI:
			gstrHifCxt.pfWifiCb = fn;
			break;
		case M2M_REQ_GROUP_OTA:
			gstrHifCxt.pfOtaCb = fn;
			break;
		case M2M_REQ_GROUP_HIF:
			gstrHifCxt.pfHifCb = fn;
			break;
		case M2M_REQ_GROUP_CRYPTO:
			gstrHifCxt.pfCryptoCb = fn;
			break;
		case M2M_REQ_GROUP_SIGMA:
			gstrHifCxt.pfSigmaCb = fn;
			break;
		case M2M_REQ_GROUP_SSL:
			gstrHifCxt.pfSslCb = fn;
			break;
		default:
			M2M_ERR("GRp ? %d\n",u8Grp);
			ret = M2M_ERR_FAIL;
			break;
	}
	return ret;
}

#endif
