#include "FU68xx_5.h"
#include <Myproject.h>

FaultStateType     xdata   mcFaultSource;
FaultVarible       idata   mcFaultDect;
ProtectVarible     xdata   mcProtectTime;


void FaultProcess(void)
{
    PRE_DRIVER_RST = 0;
    ClrBit(DRV_CR, FOCEN);
    MOE = 0;
}

/*****************************************************************************
    Function:         void   Fault_OverVoltage(mcFaultVarible *h_Fault)
    Description:  过压欠压保护函数：程序每5ms判断一次，母线电压大于过压保护值时，计数器加一，计数器值超过20次，判断为过压保护，关闭输出;反之，计数器慢慢减
                 同理，欠压保护。
                   电机过欠压保护状态下，母线电压恢复到欠压恢复值以上，过压恢复值以下时，计数器加一，超过200次后，恢复。根据档位信息来决定恢复到哪个状态。
    Parameter:        mcFaultVarible *h_Fault
    Return:           no
 *****************************************************************************/
void Fault_OverUnderVoltage(void)
{
    if ((mcFaultSource == FaultNoSource) && (mcState == mcRun)) //程序无其他保护下
    {
        //过压保护
        if (mcFocCtrl.mcDcbusFlt > OVER_PROTECT_VALUE)   //母线电压大于过压保护值时，计数，超过20次，判断为过压保护，关闭输出;反之，计数器慢慢减
        {
            mcFaultDect.OverVoltDetecCnt++;
            
            if (mcFaultDect.OverVoltDetecCnt > 20) //检测100ms
            {
                mcFaultDect.OverVoltDetecCnt = 0;
                mcFaultSource             = FaultOverVoltage;
                FaultProcess();
            }
        }
        else
        {
            if (mcFaultDect.OverVoltDetecCnt > 0)
            { mcFaultDect.OverVoltDetecCnt--; }
        }
        
        //欠压保护
        if (mcFocCtrl.mcDcbusFlt < UNDER_PROTECT_VALUE)
        {
            mcFaultDect.UnderVoltDetecCnt++;
            
            if (mcFaultDect.UnderVoltDetecCnt > 20) //检测100ms
            {
                mcFaultDect.UnderVoltDetecCnt = 0;
                mcFaultSource              = FaultUnderVoltage;
                FaultProcess();
            }
        }
        else
        {
            if (mcFaultDect.UnderVoltDetecCnt > 0)
            { mcFaultDect.UnderVoltDetecCnt--; }
        }
    }
    
    /*******过压欠压保护恢复*********/
    if ((mcState == mcFault) && ((mcFaultSource == FaultUnderVoltage) || (mcFaultSource == FaultOverVoltage)))
    {
        if ((mcFocCtrl.mcDcbusFlt < OVER_RECOVER_VALUE) && (mcFocCtrl.mcDcbusFlt > UNDER_RECOVER_VALUE))
        {
            mcFaultDect.VoltRecoverCnt++;
            
            if (mcFaultDect.VoltRecoverCnt > 2000) //连续检测1s，若正常则恢复
            {
                mcFaultSource           = FaultNoSource;
                mcFaultDect.VoltRecoverCnt = 0;
            }
        }
        else
        {
            mcFaultDect.VoltRecoverCnt = 0;
        }
    }
}

/*****************************************************************************
    Function:     void Fault_Overcurrent(CurrentVarible *h_Cur)
    Description:  电机运行或者启动时，当三相中某一相最大值大于OverCurrentValue，则OverCurCnt加1。
                 连续累加3次，判断为软件过流保护。执行时间约30.4us。
    Parameter:    mcFaultVarible *h_Fault
    Return:       no
 *****************************************************************************/
void Fault_Overcurrent(void)
{
    static uint16 IIs;
    
    if (mcFaultSource == FaultNoSource)
    {
        if (mcState == mcStart || mcState == mcAlign || mcState == mcRun || mcState == mcStop)
        {
            SqrtI_alpbet(FOC__ID, FOC__IQ, IIs); //平方和后开根号
            mcCurVarible.Max_is = IIs;
            
            if (mcCurVarible.Max_is >= SW_OC_CurrentVal) // 过流保护
            {
                mcCurVarible.time++;
                
                if (mcCurVarible.time > SW_OC_DectTime)
                {
                    mcCurVarible.time  = 0;
                    mcFaultSource = FaultSoftOVCurrent;
                    FaultProcess();
                }
            }
            else
            {
                mcCurVarible.time = 0;
            }
        }
    }
}
/*****************************************************************************
    Function:         void   Fault_OverCurrentRecover(mcFaultVarible *h_Fault)
    Description:  软硬件过流保护恢复
    Parameter:        mcFaultVarible *h_Fault
    Return:           no
 *****************************************************************************/
void Fault_OverCurrentRecover(void)
{
    if ((mcState == mcFault) && ((mcFaultSource == FaultSoftOVCurrent)
            || (mcFaultSource == FaultHardOVCurrent)) && (mcProtectTime.CurrentPretectTimes < CurrentProtectRestartTimes))
    {
        mcFaultDect.CurrentRecoverCnt++;
        
        if (mcFaultDect.CurrentRecoverCnt >= OverCurrentRecoverTime) //200*5=1s
        {
            mcFaultDect.CurrentRecoverCnt = 0;
            mcProtectTime.CurrentPretectTimes++;
            mcFaultSource = FaultNoSource;
            PRE_DRIVER_RST = 0;
        }
    }
}

/*****************************************************************************
    Function:         void   Fault_Start(mcFaultVarible *h_Fault)
    Description:  启动保护函数，电机运行状态下，电机在前5s估算转速达到堵转保护值或者5s后反电动势值太低(此方法未验证)
                  或4s内还在CtrlMode状态，即速度低于MOTOR_LOOP_RPM，程序判断为启动失败，电机停机。
                  当程序判断为启动失败后，若重启次数少于或等于5次，程序立即进入校准状态，等待重启。
    Parameter:        mcFaultVarible *h_Fault
    Return:           no
 *****************************************************************************/
void Fault_Start(void)
{
    /*******启动保护恢复*********/
    if (mcState == mcRun)
    {
        //方法一，5s内速度大于最大速度，同时反电动势值低于一定值
        if (mcFaultDect.StartSpeedCnt <= 1000)
        {
            mcFaultDect.StartSpeedCnt++;
            
            if ((motorControl.ActualSpeed > MOTOR_MAX_SPEED) && (motorControl.BackEMF < 1300))
            {
                mcFaultDect.StartSpeedCnt = 0;
                mcFaultSource          = FaultStart;
                FaultProcess();
                mcProtectTime.StartFlag = 1;
            }
        }
        
        //方法二
        if (mcFaultDect.StartEsCnt <= 1200) //前6s，等待1.5s后，开始判断ES，如果超过一定次数，则失败
        {
            mcFaultDect.StartEsCnt++;
            mcFaultDect.StartDelay++;
            
            if (mcFaultDect.StartDelay >= 300)               // 1.5s
            {
                mcFaultDect.StartDelay = 300;
                
                if ((motorControl.BackEMF < 500))
                {
                    mcFaultDect.StartESCount++;
                    
                    if (mcFaultDect.StartESCount >= 20)
                    {
                        mcFaultSource = FaultStart;
                        FaultProcess();
                        mcFaultDect.StartDelay     = 0;
                        mcFaultDect.StartESCount   = 0;
                        mcProtectTime.StartFlag = 2;
                    }
                }
                else
                {
                    if (mcFaultDect.StartESCount > 0)
                    {
                        mcFaultDect.StartESCount--;
                    }
                }
            }
        }
        else
        {
            mcFaultDect.StartESCount = 0;
        }
        
        if (motorControl.LoopState == OPEN_MODE)
        {
            mcFaultDect.StartFocmode++;
            
            if (mcFaultDect.StartFocmode >= 400)
            {
                mcFaultDect.StartFocmode = 0;
                mcFaultSource         = FaultStart;
                FaultProcess();
                mcProtectTime.StartFlag = 3;
            }
        }
    }
    
    if ((mcFaultSource == FaultStart) && (mcState == mcFault) && (mcProtectTime.SecondStartTimes <= StartProtectRestartTimes))
    {
        mcProtectTime.SecondStartTimes++;
        mcFaultSource = FaultNoSource;
    }
}
/*****************************************************************************
    Function:         void   Fault_Stall(mcFaultVarible *h_Fault)
    Description:  堵转保护函数，有三种保护方式，
                  第一种，
                  第二种，电机运行状态下，延迟4s判断，估算速度绝对值超过堵转速度连续5次；
                  第三种，电机运行状态下，当U,V两相电流绝对值大于堵转电流保护值连续6次；
                  当以上三种的任何一种保护触发时，电机停机，程序判断为堵转保护；
                  当堵转保护状态下，U相采集值低于堵转恢复值时，若堵转次数小于或等于堵转重启次数8次，
                  程序延迟mcStallRecover重新启动，进行校准状态。
    Parameter:        mcFaultVarible *h_Fault
    Return:           no
*****************************************************************************/
//堵转保护
void Fault_Stall(void)
{
    if (mcState == mcRun)
    {
        if (mcFaultDect.StallDelayCnt <= 1000) //5s
        {
            mcFaultDect.StallDelayCnt++;
        }
        else
        {
            //method 1，判断反电动势太小或当反电动势太小，转速太大
            if ((motorControl.BackEMF < 1000) || ((FOC__EOME > _Q15(3000.0 / MOTOR_SPEED_BASE)) && (motorControl.BackEMF < 2000)))
            {
                mcFaultDect.StallDectEs++;
                
                if (mcFaultDect.StallDectEs >= 10)
                {
                    mcFaultDect.StallDectEs = 0;
                    mcFaultSource        = FaultStall;
                    FaultProcess();
                    mcProtectTime.StallFlag = 1;
                }
            }
            else
            {
                if ( mcFaultDect.StallDectEs > 0)
                {
                    mcFaultDect.StallDectEs--;
                }
            }
            
            //method 2，判断速度低于堵转最小值或者超过堵转最大值
            if ((motorControl.ActualSpeed < MOTOR_STALL_MIN_SPEED) || (motorControl.ActualSpeed > MOTOR_STALL_MAX_SPEED))
            {
                mcFaultDect.StallDectSpeed++;
                
                if (mcFaultDect.StallDectSpeed >= 8)
                {
                    mcFaultDect.StallDectSpeed = 0;
                    mcFaultSource           = FaultStall;
                    FaultProcess();
                    mcProtectTime.StallFlag = 2;
                }
            }
            else
            {
                if (mcFaultDect.StallDectSpeed > 0)
                {
                    mcFaultDect.StallDectSpeed--;
                }
            }
            
            //method 3
            //                      if((motorControl.BackEMF<=25*(uint32)motorControl.ActualSpeed/10)&&motorControl.BackEMF>=10*(uint32)motorControl.ActualSpeed/10)//1.15
            //                      {
            //                          mcFaultDect.StallDectEs2 = 0;
            //                      }
            //                      else
            //                      {
            //
            //                          mcFaultDect.StallDectEs2++;
            //                          if(mcFaultDect.StallDectEs2>=30)
            //                          {
            //                                  mcFaultDect.StallDectEs2 = 0;
            //                                  mcFaultSource = FaultStall;
            //                                  FaultProcess();
            //                          }
            //
            //                      }
        }
    }
    
    /*******堵转保护恢复*********/
    if ((mcFaultSource == FaultStall) && (mcState == mcFault) && (mcProtectTime.StallTimes < StallProtectRestartTimes))
    {
        mcFaultDect.StallReCount++;
        
        if (mcFaultDect.StallReCount >= StallRecoverTime)
        {
            mcProtectTime.StallTimes++;
            mcFaultDect.StallReCount = 0;
            mcFaultSource         = FaultNoSource;
        }
    }
    else
    {
        mcFaultDect.StallReCount = 0;
    }
}
/*****************************************************************************
    Function:         void   Fault_phaseloss(mcFaultVarible *h_Fault)
    Description:  缺相保护函数，当电机运行状态下，10ms取三相电流的最大值，
                  1.5s判断各相电流最大值，若存在两相电流值大于一定值，而第三相电流值却非常小，则判断为缺相保护，电机停机；
    Parameter:        mcFaultVarible *h_Fault
    Return:           no
*****************************************************************************/
void Fault_phaseloss(void)
{
    if (mcState == mcAlign)
    {
        if (mcFocCtrl.CurrentAlignStatus == 0)
        {
            mcFaultDect.CurrentASum += FOC__IA;
            mcFaultDect.CurrentBSum += FOC__IB;
            mcFaultDect.CurrentCSum += FOC__IC;
        }
        else if (mcFocCtrl.CurrentAlignStatus == 1)
        {
            mcFaultDect.CurrentAAlign =  mcFaultDect.CurrentASum / AlignmentHoldTime1 ;
            mcFaultDect.CurrentBAlign = -(mcFaultDect.CurrentBSum << 1) / AlignmentHoldTime1;
            mcFaultDect.CurrentCAlign = -(mcFaultDect.CurrentCSum << 1) / AlignmentHoldTime1;
            
            if ( mcFaultDect.CurrentAAlign > mcFaultDect.CurrentBAlign << 1
                || mcFaultDect.CurrentAAlign > mcFaultDect.CurrentCAlign << 1
                || mcFaultDect.CurrentBAlign > mcFaultDect.CurrentCAlign << 1
                || (mcFaultDect.CurrentAAlign < 20 && mcFaultDect.CurrentBAlign < 20 && mcFaultDect.CurrentCAlign < 20))
            {
                mcFaultSource = FaultLossPhase;
                FaultProcess();
            }
        }
    }
    
    if (mcState == mcRun)
    {
        mcCurVarible.Max_ia = FOC__IAMAX;
        mcCurVarible.Max_ib = FOC__IBMAX;
        mcCurVarible.Max_ic = FOC__ICMAX;
        mcFaultDect.Lphasecnt++;
        
        if (mcFaultDect.Lphasecnt > 40) //100*5=500ms
        {
            mcFaultDect.Lphasecnt = 0;
            
            if (((mcCurVarible.Max_ia > (mcCurVarible.Max_ib << 1)) || (mcCurVarible.Max_ia > (mcCurVarible.Max_ic << 1)))
                && (mcCurVarible.Max_ia > PhaseLossCurrentValue))
            {
                mcFaultDect.AOpencnt++;
            }
            else
            {
                if (mcFaultDect.AOpencnt > 0)
                {
                    mcFaultDect.AOpencnt --;
                }
            }
            
            if (((mcCurVarible.Max_ib > (mcCurVarible.Max_ia << 1)) || (mcCurVarible.Max_ib > (mcCurVarible.Max_ic << 1)))
                && (mcCurVarible.Max_ib > PhaseLossCurrentValue))
            {
                mcFaultDect.BOpencnt++;
            }
            else
            {
                if (mcFaultDect.BOpencnt > 0)
                {
                    mcFaultDect.BOpencnt --;
                }
            }
            
            if (((mcCurVarible.Max_ic > (mcCurVarible.Max_ia << 1)) || (mcCurVarible.Max_ic > (mcCurVarible.Max_ib << 1)))
                && (mcCurVarible.Max_ic > PhaseLossCurrentValue))
            {
                mcFaultDect.COpencnt++;
            }
            else
            {
                if (mcFaultDect.COpencnt > 0)
                {
                    mcFaultDect.COpencnt --;
                }
            }
            
            mcCurVarible.Max_ia = 0;
            mcCurVarible.Max_ib = 0;
            mcCurVarible.Max_ic = 0;
            SetBit(FOC_CR2, ICLR);  //FOC__IA/B/CMAX清零
            
            if ((mcFaultDect.AOpencnt > 3) || (mcFaultDect.BOpencnt > 3) || (mcFaultDect.COpencnt > 3))
            {
                mcFaultSource = FaultLossPhase;
                FaultProcess();
            }
        }
    }
    
    /*******缺相保护恢复*********/
    if ((mcFaultSource == FaultLossPhase) && (mcState == mcFault) && (mcProtectTime.LossPHTimes < PhaseProtectRestartTimes)) //可重启5次
    {
        mcFaultDect.mcLossPHRecCount++;
        
        if (mcFaultDect.mcLossPHRecCount >= PhaseLossRecoverTime)
        {
            mcProtectTime.LossPHTimes++;
            mcFaultSource     = FaultNoSource;
        }
    }
    else
    {
        mcFaultDect.mcLossPHRecCount = 0;
    }
}

void Fault_IPMOverTemp(void)
{
    if (mcFaultSource == FaultNoSource)
    {
        if (motorControl.IGBTTemp > TempProtValue)
        {
            mcFaultDect.OverTempDetecCnt++;
            
            if (mcFaultDect.OverTempDetecCnt > 20)
            {
                mcFaultDect.OverTempDetecCnt = 0;
                mcFaultSource             = FaultIpmTemp;
                FaultProcess();
            }
        }
        else
        {
            mcFaultDect.OverTempDetecCnt = 0;
        }
    }
    
    /*******温度保护恢复*********/
    if ((mcState == mcFault) && (mcFaultSource == FaultIpmTemp))
    {
        if (motorControl.IGBTTemp < TempRecoverValue)
        {
            mcFaultDect.TempRecoverCnt++;
            
            if (mcFaultDect.TempRecoverCnt > 200)
            {
                mcFaultSource           = FaultNoSource;
                mcFaultDect.TempRecoverCnt = 0;
            }
        }
        else
        {
            mcFaultDect.TempRecoverCnt = 0;
        }
    }
}


/*压机偏置电压错误恢复*/
void IOffsetRecoverEnable()
{
    if ((mcFaultSource == FaultIbusOffset) && (mcProtectTime.IbusOffsetProtectTimes < IbusOffsetRestartTimes))
    {
        mcFaultDect.IbusOffsetRecoverCnt++;
        
        if ((mcFaultDect.IbusOffsetRecoverCnt) >= IbusOffsetRecoverTime)//IbusOffsetRecoverTime*1ms
        {
            mcFaultDect.IbusOffsetRecoverCnt = 0;
            mcProtectTime.IbusOffsetProtectTimes++;
            mcFaultSource = FaultNoSource;
        }
    }
}
void Fault_UdcMax_Min(void)
{
    if ((mcFaultSource == FaultNoSource) && (mcState == mcRun))
    {
        if ((mcFocCtrl.mcDcbus_chazhi >= _Q15(120 / HW_BOARD_VOLT_MAX)) && mcFocCtrl.mcDcbus_min <= _Q15(380 / HW_BOARD_VOLT_MAX))
        {
            mcFaultDect.shurulossCnt++;
            
            if (mcFaultDect.shurulossCnt > 10)
            {
                mcFaultDect.shurulossCnt = 0;
                mcFaultSource             = FaultshuruLoss;
                FaultProcess();
            }
        }
        else
        {
            mcFaultDect.shurulossCnt--;
            
            if (mcFaultDect.shurulossCnt <= 0)
            {
                mcFaultDect.shurulossCnt = 0;
            }
        }
    }
    
    /*******保护恢复*********/
    if ((mcState == mcFault) && (mcFaultSource == FaultshuruLoss) && (mcProtectTime.shurulossTimes <= 3))
    {
        if (((mcFocCtrl.mcDcbus_chazhi) <= _Q15(20 / HW_BOARD_VOLT_MAX)) && mcFocCtrl.mcDcbus_min >= _Q15(500 / HW_BOARD_VOLT_MAX))
        {
            mcFaultDect.shurulossRecCount++;
            
            if (mcFaultDect.shurulossRecCount > 200)
            {
                mcProtectTime.shurulossTimes++;
                mcFaultSource           = FaultNoSource;
                mcFaultDect.shurulossRecCount = 0;
            }
        }
        else
        {
            mcFaultDect.shurulossRecCount = 0;
        }
    }
}
/*---------------------------------------------------------------------------*/
/*  Name     :   void Fault_Detection(void)
    /* Input    :   NO
    /* Output   :   NO
    /* Description: 保护函数，因保护的时间响应不会很高，采用分段处理，每5个定时器中断执行一次对应的保护
                  常见保护有过欠压、过温、堵转、启动、缺相等保护，调试时，可根据需求，一个个的调试加入。
    /*---------------------------------------------------------------------------*/
void Fault_Detection(void)
{
    mcFaultDect.segment++;
    
    if (mcFaultDect.segment >= 7)
    {
        mcFaultDect.segment = 0;
    }
    
    if (mcFaultDect.segment == 0)
    {
        #if (CurrentRecoverEnable == 1)//过流保护恢复使能
        {
            Fault_OverCurrentRecover();
        }
        #endif
    }
    else if (mcFaultDect.segment == 1)
    {
        #if (VoltageProtectEnable == 1)//过压保护使能
        {
            Fault_OverUnderVoltage();
        }
        #endif
        #if (IbusOffsetRecoverEnable)  //偏执电压保护恢复
        {
            IOffsetRecoverEnable();
        }
        #endif
    }
    else if (mcFaultDect.segment == 2)
    {
        #if (StartProtectEnable == 1)//启动保护使能
        {
            Fault_Start();
        }
        #endif
    }
    else if (mcFaultDect.segment == 3)
    {
        #if (StallProtectEnable == 1)//堵转保护使能
        {
            Fault_Stall();
        }
        #endif
    }
    else if (mcFaultDect.segment == 4)
    {
        #if (PhaseLossProtectEnable == 1)//缺相保护使能
        {
            Fault_phaseloss();
        }
        #endif
    }
    else if (mcFaultDect.segment == 5)
    {
        #if (TempProtectEnable == 1)//IPM温度保护
        {
            Fault_IPMOverTemp();
        }
        #endif
        #if (TempSensorProtectEnable==1)
        {
            Fault_TempSensor();
        }
        #endif
    }
    
    #if (ShuruLossProtectEnable == 1)
    {
        Fault_UdcMax_Min();
    }
    #endif
}

