#include "NM_includes.h"

OSEK_NM_PARA NmPara;

/*-------------------------------------------------------------------------
* Function Name  : NM_Do_Nothing
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_Do_Nothing(void)
{
	;
}

/*-------------------------------------------------------------------------
* Function Name  : NM_Do_Nothing
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_State_Transformation(void (*pProgram)(void))
{
    NmPara.NmTxState = 0;
    NmPara.NmRxState = 0;
    NmPara.NmErrState = 0;
    NmPara.NM_Main_Program = pProgram;
}

/*-------------------------------------------------------------------------
* Function Name  : NM_ReceiveMsg_handle
* Description    : handle receive PDU;
* Input          :
* Output         : None
* Return         : None
* onther         : propose : in interrupt function
--------------------------------------------------------------------------*/
void NM_ReceiveMsg_handle(void)
{
    if(NmPara.NmPduBuf.bits.ProceF == BUF_FULL) {
        NmPara.NmRecvPdu.msg[0] = NmPara.NmPduBuf.msg[0];
        NmPara.NmRecvPdu.msg[1] = NmPara.NmPduBuf.msg[1];
        NmPara.NmRecvPdu.msg[2] = NmPara.NmPduBuf.msg[2];
        NmPara.NmRecvPdu.msg[3] = NmPara.NmPduBuf.msg[3];
        NmPara.NmRecvPdu.msg[4] = NmPara.NmPduBuf.msg[4];
        NmPara.NmRecvPdu.msg[5] = NmPara.NmPduBuf.msg[5];
        NmPara.NmRecvPdu.msg[6] = NmPara.NmPduBuf.msg[6];
        NmPara.NmRecvPdu.msg[7] = NmPara.NmPduBuf.msg[7];
        NmPara.NmRecvPdu.bits.SourceID = NmPara.NmIdBuf;
        NmPara.NmRxState = 1;
        NmPara.NmPduBuf.bits.ProceF = BUF_EMPTY;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : OsekNM_Manage_Main
* Description    : OSEK Main function
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void OsekNM_Manage_Main(void)
{
    
    if (NmPara.NmTaskLock == NM_LOCK) {
        return;
    }
       NM_Time_2ms_Count();
    if (NmPara.NM_Main_Program == NMLimpHome_main) {
      NmPara.NmState = NM_STATE_LIMPHOME_MAIN;
    } else if (NmPara.NM_Main_Program == NMNormal_main) {
      NmPara.NmState = NM_STATE_NORMAL_MAIN;
    } else if (NmPara.NM_Main_Program == NMTwbsNormal_main) {
      NmPara.NmState = NM_STATE_TWBSNORMAL_MAIN;
    } else if (NmPara.NM_Main_Program == NMNormalPrepSleep_main) {
      NmPara.NmState = NM_STATE_NORMALPREPSLEEP_MAIN;
    } else if (NmPara.NM_Main_Program == NMBusSleep_main) {
      NmPara.NmState = NM_STATE_BUSSLEEP_MAIN;
    } else if (NmPara.NM_Main_Program == NMLimpHomePrepSleep_main) {
      NmPara.NmState = NM_STATE_LIMPHOMEPREPSLEEP_MAIN;
    } else if (NmPara.NM_Main_Program == NMTwbsLimpHome_main) {
      NmPara.NmState = NM_STATE_TWBSLIMPHOME_MAIN; 
    } else if (NmPara.NM_Main_Program == NMReset_main) {
	  NmPara.NmState = NM_STATE_RESET_MAIN; 
    } else if (NmPara.NM_Main_Program == NM_Do_Nothing) {
      NmPara.NmState = NM_STATE_DO_NOTHING; 
    }
    

    NM_CheckBusOff_Fun();
    NM_ReceiveMsg_handle();
    NM_CheckSleep_Fun();
    
    if (NmPara.NmIGNState == NM_IGN_ON) {
        if(NmPara.NmNetWorkStatus.bussleep == NM_NO) {
            if(NmPara.NM_Main_Program != NMBusSleep_main) {
                GotoMode(NMAwake);
            }
        }
    }
    
    if (NmPara.NM_Main_Program == 0) {
        NmPara.NM_Main_Program = NMReset_main;
    }
    
    NM_CheckBusOff_Fun();
    
    if (NmPara.NmNetWorkStatus.NMactive == NM_Active) {
        (*NmPara.NM_Main_Program)();
    }
    
    if (NmPara.NmNetWorkStatus.APPactive == NM_Active) {
        NM_Send_App_Fun();
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMInitReset
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMInitReset(void)
{
    NmPara.NmRxErrCount = 0;
    NmPara.NmTxErrCount = 0;
    
    NM_D_Online();
}

/*-------------------------------------------------------------------------
* Function Name  : NMReset
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMReset(void)
{
    NmPara.NmDestination = NmPara.NmIdOwn;
    NmPara.NmRxErrCount++;
    NmPara.NmRecvPdu.bits.Opcode = 0;
    NmPara.NmTxState = 0;
    NmPara.NmRxState = 0;
    NmPara.NmErrState = 0;
    NmPara.NmSleepRequestMin = 0;
    NmPara.NmLimpHomeTxCnt = 0;
    NmPara.NmNetWorkStatus.bussleep = NM_NO;
    Transmit_NMPDU(ALIVE_MSG);
}

/*-------------------------------------------------------------------------
* Function Name  : NMReset_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMReset_main(void)
{
    if (NmPara.NMInitReset_Program == NMInitReset) {
        (*NmPara.NMInitReset_Program)();
        NmPara.NMInitReset_Program = NM_Do_Nothing;
    }
    
    if (NmPara.NMReset_Program == NMReset) {
        (*NmPara.NMReset_Program)();
        NmPara.NMReset_Program = NM_Do_Nothing;
    }
    
	if ((NmPara.NmErrState + NmPara.NmTxState) == 0) {
		if (NmPara.NmResetContinueCallCnt < 10) {
			NmPara.NmResetContinueCallCnt++;   
		} else {
			NmPara.NmResetContinueCallCnt = 0;
			NmPara.NmErrState = 1;
		}
	}
    
    if (NmPara.NmErrState) {
		NMReset_error();
		return;
	}
	
    if (NmPara.NmTxState) {
		NMReset_tx();
	}
}

void NMReset_error(void)
{
    NmPara.NmTxErrCount++;
    if ((NmPara.NmTxErrCount > NmPara.NmTxLimit) || (NmPara.NmRxErrCount > NmPara.NmRxLimit)) {
        NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo *)&NmPara.NmTime);
        NmPara.NmMarker.limphome = NM_NO;
        NM_State_Transformation(NMLimpHome_main);
    } else {
        NM_SetTSendTimer(NmPara.NmTimeType, (_NM_TimeInfo *)&NmPara.NmTime);
        NM_State_Transformation(NMNormal_main);
    }
}

void NMReset_tx(void)
{
    if ((NmPara.NmTxErrCount <= NmPara.NmTxLimit) && (NmPara.NmRxErrCount <= NmPara.NmRxLimit)) {
        NM_SetTSendTimer(NmPara.NmTimeType, (_NM_TimeInfo*)&NmPara.NmTime);
        NM_State_Transformation(NMNormal_main);
    } else {
        NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
        NmPara.NmMarker.limphome = NM_NO;
        NM_State_Transformation(NMLimpHome_main);
    }
}

void NMReset_rx(void)
{
    unsigned char OpCode = 0;
    unsigned char Source = 0;
    
    NmPara.NmRxState = 0;
    
    NmPara.NmRxErrCount = 0;
    
    if (NmPara.NmLastSendPDUType == ALIVE_MSG) {
        Source = NmPara.NmRecvPdu.bits.SourceID;
        OpCode = NmPara.NmRecvPdu.msg[ 1 ];
        if (OpCode & 0x03) {
            NM_ConfigLogicalFun(Source);
        }
    }
}

/*-------------------------------------------------------------------------
* Function Name  : StartNM
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void StartNM(void)
{
    NmPara.NmMarker.stable = NM_Unstabitily;
    NmPara.NmSleep.ind = NM_NO;
    NmPara.NmSleep.ack = NM_NO;
    NM_D_Init(BusInit);
    NmPara.NmTaskLock = NM_UNLOCK;
    TalkNM();
    TalkAPP();
    NMInitReset();
    NMReset();
    NmPara.NM_Main_Program = NMReset_main;
    NmPara.NMInitReset_Program = NM_Do_Nothing;
    NmPara.NMReset_Program = NM_Do_Nothing;
    NmPara.NmNetWorkStatus.BusOffEvent = DISABLE;
    NmPara.NmNetWorkStatus.WakeupEvent = NM_WaitWakeup;
    NmPara.NmSleepRequestMin = 0;
}

/*-------------------------------------------------------------------------
* Function Name  : InitNM
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void InitNM(OSEK_NM_INIT *NmInit) 
{                               
  	NmPara.NmIdBase=0X500;                //2018-04-10   //default:0x400
  	NmPara.NmIdBottom=0X5FF;              //default:0x4ff
  	NmPara.NmIdOwn=0X03;//                //default:0x4;
  	NmPara.NmRxLimit=4;                   //default:0x4
  	NmPara.NmTxLimit=8;                   //default:0x8
  	NmPara.NmTimeType=100;//100;           //default:100,unit:ms
  	NmPara.NmTimeMax=260;//260;           //default:260,unit:ms
  	NmPara.NmTimeError=1000;//1000;        //default:1000,unit:ms
  	NmPara.NmTimeWaitBusSleep=1500;       //default:1500,unit:ms
  	NmPara.NmTimeRequestSleepInd=5000;    //default:5000,unit:ms
  	NmPara.NmTimeRequestLimpSleepInd=4;   //default:4   

	if ((NmInit->NmIdBase) && (NmInit->NmIdBottom) && (NmInit->NmIdBase != NmInit->NmIdBottom)) {
		NmPara.NmIdBase = NmInit->NmIdBase;
		NmPara.NmIdBottom = NmInit->NmIdBottom;
	}
	if ((NmInit->NmIdBase + NmInit->NmIdOwn) < NmInit->NmIdBottom) {
		NmPara.NmIdOwn = NmInit->NmIdOwn;
	}
	if (NmPara.NmRxLimit) {
		NmPara.NmRxLimit = NmInit->NmRxLimit;
	}
	if (NmPara.NmTxLimit) {
		NmPara.NmTxLimit = NmInit->NmTxLimit;
	}
	if (NmPara.NmTimeType) {
		NmPara.NmTimeType = NmInit->NmTimeType;
	}
	if (NmPara.NmTimeMax) {
		NmPara.NmTimeMax = NmInit->NmTimeMax;
	}
	if (NmPara.NmTimeError) {
		NmPara.NmTimeError = NmInit->NmTimeError;
	}
	if (NmPara.NmTimeWaitBusSleep) {
		NmPara.NmTimeWaitBusSleep = NmInit->NmTimeWaitBusSleep;
	}
	if (NmPara.NmTimeRequestSleepInd) {
		NmPara.NmTimeRequestSleepInd = NmInit->NmTimeRequestSleepInd;
	}
	if (NmPara.NmTimeRequestLimpSleepInd) {
		NmPara.NmTimeRequestLimpSleepInd = NmInit->NmTimeRequestLimpSleepInd;
	}
	StartNM();
}

/*-------------------------------------------------------------------------
* Function Name  : SetTxState
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void SetTxState(unsigned char n) 
{
  NmPara.NmTxState = n; 
}

/*-------------------------------------------------------------------------
* Function Name  : SetRxState
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void SetRxState(unsigned char n) 
{
  NmPara.NmRxState = n;
}

/*-------------------------------------------------------------------------
* Function Name  : SetErrState
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void SetErrState(unsigned char n) 
{
  NmPara.NmErrState = n;
}
  

/*-------------------------------------------------------------------------
* Function Name  : NMNormal_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMNormal_main(void)
{
    if (NmPara.NmErrState) {
        NMNormal_error();
        return;
    } else if (NmPara.NmTxState) {
        NMNormal_tx();
        if (NmPara.NM_Main_Program == NMNormalPrepSleep_main) {
            return;
        }
    }
    
    if (NmPara.NmRxState) {
        NMNormal_rx();
        if (NmPara.NM_Main_Program == NMTwbsNormal_main) {
            return;
        }
    }
    
    if (NM_TSendTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        if (NmPara.NmNetWorkStatus.NMactive == NM_Active) {
            NM_SetTmaxTimer(NmPara.NmTimeMax, (_NM_TimeInfo *)&NmPara.NmTime);
            Transmit_NMPDU(RING_MSG);
        }
    }
    
    if (NM_TmaxTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        NMReset();
        NmPara.NM_Main_Program = NMReset_main;
    }
}

void NMNormal_rx (void)
{
    unsigned char OpCode = 0;
    unsigned char Source = 0;
    unsigned char Destination = 0;
    unsigned char Own_Node_Staute = 0;
    unsigned char OwnID = 0;
    
    NmPara.NmRxState = 0;
    NmPara.NmRxErrCount = 0;
    
    Source =  NmPara.NmRecvPdu.bits.SourceID;
    Destination =  NmPara.NmRecvPdu.bits.DestID;
    
    OpCode = NmPara.NmRecvPdu.msg[1];
    
    if (OpCode & 0x03) {
        NM_ConfigLogicalFun(Source);
    }
    
    if (OpCode & 0x10) {
         NmPara.NmSleep.ind = NM_YES;
    } else {
         NmPara.NmSleep.ind = NM_NO;
    }
    
    if (OpCode & 0x02) {//RING
        CancelAlarm(NmPara.NmTimeType);
        CancelAlarm(NmPara.NmTimeMax);
        
        if(OpCode & 0x20) {//NmSleep_ACK=1
            if(NmPara.NmNetWorkStatus.bussleep) {
                NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo *)&NmPara.NmTime);
                NM_State_Transformation(NMTwbsNormal_main);
                return;
            }
        }

        OwnID = NmPara.NmIdOwn;
        
        if((Destination == OwnID) || (Source == Destination)) {
            NM_SetTSendTimer(NmPara.NmTimeType,(_NM_TimeInfo *)&NmPara.NmTime);
        } else {
            NM_SetTmaxTimer(NmPara.NmTimeMax,(_NM_TimeInfo *)&NmPara.NmTime);
            Own_Node_Staute = NM_CheckSkip(Source,Destination,OwnID);
            if (Own_Node_Staute == NM_NODE_SKIP) {
                NmPara.NmDestination = OwnID;
                Transmit_NMPDU(ALIVE_MSG);
            }
        }
    } else if(OpCode & 0x01) {
        NmPara.NmMarker.stable = NM_Unstabitily;
    }
}

void NMNormal_tx(void)
{
    NmPara.NmTxState = 0;
    NmPara.NmTxErrCount = 0;
    
    if ((NmPara.NmSleep.ind) && (NmPara.NmNetWorkStatus.bussleep) && (NmPara.NmLastSendPDUType == RING_MSG)) {
        NM_SetTmaxTimer(NmPara.NmTimeMax, (_NM_TimeInfo *)&NmPara.NmTime);
        CancelAlarm(NmPara.NmTimeType);
        NmPara.NmSleep.ack = NM_YES;
        NM_State_Transformation(NMNormalPrepSleep_main);
        AbortAllCanTx();
    }
}

void NMNormal_error(void)
{
    NmPara.NmErrState = 0;
    NmPara.NmTxErrCount++;
    
    if (NmPara.NmTxErrCount > NmPara.NmTxLimit) {
        NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
        NmPara.NmMarker.limphome = NM_NO;
        NM_State_Transformation(NMLimpHome_main);
    }
}
/*-------------------------------------------------------------------------
* Function Name  : NMNormalPrepSleep_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMNormalPrepSleep_main(void)
{
    if (NmPara.NmErrState) {
        NMNormalPrep_error();
        return;
    } else if (NmPara.NmTxState) {
        NMNormalPrep_tx();
        return;
    }
    
    if (NmPara.NmRxState) {
        NMNormalPrep_rx();
        if ((NmPara.NM_Main_Program == NMTwbsNormal_main) || (NmPara.NM_Main_Program == NMNormal_main)) {
            return;
        }
    }
    
    if (NM_TmaxTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        CancelAlarm(NmPara.NmTimeError);
        CancelAlarm(NmPara.NmTimeType);
        NmPara.NmMarker.limphome = NM_NO;
        NMReset();
        NmPara.NM_Main_Program = NMReset_main;
        return;
    }
    
    if (NM_TSendTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        if(NmPara.NmNetWorkStatus.NMactive == NM_Active) {
            Transmit_NMPDU(RING_MSG);
        }
    }
}

void NMNormalPrep_rx(void)
{
    unsigned char OpCode = 0;
    unsigned char Source = 0;
    unsigned char Destination = 0;
    unsigned char Own_Node_Staute = 0;
    unsigned char OwnID = 0;
    
    NmPara.NmRxState = 0;
    NmPara.NmRxErrCount = 0;
    Source = NmPara.NmRecvPdu.bits.SourceID;
    Destination = NmPara.NmRecvPdu.bits.DestID;
    OpCode = NmPara.NmRecvPdu.msg[ 1 ];
    
    if (OpCode & 0x03) {
        NM_ConfigLogicalFun(Source);
    }
    
    if (OpCode & 0x10) {
        NmPara.NmSleep.ind = NM_YES;
    } else {
        NmPara.NmSleep.ind = NM_NO;
    }
    
    OwnID = NmPara.NmIdOwn;
    
    if (NmPara.NmSleep.ind == NM_NO) {
        CancelAlarm(NmPara.NmTimeMax);
        CancelAlarm(NmPara.NmTimeType);
        if ((Destination == OwnID) || (Source == Destination)) {
            NM_SetTSendTimer(NmPara.NmTimeType, (_NM_TimeInfo *)&NmPara.NmTime);
        } else {
            NM_SetTmaxTimer(NmPara.NmTimeMax, (_NM_TimeInfo *)&NmPara.NmTime);
            Own_Node_Staute = NM_CheckSkip(Source, Destination, OwnID);
            
            if (Own_Node_Staute == NM_NODE_SKIP) {
                NmPara.NmDestination = OwnID;
                Transmit_NMPDU(ALIVE_MSG);
            }
        }
        NmPara.NM_Main_Program = NMNormal_main;
    } else {
        if (OpCode & 0x02) {//RING
        
            if ((OpCode & 0x20) == 0x20) {//NmSleep_ACK=1
                CancelAlarm(NmPara.NmTimeType);
                CancelAlarm(NmPara.NmTimeMax);
                NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo *)&NmPara.NmTime);
                NM_State_Transformation(NMTwbsNormal_main);
                return;
            }
            
            CancelAlarm(NmPara.NmTimeType);
            CancelAlarm(NmPara.NmTimeMax);
            
            if ((Destination == OwnID) || (Source == Destination)) {
                NM_SetTSendTimer(NmPara.NmTimeType, (_NM_TimeInfo *)&NmPara.NmTime);
            } else {
                NM_SetTmaxTimer(NmPara.NmTimeMax,(_NM_TimeInfo *)&NmPara.NmTime);
                Own_Node_Staute = NM_CheckSkip(Source, Destination, OwnID);
                
                if (Own_Node_Staute == NM_NODE_SKIP) {
                    NmPara.NmDestination = OwnID;
                    Transmit_NMPDU(ALIVE_MSG);
                }
            }
        } else if (OpCode & 0x01) {
            NmPara.NmMarker.stable = NM_Unstabitily;
        }
    }
}

void NMNormalPrep_tx(void)
{
    NmPara.NmTxState = 0;
    if (NmPara.NmLastSendPDUType == RING_MSG) {
        NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo *)&NmPara.NmTime);
        NM_State_Transformation(NMTwbsNormal_main);
    }
}

void NMNormalPrep_error(void)
{
    NmPara.NmErrState = 0;
    if (NmPara.NmLastSendPDUType == RING_MSG) {
        NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo *)&NmPara.NmTime);
        NM_State_Transformation(NMTwbsNormal_main);
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMTwbsNormal_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMTwbsNormal_main(void)
{
    NM_D_Offline();
    
    if (NmPara.NmRxState) {
        NMTwbsNormal_rx();
        if(NmPara.NM_Main_Program == NMReset_main) {
            return;
        }
    }
    
    if (NM_TwbsTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        NM_State_Transformation(NMBusSleep_main);
    }
}

void NMTwbsNormal_rx(void)
{
    NmPara.NmRxState = 0;
    
    NM_SetTmaxTimer(NmPara.NmTimeMax, (_NM_TimeInfo*)&NmPara.NmTime);
    NmPara.NmSleep.ind = NmPara.NmRecvPdu.msg[1] & 0x30;
    if (NmPara.NmSleep.ind == 0) {
        NMInitReset();
        NMReset();
        NmPara.NM_Main_Program = NMReset_main;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMLimpHome_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMLimpHome_main(void)
{
    if (NmPara.NmTxState) {
        NMLimpHome_tx();
        return;
    }
    
    if (NmPara.NmErrState) {
        NMLimpHome_error();
        return;
    }
    
    if (NmPara.NmRxState) {
        NMLimpHome_rx();
        if((NmPara.NM_Main_Program == NMReset_main) || (NmPara.NM_Main_Program == NMTwbsLimpHome_main)) {
            return;
        }
    }
    
    if (NM_TSendTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        if (NmPara.NmNetWorkStatus.bussleep) {
            NM_SetTmaxTimer(NmPara.NmTimeMax, (_NM_TimeInfo *)&NmPara.NmTime);
            
            NmPara.NmTxState = 0;
            NmPara.NmRxState = 0;
            NmPara.NmErrState = 0;
            NmPara.NmDestination = NmPara.NmIdOwn;
            Transmit_NMPDU(LIMP_HOME_MSG);
            if (NmPara.NmSleep.ind) {
                NM_State_Transformation(NMLimpHomePrepSleep_main);
            }
        } else {
            NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
            Transmit_NMPDU(LIMP_HOME_MSG);
        }
    }
}

void NMLimpHome_rx(void)
{
    unsigned char   OpCode = 0;
    
    NmPara.NmRxState = 0;
    OpCode = NmPara.NmRecvPdu.msg[ 1 ];
    if (OpCode & 0x20) {
        NmPara.NmSleep.ack = 1;
    } else {
        NmPara.NmSleep.ack = 0;
    }
    
    if (OpCode & 0x10) {
        NmPara.NmSleep.ind = NM_YES;
    } else {
        NmPara.NmSleep.ind = NM_NO;
    }
    
    if (NmPara.NmNetWorkStatus.NMactive == NM_Active) {
        if (NmPara.NmMarker.limphome == NM_YES) {
            if (NmPara.NmNetWorkStatus.bussleep) {
                if (NmPara.NmSleep.ack) {
                    NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo*)&NmPara.NmTime);
                    NM_State_Transformation(NMTwbsLimpHome_main);
                } else {
                    CancelAlarm(NmPara.NmTimeError);
                    NmPara.NmMarker.limphome = NM_NO;
                    NMInitReset();
                    NMReset();
                    NmPara.NM_Main_Program = NMReset_main;
                }
            } else {//if(NmNetWorkStatus.bussleep == NM_NO) //5
                CancelAlarm(NmPara.NmTimeError);
                NmPara.NmMarker.limphome = NM_NO;
                NMInitReset();
                NMReset();
                NmPara.NM_Main_Program = NMReset_main;
            }
        } else {
            if (NmPara.NmSleep.ack) {
                NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo*)&NmPara.NmTime);
                NM_State_Transformation(NMTwbsLimpHome_main);
            } else {//5
                CancelAlarm(NmPara.NmTimeError);
                NmPara.NmMarker.limphome = NM_NO;
                NMInitReset();
                NMReset();
                NmPara.NM_Main_Program = NMReset_main;
            }
        }
    }
}

void NMLimpHome_tx(void)
{
    NmPara.NmTxState = 0;
    if (NmPara.NmLastSendPDUType == LIMP_HOME_MSG) {
        NmPara.NmMarker.limphome = NM_YES;
        NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
    }
}

void NMLimpHome_error(void)
{
    NmPara.NmErrState = 0;
    if(NmPara.NmLastSendPDUType == LIMP_HOME_MSG) {
        if(!NmPara.NmTime.TtypEnable) {
            NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
        }
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMLimpHomePrepSleep_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMLimpHomePrepSleep_main(void)
{
    if (NmPara.NmRxState) {
        NMLimpHomePrepSleep_rx();
        if ((NmPara.NM_Main_Program == NMLimpHome_main) || (NmPara.NM_Main_Program == NMTwbsLimpHome_main)) {
            return;
        }
    }
    if (NM_TmaxTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {//P39
        NM_D_Offline();
        NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo*)&NmPara.NmTime);
        NM_State_Transformation(NMTwbsLimpHome_main);
    }
}

void NMLimpHomePrepSleep_rx(void)
{
    unsigned char OpCode = 0;
    
    NmPara.NmRxState = 0;
    OpCode = NmPara.NmRecvPdu.msg[1];
    if (OpCode & 0x20) {//P39
        NM_SetTwbsTimer(NmPara.NmTimeWaitBusSleep, (_NM_TimeInfo*)&NmPara.NmTime);
        NM_State_Transformation(NMTwbsLimpHome_main);
    } else if (OpCode & 0x10) {
        ;
    } else {
        NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
        NM_State_Transformation(NMLimpHome_main);
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMTwbsLimpHome_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMTwbsLimpHome_main(void)
{
    NM_D_Offline();
    
    if (NmPara.NmRxState) {
        NMTwbsLimpHome_rx();
        if (NmPara.NM_Main_Program == NMLimpHome_main) {
            return;
        }
    }
    
    if (NM_TwbsTimerOver((_NM_TimeInfo*)&NmPara.NmTime)) {
        NM_State_Transformation(NMBusSleep_main);
    }
}

void NMTwbsLimpHome_rx(void)
{
    unsigned char OpCode = 0;
    
    NmPara.NmRxState  = 0;
    
    OpCode = NmPara.NmRecvPdu.msg[1];
    if ((OpCode & 0x30) == 0) {
        NM_SetTSendTimer(NmPara.NmTimeError,(_NM_TimeInfo*)&NmPara.NmTime);
        NM_State_Transformation(NMLimpHome_main);
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NMBusSleep_main
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NMBusSleep_main(void)
{
    NM_D_Offline();
    NmPara.NmRxErrCount = 0;
    NmPara.NmTxErrCount = 0;
    
    if (NmPara.NmNetWorkStatus.WakeupEvent == NM_LocalWakeup) {
        NmPara.NmNetWorkStatus.WakeupEvent = NM_WaitWakeup;
        GotoMode(NMAwake);
    } else if (NmPara.NmNetWorkStatus.WakeupEvent == NM_RemoteWakeup) {
        NmPara.NmNetWorkStatus.WakeupEvent = NM_WaitWakeup;
        GotoMode(NMAwake);
    } else {
        GotoMode(NMBusSleep);
    }
}
/*-------------------------------------------------------------------------
* Function Name  : NM_CheckSkip
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char NM_CheckSkip(unsigned char Source, unsigned char Destination, unsigned char Own_Node)
{
    unsigned char S = 0;
    unsigned char R = 0;
    unsigned char D = 0;
    unsigned char skip;
    
    S = Source;
    R = Own_Node;
    D = Destination;
    
    skip = 0;
    
    if (D < R) {
        if (S < D) {
           ; 
        } else {
            if (S < R) {
                skip = NM_NODE_SKIP;
            }
        }
    } else {
        if (S < D) {
            if (S < R) {
                skip = NM_NODE_SKIP;
            }
        } else {
            skip = NM_NODE_SKIP;
        }
    }
    return  skip;
}
/*-------------------------------------------------------------------------
* Function Name  : NM_ConfigLogicalFun
* Description    : determine logical successor
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_ConfigLogicalFun(unsigned char SourceID)
{
    unsigned char S = 0;
    unsigned char R = 0;
    unsigned char L = 0;
    
    S = SourceID;
    R = NmPara.NmIdOwn;
    L = NmPara.NmDestination;
    
    if (L == R) {
        L = S;
    } else {
        if (L < R) {
            if (S < L) {
                L = S;
            } else {
                if (S < R) {
                    
                } else {
                    L = S;
                }
            }
        } else {
            if (S < L) {
                if (S < R) {
                    
                } else {
                    L = S;
                }
            }
        }
    }
    
    NmPara.NmDestination = L;
}

/*-------------------------------------------------------------------------
* Function Name  : GotoMode
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void GotoMode(unsigned char Mode)
{
    switch (Mode) {
        case NMBusSleep:
            NmPara.NmTxState = 0;
            NmPara.NmRxState = 0;
            NmPara.NmErrState = 0;
            NM_D_Init(BusSleep);
            SilentNM();
            break;
        case NMAwake:
            if ((NmPara.NM_Main_Program == NMNormal_main) || (NmPara.NM_Main_Program == NMLimpHome_main)) {
                break;
            }
            
            if (NmPara.NM_Main_Program == NMTwbsNormal_main) {
                CancelAlarm(NmPara.NmTimeWaitBusSleep);
                NMInitReset();
                NM_State_Transformation(NMReset_main);
                NmPara.NmDestination = NmPara.NmIdOwn;
                NmPara.NmRxErrCount++;
                Transmit_NMPDU(ALIVE_MSG);
                
                break;
            }
            
            if (NmPara.NM_Main_Program == NMLimpHomePrepSleep_main) {
                NmPara.NmMarker.limphome = NM_NO;
                NM_State_Transformation(NMLimpHome_main);
                NM_D_Online();
                Transmit_NMPDU(LIMP_HOME_MSG);
                NM_SetTSendTimer(NmPara.NmTimeError,(_NM_TimeInfo*)&NmPara.NmTime);
                break;
            }
            
            if (NmPara.NM_Main_Program == NMTwbsLimpHome_main) {
                CancelAlarm(NmPara.NmTimeWaitBusSleep);
                NmPara.NmMarker.limphome = NM_NO;
                NM_State_Transformation(NMLimpHome_main);
                NM_D_Online( );
                Transmit_NMPDU(LIMP_HOME_MSG);
                NM_SetTSendTimer(NmPara.NmTimeError, (_NM_TimeInfo*)&NmPara.NmTime);
                break;
            }
            
            if (NmPara.NM_Main_Program == NMBusSleep_main) {
                NM_D_Init(BusInit);           //initialize hardware by D_Init(...;BusInit)//NMInit
                NmPara.NmMarker.limphome = NM_NO;//NMInit
                NMInitReset();
                NmPara.NmDestination = NmPara.NmIdOwn; //P26 reset the system specific default configuration
                NmPara.NmRxErrCount++;         //P25
                NM_State_Transformation(NMReset_main);
                NmPara.NmSendPdu.bits.Opcode &= 0xCF;
                Transmit_NMPDU(ALIVE_MSG);
                break;
            }
            break;
        default:
            NM_State_Transformation(NM_Do_Nothing);
    }
}

/*-------------------------------------------------------------------------
* Function Name  : Transmit_NMPDU
* Description    : PDU Message handle
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void Transmit_NMPDU(unsigned char PDU_Type)
{
    NmPara.NmLastSendPDUType = PDU_Type;
    NmPara.NmSleep.ind = NmPara.NmNetWorkStatus.bussleep;
            
    switch (PDU_Type) {
        case ALIVE_MSG:
            NmPara.NmSendPdu.bits.Opcode = 0x01;
            NmPara.NmSleep.ack = 0;
            NmPara.NmMarker.stable = NM_Unstabitily;
            break;
        case RING_MSG:
            NmPara.NmSendPdu.bits.Opcode = 0x02;
            NmPara.NmMarker.stable = NM_Stabilize;
            break;
        case LIMP_HOME_MSG:
            NmPara.NmSendPdu.bits.Opcode = 0x04;
            NmPara.NmSleep.ack = 0;
            NmPara.NmMarker.stable = NM_Unstabitily;
            break;
        default:
            ;
    }
    
    if ((NmPara.NmSendPdu.bits.Opcode & 0x04) == 0x04) {
        if (NmPara.NmLimpHomeTxCnt < 255) {
            NmPara.NmLimpHomeTxCnt ++;
        }
    } else {
        NmPara.NmLimpHomeTxCnt = 0;
    }
    
    if (NmPara.NmSleep.ind == NM_YES) {
        NmPara.NmSendPdu.bits.Opcode |= 0x10;
    } else {
        NmPara.NmSendPdu.bits.Opcode &= 0xCF;
    }
    
    if (NmPara.NmSleep.ind == NM_NO) {
        NmPara.NmSleep.ack = 0;
    }
    
    if (NmPara.NM_Main_Program != NMNormalPrepSleep_main) {
        NmPara.NmSleep.ack = NM_NO;
    }
    
    if (NmPara.NmSleep.ack) {
        NmPara.NmSendPdu.bits.Opcode |= 0x20;
    } else {
        NmPara.NmSendPdu.bits.Opcode &= 0xDF;
    }
    
    NmPara.NmSendPdu.bits.NM_Data0 = 0x00;
    NmPara.NmSendPdu.bits.NM_Data1 = 0x00;
    NmPara.NmSendPdu.bits.NM_Data2 = 0x00;
    NmPara.NmSendPdu.bits.NM_Data3 = 0x00;
    NmPara.NmSendPdu.bits.Reserved0 = 0x00;
    NmPara.NmSendPdu.bits.Reserved1 = 0x00;
    NmPara.NmErrState = 0;
    NmPara.NmTxState = 0;
    NM_Send_PDU_Fun();
}

/*-------------------------------------------------------------------------
* Function Name  : CancelAlarm
* Description    : Cansel Ttyp /Tmax /Terror count
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void CancelAlarm(unsigned int timetype)
{
	if (timetype == NmPara.NmTimeError) {
		NmPara.NmTime.TtypEnable = 0;
        NmPara.NmTime.TtypTime = 0;
	} else if (timetype == NmPara.NmTimeType) {
		NmPara.NmTime.TtypEnable = 0;
        NmPara.NmTime.TtypTime = 0;
	} else if (timetype == NmPara.NmTimeMax) {
		NmPara.NmTime.TmaxEnable = 0;
		NmPara.NmTime.TmaxTime = 0;
	} else if (timetype == NmPara.NmTimeWaitBusSleep) {
        NmPara.NmTime.SleepEnable = 0;
	} 
}

/*-------------------------------------------------------------------------
* Function Name  : NM_SetTmaxTimer
* Description    : set Tmax count start
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_SetTmaxTimer(unsigned int Second, _NM_TimeInfo *T)
{
    T->TtypEnable = 0;
    T->TtypTime = 0;
    T->TmaxEnable = 1;
    T->OverTmaxTime = Second;
    T->TmaxTime = 0;
}
/*-------------------------------------------------------------------------
* Function Name  : NM_TmaxTimerOver
* Description    : check Tmax out
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char NM_TmaxTimerOver(_NM_TimeInfo *T)
{
    if ((T->TmaxTime >= T->OverTmaxTime) && (T->TmaxEnable)) {
        T->TmaxEnable = 0;
        T->TmaxTime = 0;
        return 1;
    } else {
        return 0;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NM_SetTSendTimer
* Description    : set Ttyp or Terror count
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_SetTSendTimer(unsigned int Second, _NM_TimeInfo *T)
{
    T->TmaxEnable = 0;
    T->TmaxTime = 0;
    T->TtypEnable = 1;
    T->OverTtypTime = Second;
    T->TtypTime = 0;
}
/*-------------------------------------------------------------------------
* Function Name  : NM_TSendTimerOver
* Description    : Ttyp or Terror out
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char NM_TSendTimerOver(_NM_TimeInfo *T)
{
    if ((T->TtypTime >= T->OverTtypTime) && (T->TtypEnable)) {
        T->TtypEnable = 0;
        T->TtypTime = 0;
        return 1;
    } else {
        return 0;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NM_SetTwbsTimer
* Description    : set Twbs count
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_SetTwbsTimer(unsigned int Second, _NM_TimeInfo *T)
{
    T->TwbsEnable = 1;
    T->OverTwbsTime = Second;
    T->TwbsTime = 0;
}

/*-------------------------------------------------------------------------
* Function Name  : NM_TwbsTimerOver
* Description    : check Twbs out
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char NM_TwbsTimerOver(_NM_TimeInfo *T)
{
    if ((T->TwbsTime >= T->OverTwbsTime) && (T->TwbsEnable)) {
        T->TwbsEnable = 0;
        return 1;
    } else {
        return 0;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : NM_SetSleepTimer
* Description    : set sleep wait timer
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void NM_SetSleepTimer(unsigned int Second, _NM_TimeInfo *T)
{
    T->SleepEnable = 1;
    T->OverSleepTime = Second;
    T->SleepTime = 0;
}

/*-------------------------------------------------------------------------
* Function Name  : NmSleepTimerOver
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char NmSleepTimerOver(_NM_TimeInfo *T)
{
    if((T->SleepTime >= T->OverSleepTime) && (T->SleepEnable)) {
        T->SleepEnable = 0;
        T->SleepTime = 0;
        return 1;
    } else {
        return 0;
    }
}