#include "Config/Include/APP_Config.h"
#include "Abstraction/Include/OS_Interface.h"
#include "CanManager.h"
#include "App/include/CanMgrExt.h"
#include "CanNm.h"
#include <string.h>
#include "App/Power/Power_Os.h"
#include "Middleware/CAN/BSW/Ccl/ccl_inc.h"
//#include "Middleware/CAN/CANMID.h"
typedef struct
{
	uint8_t status;
	uint32_t request_zone;
    uint8_t CGW_flag;
    uint32_t TTL_time;
    uint32_t release_time;
}CanMgrWkupSrc_st;
static OS_TaskParam CanMgrParam;
static uint32_t TaskOffsetTime;
typedef struct TBOX_NM_UserDataun
{
  unsigned char _c[6];  
} c_TBOX_NM_UserDataun;
c_TBOX_NM_UserDataun CanMgrNmUserData;
c_TBOX_NM_UserDataun CanMgrNmUserDataTemp;

static CanMgrWkupSrc_st CmgrWkupSrcTbl[CANNM_WKPU_SRC_MAX]={
                                /*status*/
/*CANNM_SRC_TSP_AGENT*/ { CANNM_RELEASE,    PNC_TYPE_2,    false, 50000,0},			
/*CANNM_SRC_BLE*/	    { CANNM_RELEASE,    PNC_TYPE_3,    false, 20000,0},	
/*CANNM_SRC_ECALL*/	    { CANNM_RELEASE,    PNC_TYPE_3,    false, 20000,0}	
};
static void canmgr_network_release(CanNmWkupSrc_Enum source);
static void canmgr_network_request(CanNmWkupSrc_Enum source,uint32_t ttl);
static void canmgr_release_network_timeout();
static void canmgr_set_zone(uint8_t type,uint8_t wkup_src);
static void test_timer();
Nm_StateType CanApi_GetNmSts(void);
static void CanMgr_on_task_init()
{
   OS_createTimer(TIMER_ID_CANMGR_RELEASE,CANMGR_TIMER_BASE,1,canmgr_release_network_timeout);
 //  OS_createTimer(TIMER_ID_CANMGR_TEST,5000,1,test_timer);
   OS_startTimer(TIMER_ID_CANMGR_RELEASE);
}

static void CanMgr_on_recv_msg(uint16_t event_code, void* data, uint32_t data_size)
{
    uint8_t CanNmWkupSource = 0xFF;   
    uint32_t CanNmWkupSource_TTL_time = 0;
    uint8_t DTCbuff[2] = {0};
    uint8_t Networkbuff[8] = {0};
	uint8_t aubTaskID = TSK_ID_CANMGR;

	//buff[0]=CAN_BUS_OFF;//ADD DTC CODE FROM DTC APP

    //TaskOffsetTime = 1000;//should add task offset function
    //Param.wait_time = TaskOffsetTime;//set task timeout offset
	switch(event_code)  
    {
        case EVENT_MCU_POWER_STANDBYOUT:
            //DO STDBYOUT

	        /* Notification Power processing completed*/
            OS_sndMsg(MSG_ID_POWERMGR, EVENT_MCU_POWER_STANDBYOUT_STAGE2_ACK, 0, 0, OS_WAIT_INFINITE);
       //     canmgr_network_request(CANNM_SRC_BLE,30000);
       //      OS_startTimer(TIMER_ID_CANMGR_TEST);
            break;
        case EVENT_MCU_POWER_STANDBYIN:
            //do stdbyin
            
            /* Notification Power processing completed*/
            OS_sndMsg(MSG_ID_POWERMGR, EVENT_MCU_POWER_STANDBYIN_STAGE2_ACK, 0, 0, OS_WAIT_INFINITE);
            break;
        case CANMGR_NM_LOCAL_REQUEST:
            break;
        case CANMGR_NM_LOCAL_RELEASE:
            break;
        case CANMGR_BUSOFF_DTC_REMOVE:
            break;
        case CANMGR_BUSOFF_DTC_OCCUR:
            break;
        case SPI_LOCAL_REQUEST:
            if((data!=NULL)&&(data_size == 8))
            {
                memcpy(Networkbuff,data,data_size);
                CanNmWkupSource = Networkbuff[0];
                CanNmWkupSource_TTL_time = Networkbuff[4];//ttl should be 4byte
                canmgr_network_request(CanNmWkupSource,CanNmWkupSource_TTL_time);
            }
            else
            {
                //output error log
            }
            break;
        case SPI_LOCAL_RELEASE:
            if((data!=NULL)&&(data_size == 4))
            {
                memcpy(Networkbuff,data,data_size);
                CanNmWkupSource = Networkbuff[0];
                if((CanNmWkupSource<CANNM_WKPU_SRC_MAX)&&(CmgrWkupSrcTbl[CanNmWkupSource].status == CANNM_REQUEST))
                {		
                   
                    canmgr_network_release(CanNmWkupSource);								
                }
            }
            else
            {
                //output error log
            }
        
            break;
        case CANMGR_DIAG_COMM_CTRL:
            break;
    }

}

static void CanMgr_on_recv_time_out()
{
    #if 0
    //add TaskOffsetTime chuli
    if(TaskOffsetTime>=500)
    {
        canmgr_release_network_timeout(1);
    }
    else
    {
        canmgr_release_network_timeout(0);
    }   
    #endif
   
}

static void on_loop()
{
    
}

void* CanMgr_getTaskParam()
{
    CanMgrParam.queue_id = MSG_ID_CANMGR;
    CanMgrParam.wait_time = OS_WAIT_INFINITE; 
    CanMgrParam.task_init = CanMgr_on_task_init;
    CanMgrParam.recv_msg = CanMgr_on_recv_msg;
  //  CanMgrParam.time_out = CanMgr_on_recv_time_out;
 //   CanMgrParam.loop =  on_loop;
    return &CanMgrParam;
}
#if 0
static void test_timer()
{
     canmgr_network_request(CANNM_SRC_BLE,10000);
}
#endif
static void canmgr_release_network_timeout()
{
	unsigned char i;
    unsigned char nm_release_sts=true;
	for(i=0;i<CANNM_WKPU_SRC_MAX;i++)
	{
        if(CmgrWkupSrcTbl[i].status == CANNM_REQUEST)
        {
             //set ttl time
            if(CmgrWkupSrcTbl[i].release_time != 0)
            {
                CmgrWkupSrcTbl[i].release_time -= CANMGR_TIMER_BASE;
            } 
             //set status
            if (CmgrWkupSrcTbl[i].release_time == 0)
            {
                canmgr_network_release(i);// do release
            }
        }     
       
        //set flag
        if(CmgrWkupSrcTbl[i].status != CANNM_RELEASE)
        {
            nm_release_sts=false;
        }           
	}
	if(true==nm_release_sts)// if all network releases and release timer expired, ccl release
	{			
	  	CclReleaseCommunication(0);
	}else
	{
		//do nothing
	}
}
static void canmgr_network_request(CanNmWkupSrc_Enum source,uint32_t ttl)
{

    Nm_StateType nmState;//canbedded type

 	if(source<CANNM_WKPU_SRC_MAX)
	{
		if(CmgrWkupSrcTbl[source].status==CANNM_REQUEST)
        {
            //  only set ttl time to max
			CmgrWkupSrcTbl[source].release_time = ttl;
		}
		else
		{
			CmgrWkupSrcTbl[source].status=CANNM_REQUEST;
			CmgrWkupSrcTbl[source].release_time = ttl;
            CmgrWkupSrcTbl[source].CGW_flag = true;
			canmgr_set_zone(CANNM_REQUEST,source);
						
		    memcpy(&CanMgrNmUserData, &CanMgrNmUserDataTemp, sizeof(c_TBOX_NM_UserDataun));
						
			nmState=CanApi_GetNmSts();//canbedded function

			if(nmState==NM_STATE_BUS_SLEEP)
            {
                CclRequestCommunication(0);
            }
            else if((nmState==NM_STATE_PREPARE_BUS_SLEEP)||(nmState==NM_STATE_READY_SLEEP) || (nmState==NM_STATE_NORMAL_OPERATION)||(nmState==NM_STATE_REPEAT_MESSAGE))
            {
                CclRequestCommunication(0);
                Nm_RepeatMessageRequest(0);					
            }
            else
            {
                CclRequestCommunication(0);
                Nm_RepeatMessageRequest(0);
            }
								
		}	
	}
	else
	{
		//output error log
	}
}
static void canmgr_network_release(CanNmWkupSrc_Enum source)
{
	unsigned char i;

	if(source<CANNM_WKPU_SRC_MAX)
	{	
        CmgrWkupSrcTbl[source].status=CANNM_RELEASE;
        CmgrWkupSrcTbl[source].release_time = 0;
		canmgr_set_zone(CANNM_RELEASE,source);
	
		for(i=0;i<CANNM_WKPU_SRC_MAX;i++)
		{
			if(CmgrWkupSrcTbl[i].status==CANNM_REQUEST)
			{				
				canmgr_set_zone(CANNM_REQUEST,i);  /*un-release source ,set related zone*/
			}
		}
        //user data temp set,maybe need
		memcpy(&CanMgrNmUserData, &CanMgrNmUserDataTemp, sizeof(c_TBOX_NM_UserDataun));
	}
	else
	{
        //output error log
	}
}



static void canmgr_set_zone(uint8_t type,uint8_t wkup_src)
{


   unsigned long int NmZone=0;
  
   NmZone=(unsigned long int )CanMgrNmUserDataTemp._c[4];
   NmZone=(NmZone<<8)|(unsigned long int )CanMgrNmUserDataTemp._c[3];
   NmZone=(NmZone<<8)|(unsigned long int )CanMgrNmUserDataTemp._c[2];
   NmZone=(NmZone<<8)|(unsigned long int )CanMgrNmUserDataTemp._c[1];

  if(type==CANNM_REQUEST)
  {
	  NmZone|=CmgrWkupSrcTbl[wkup_src].request_zone;

  }
  else if(type==CANNM_RELEASE)
  {
	  NmZone&=(~CmgrWkupSrcTbl[wkup_src].request_zone);
  }
  else
  {
	  //do nothing
  }
  

  CanMgrNmUserDataTemp._c[1]= (uint8_t)NmZone;
  CanMgrNmUserDataTemp._c[2]= (uint8_t)(NmZone>>8);
  CanMgrNmUserDataTemp._c[3]= (uint8_t)(NmZone>>16);
  CanMgrNmUserDataTemp._c[4]= (uint8_t)(NmZone>>24);

  CanNm_SetUserData(0,&(CanMgrNmUserData._c[0])); 
}

#if 0

void CanMgrDiagCommCtrl(uint8_t Ctrl ,uint8_t Group)
{

	if(Ctrl==COMM_CTRL_RX_ENABLE)
	{
		switch (Group)
		{
			case COMM_CTRL_GROUP_NM:
				CommCtrlNmRx=COMM_CTRL_RX_ENABLE;
				break;
			case COMM_CTRL_GROUP_IL:
				CommCtrlIlRx=COMM_CTRL_RX_ENABLE;
				break;
			case COMM_CTRL_GROUP_ALL:
				CommCtrlNmRx=COMM_CTRL_RX_ENABLE;
				CommCtrlIlRx=COMM_CTRL_RX_ENABLE;
				break;
			default:
				break;

		}
	}
	else if(Ctrl==COMM_CTRL_RX_DISABLE)
	{
		switch (Group)
		{
			case COMM_CTRL_GROUP_NM:
				CommCtrlNmRx=COMM_CTRL_RX_DISABLE;
				break;
			case COMM_CTRL_GROUP_IL:
				CommCtrlIlRx=COMM_CTRL_RX_DISABLE;
				break;
			case COMM_CTRL_GROUP_ALL:
				CommCtrlNmRx=COMM_CTRL_RX_DISABLE;
				CommCtrlIlRx=COMM_CTRL_RX_DISABLE;
				break;
			default:
				break;

		}

	}
	else
	{
		//do nothing
	}
}
unsigned char CanMgrGetCommCtrlNmRx(void)
{
	return CommCtrlNmRx;

}

unsigned char CanMgrGetCommCtrlIlRx(void)
{
	return CommCtrlIlRx;

}
#endif

void ApplBusSleepIndication(void)
{
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplBusSleepIndication]---",OS_GetCurrentTime());
#endif
   //wvdPowerMgr_CallBack(MSG_POWER_MGR_RES_CAN_RELEASE,0,0);
}
void ApplFirstCommReqIndication(void)
{
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplFirstCommReqIndication]---",OS_GetCurrentTime());
#endif

}
void ApplWakeupByBusIndication(void)
{
#ifdef OPEN_LOG_NW
  JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[ApplWakeupByBusIndication]---",OS_GetCurrentTime());
#endif

  	//wvdPowerMgr_CallBack(MSG_POWER_MGR_RES_WKPU_CAN,0,0);
	//GPIO_Clear(PA_5);

}
void  CanWakupeMessageRxIndicaiton(void)
{
#ifdef OPEN_LOG_NW
  	JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---[CCL_CanWakupeMessageRxIndicaiton]---",OS_GetCurrentTime());
#endif


}


/* called by isr*/

void CanMgr_CGWNmRxIndicaiton(void)
{
#if 0
	if(CanMgrNmRx==FALSE)
	{
		CanMgrNmRx=TRUE;

		CanStsCurrent=CAN_CGW_AWAKE;

		nubCanMgrISR_SendMessage(CANMGR_CGW_NM_RX,0,0);
	}
#endif

}
void CanMgr_PassiveStartUp(void)
{
//	JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]---in CanMgr_PassiveStartUp--",OS_GetCurrentTime());
}
void CanMgr_RxNmPdu(unsigned char RepeatBit)
{
#if 0
	Nm_StateType nmState;
	nmState=CanApi_GetNmSts();
	if((RepeatBit&0x01)==0x01)
	{
		//receive repeat msg bit
		RepeatMsgBitInd = TRUE;
	}
	if((nmState == NM_STATE_BUS_SLEEP)||(nmState == NM_STATE_PREPARE_BUS_SLEEP))
	{
		PassiveStartUp = TRUE;
	}
#endif
}


/*external function*/
/* called by isr*/

void CGWRxIndication(void)
{
    uint8_t i;
    uint8_t CGW_set = false;
    for(i = 0;i< CANNM_WKPU_SRC_MAX;i++)
    {
        if(CmgrWkupSrcTbl[i].CGW_flag == true)
        {
            CGW_set = true;
            CmgrWkupSrcTbl[i].CGW_flag = false;
        }
    }
    if(CGW_set == true)
    {
        //add send msg to can service
    }
}
void ApplCclCbdWrpStateChange(NetworkHandleType nmChannelHandle, Nm_StateType nmPreviousState, Nm_StateType nmCurrentState )
{

	//unsigned char i;
	/*repeat message state set*/	
	if(nmCurrentState==NM_STATE_REPEAT_MESSAGE)
	{	
		//nvdCanMgr_SetRepeatMsgSt(1);
        //set repeatmsg bit to 1
       // CanNm_SetUserData(0,&(CanMgrNmUserData._c[0]));
        #if 0
		if((PassiveStartUp  == TRUE)||(RepeatMsgBitInd == TRUE))//enter repeat message state by network request or repeat message request
		{
			
			if(PassiveStartUp == TRUE)/*passive start up*/
			{				
				/*passive startup ,network request*/
				CclRequestCommunication(0);
				PassiveStartUp = FALSE;
			}
		}
		else
		{
			/*dont set network bit*/
			JPCC_DEBUG(JPCC_LOG_LEVEL_INFO, "[%d]In repeat msg state,not passive startup,not receive repeat bit-",OS_GetCurrentTime());
		}	
        #endif	
		
	    //	NotifyToDtcCanCommActive();	
	}	
	else
	{
		/*not in repeat message state,set network bit 0,set repeatMsgSt bit 0*/
		//set repeatmsg bit to 0
		CanNm_SetUserData(0,&(CanMgrNmUserData._c[0]));
	}
    if(nmCurrentState==NM_STATE_PREPARE_BUS_SLEEP)
    {
        CanNm_SetUserData(0,&(CanMgrNmUserData._c[0]));
    }

}


Nm_StateType CanApi_GetNmSts(void)
{
	Nm_ModeType nmMode;
	Nm_StateType nmState;

	CanNm_GetState(0,&nmState,&nmMode);

	return nmState;
}

vuint8 NM_SA_TxPreTransmit(CanTxInfoStruct ctis)
{
    CanNm_SetUserData(0,&(CanMgrNmUserData._c[0])); 
	return kCanCopyData;
}




