
#include "Popup_Scheduler.h"

/*** 弹出信息状态(链)表 ***/
PopupStatusStruct         PopupStatus[POPUP_NUMBER_TOTAL];

/*=====================================================
                  弹出信息调度链表
-------------------------------------------------------
        序号        |            链表名称
 (链表控制数组下标) |
-------------------------------------------------------
          0         | POPUP_LINK_LIST_NEW_FATAL
          1         | POPUP_LINK_LIST_FATAL
                    |
          2         | POPUP_LINK_LIST_NEW_HINT
          3         | POPUP_LINK_LIST_HINT
                    |
          3         | POPUP_LINK_LIST_NEW_WARNING
          4         | POPUP_LINK_LIST_WARNING
          5         | POPUP_LINK_LIST_MASKED_WARNING
=====================================================*/
PopupLinkListCtrlStruct   PopupLinkList[7];

/*** 弹出信息调度管理 ***/
PopupSchedulingStruct     PopupScheduling;

/******************************************************************************
函数名：Popup_Scheduler_Init
功  能：初始化弹出信息调度器
参  数：无
返回值：无
******************************************************************************/
void Popup_Scheduler_Init(void)
{
  uint8_t i;

  for (i = 0; i < POPUP_NUMBER_TOTAL; i++)
  {
    PopupStatus[i].Status     = POPUP_STATUS_OFF;
    PopupStatus[i].LinkList   = POPUP_LINK_LIST_NONE;
    PopupStatus[i].Prev       = i;
    PopupStatus[i].Next       = i;
    PopupStatus[i].SndReqCode = 1;
  }

  Popup_Link_List_Init(     POPUP_LINK_LIST_NEW_FATAL, POPUP_PRIORITY_NUMBER_FATAL);
  Popup_Link_List_Init(         POPUP_LINK_LIST_FATAL, POPUP_PRIORITY_NUMBER_FATAL);

  Popup_Link_List_Init(      POPUP_LINK_LIST_NEW_HINT, POPUP_PRIORITY_NUMBER_HINT);
  Popup_Link_List_Init(          POPUP_LINK_LIST_HINT, POPUP_PRIORITY_NUMBER_HINT);

  Popup_Link_List_Init(   POPUP_LINK_LIST_NEW_WARNING, POPUP_PRIORITY_NUMBER_WARNING);
  Popup_Link_List_Init(       POPUP_LINK_LIST_WARNING, POPUP_PRIORITY_NUMBER_WARNING);
  Popup_Link_List_Init(POPUP_LINK_LIST_MASKED_WARNING, POPUP_PRIORITY_NUMBER_WARNING);

  PopupScheduling.Timer         = 0;
  PopupScheduling.Current       = POPUP_NONE;
  PopupScheduling.NewSnd        = 0;
  PopupScheduling.WarningExist  = 0;
  PopupScheduling.MaskReq       = 0;
  PopupScheduling.LastMasked    = POPUP_NONE;
  PopupScheduling.MaskedPolling = 0;
}

/******************************************************************************
函数名：Popup_Scheduling_Service
功  能：调度弹出信息,更新当前应显示的弹出信息与应播放的报警音
        可能导致显示的弹出信息发生切换的条件：    1.当前显示的弹出信息被删除
                                              或  2.当前显示的弹出信息被屏蔽
                                              或  3.有新弹出信息到来
                                              或  4.当前弹出信息显示时间到
参  数：无
返回值：无
*******************************************************************************
注  意：该服务函数必须每100ms被调用一次
******************************************************************************/
void Popup_Scheduling_Service(void)
{
  uint8_t   i;
  uint8_t   PopupID;
  uint8_t   PopupMbr;
  uint8_t   PopupNext;
  uint8_t   PopupMaskEn;

  if (SYS_SELF_TEST_DISP_MODE)
    return;

  if (PopupScheduling.Timer < 0xFF)
    PopupScheduling.Timer++;

  PopupMaskEn = 0;                            //专用于处理屏蔽报警时,恰好当前显示的报警被删除的情况

  /*===========================================================================
  1.当前显示的弹出信息被删除
  ============================================================================*/
  if (PopupScheduling.Current < POPUP_NUMBER_TOTAL)
  {
    if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_DELETE)
    {
      if ((PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_NEW_FATAL) || \
          (PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_NEW_WARNING))
      {
        if ((PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_NEW_WARNING) &&
            (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10))
          PopupMaskEn = 1;

        /*if ((PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)   || \
            (PopupAttributeTable[PopupScheduling.Current].Message == POPUP_MSG_DOOR_OPEN_HI_SPEED) || \
            (PopupAttributeTable[PopupScheduling.Current].Message == POPUP_MSG_DOOR_OPEN_LOW_SPEED))*/
        if (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)
        {
          Popup_Link_List_Remove(PopupScheduling.Current);
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_OFF;
          PopupScheduling.Current = POPUP_NONE;
          PopupScheduling.Timer   = POPUP_DISP_TIME_NORMAL * 10;
        }
      }
      else
      {
        if (PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_WARNING)
          PopupMaskEn = 1;

        Popup_Link_List_Remove(PopupScheduling.Current);
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_OFF;
        PopupScheduling.Current = POPUP_NONE;
        PopupScheduling.Timer   = POPUP_DISP_TIME_NORMAL * 10;
      }
    }
    else if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_CLEAR)
    {
      if ((PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_NEW_WARNING) || \
          (PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_WARNING))
        PopupMaskEn = 1;

      Popup_Link_List_Remove(PopupScheduling.Current);
      PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_OFF;
      PopupScheduling.Current = POPUP_NONE;
      PopupScheduling.Timer   = POPUP_DISP_TIME_NORMAL * 10;
    }
  }

  /*===========================================================================
  2.有弹出信息屏蔽请求
  ============================================================================*/
  /*** #2.1：处理报警屏蔽请求 ***/
  if (PopupScheduling.MaskReq)
  {
    PopupScheduling.MaskReq = 0;

    if (PopupScheduling.Current != POPUP_NONE)
    {
      if (((PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_NEW_WARNING) && \
           (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)) || \
          (PopupStatus[PopupScheduling.Current].LinkList == POPUP_LINK_LIST_WARNING))
      {
        /*** #2.1.1：重置报警信息循环显示列表的指针 ***/
        i = 0;
        while (i < PopupLinkList[POPUP_LINK_LIST_WARNING].PrioNum)
        {
          if (PopupLinkList[POPUP_LINK_LIST_WARNING].Prio[i].First != POPUP_NONE)
          {
            PopupLinkList[POPUP_LINK_LIST_WARNING].Cur = PopupLinkList[POPUP_LINK_LIST_WARNING].Prio[i].First;
            break;
          }
          i++;
        }

        /*** #2.1.2：屏蔽报警信息循环显示列表中的报警信息 ***/
        PopupID = PopupLinkList[POPUP_LINK_LIST_WARNING].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_WARNING].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupID);
          PopupStatus[PopupID].Status = POPUP_STATUS_MASKED;
          PopupID   = PopupNext;
        }

        /*** #2.1.3：屏蔽显示中的报警信息 ***/
        Popup_Link_List_Remove(PopupScheduling.Current);
        Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupScheduling.Current);
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_MASKED;
        PopupScheduling.Current = POPUP_NONE;
        PopupScheduling.Timer   = POPUP_DISP_TIME_NORMAL * 10;

        /*** #2.1.4：查找最后一个已屏蔽报警信息 ***/
        i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;
        while (i)
        {
          i--;

          if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
          {
            PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
            break;
          }
        }
      }
    }
    else
    {
      if (PopupMaskEn)
      {
        /*** #2.2.1：重置报警信息循环显示列表的指针 ***/
        i = 0;
        while (i < PopupLinkList[POPUP_LINK_LIST_WARNING].PrioNum)
        {
          if (PopupLinkList[POPUP_LINK_LIST_WARNING].Prio[i].First != POPUP_NONE)
          {
            PopupLinkList[POPUP_LINK_LIST_WARNING].Cur = PopupLinkList[POPUP_LINK_LIST_WARNING].Prio[i].First;
            break;
          }
          i++;
        }

        /*** #2.2.2：屏蔽报警信息循环显示列表中的报警信息 ***/
        PopupID = PopupLinkList[POPUP_LINK_LIST_WARNING].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_WARNING].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupID);
          PopupStatus[PopupID].Status = POPUP_STATUS_MASKED;
          PopupID   = PopupNext;
        }

        /*** #2.2.3：查找最后一个已屏蔽报警信息 ***/
        i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;
        while (i)
        {
          i--;

          if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
          {
            PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
            break;
          }
        }
      }
    }
  }

  /*** #2.2：处理提示信息屏蔽请求 ***/
  if (PopupScheduling.Current < POPUP_NUMBER_TOTAL)
  {
    if ((PopupAttributeTable[PopupScheduling.Current].Type == POPUP_TYPE_HINT) && \
        (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_MASKED))
    {
      Popup_Link_List_Remove(PopupScheduling.Current);
      PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;
      PopupScheduling.Current = POPUP_NONE;
      PopupScheduling.Timer   = POPUP_DISP_TIME_NORMAL * 10;
    }
  }

  /*===========================================================================
  4.有新弹出信息到来
  ============================================================================*/
  /*** #4.1：处理新到来的严重报警 ***/
  if ((PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur != POPUP_NONE) && \
      (PopupStatus[PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur].Status == POPUP_STATUS_NEW))
  {
    if (PopupScheduling.Current != POPUP_NONE)
    {
      switch (PopupStatus[PopupScheduling.Current].LinkList)
      {
      case  POPUP_LINK_LIST_NEW_FATAL :     //当前是严重报警信息在首次显示

        //根据链表插入规则,此新信息优先级必然高于原信息优先级
        //如果首次显示时间已达到或超过最小显示时间,即打断原显示
        if (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)
        {
          if (PopupScheduling.Current != PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur)
          {
            Popup_Link_List_Remove(PopupScheduling.Current);                            //将原信息转移至严重报警列表中
            Popup_Link_List_Insert(POPUP_LINK_LIST_FATAL, PopupScheduling.Current);
            PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;            //标记原信息进入循环显示
          }
          if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果原信息是一个报警类
          {
            for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
            {
              PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
              if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                       //标记成员进入循环显示
            }
          }

          PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;       //新到来的严重报警进入当前显示
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;             //标记此信息进入首次显示
          if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果是一个报警类
          {
            for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
            {
              PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
              if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
                PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                      //标记成员进入首次显示
            }

            if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                //更新声音请求码
              PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
            else
              PopupStatus[PopupScheduling.Current].SndReqCode++;
          }

          PopupScheduling.Timer = 0;                                                    //重置显示时间
        }
        break;

      case  POPUP_LINK_LIST_HINT :          //当前是提示信息在首次显示

        //新严重报警立即打断显示中的提示信息,且未显示的提示信息不需要再显示
        PopupID = PopupScheduling.Current;
        while (PopupLinkList[POPUP_LINK_LIST_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
          PopupID   = PopupNext;
        }

        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;         //新到来的严重报警进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)              //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)     //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                        //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                  //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }

        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;

      case  POPUP_LINK_LIST_NEW_WARNING :   //当前是报警信息在首次显示

        //新严重报警立即打断显示中的报警信息
        Popup_Link_List_Remove(PopupScheduling.Current);                                //将原信息转移至报警列表中
        if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_DELETE)
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_OFF;
        else
        {
          if (PopupAttributeTable[PopupScheduling.Current].DispMode == POPUP_MODE_SINGLE)
          {
            Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupScheduling.Current);
            PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_MASKED;             //标记原信息为已屏蔽状态

            i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;                     //查找最后一个已屏蔽报警
            while (i)
            {
              i--;

              if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
              {
                PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
                break;
              }
            }
          }
          else
          {
            Popup_Link_List_Insert(POPUP_LINK_LIST_WARNING, PopupScheduling.Current);
            PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;              //标记原信息进入循环显示
            if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果原信息是一个报警类
            {
              for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
              {
                PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
                if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                  PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                       //标记成员进入循环显示
              }
            }
          }
        }

        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;         //新到来的严重报警进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)              //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)     //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                        //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                  //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }

        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;

      case  POPUP_LINK_LIST_FATAL :         //当前是严重报警信息在循环显示
      case  POPUP_LINK_LIST_WARNING :       //当前是报警信息在循环显示
      default :                             //意外情况

        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;         //新到来的严重报警进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)              //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)     //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                        //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                  //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }

        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;
      }
    }
    else                                      //此信息到来时并无其他信息显示
    {
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;                 //新到来的严重报警进入当前显示
      PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;                       //标记此信息进入首次显示
      if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)                      //如果是一个报警类
      {
        for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)             //更新该类下所有成员的状态
        {
          PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
          if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
            PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                                 //标记成员进入首次显示
        }

        if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                           //更新声音请求码
          PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
        else
          PopupStatus[PopupScheduling.Current].SndReqCode++;
      }

      PopupScheduling.Timer = 0;                                                              //重置显示时间
    }
  }

  /*** #4.2：处理新到来的提示信息 ***/
  else if ((PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur != POPUP_NONE) && \
           (PopupStatus[PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur].Status == POPUP_STATUS_NEW))
  {
    if (PopupScheduling.Current != POPUP_NONE)
    {
      switch (PopupStatus[PopupScheduling.Current].LinkList)
      {
      case  POPUP_LINK_LIST_NEW_FATAL :     //当前是严重报警信息在首次显示
      case  POPUP_LINK_LIST_FATAL :         //当前是严重报警信息在循环显示

        //提示信息不可以打断严重报警信息显示,且不需要再显示
        PopupID = PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
          PopupID   = PopupNext;
        }
        break;

      case  POPUP_LINK_LIST_HINT :          //当前是提示信息在首次显示

        //提示信息可以立即打断提示信息,且先前的提示信息不需要再接着显示
        //Step 1：删除提示信息显示队列中的所有信息
        PopupID = PopupScheduling.Current;
        while (PopupLinkList[POPUP_LINK_LIST_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
          PopupID   = PopupNext;
        }

        //Step 2：将所有新提示信息转入提示信息显示队列中
        PopupID = PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          Popup_Link_List_Insert(POPUP_LINK_LIST_HINT, PopupID);
          PopupID   = PopupNext;
        }
        PopupLinkList[POPUP_LINK_LIST_HINT].Cur = PopupStatus[PopupLinkList[POPUP_LINK_LIST_HINT].Cur].Next;

        //Step 3：从提示信息显示队列中提取信息显示
        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_HINT].Cur;              //新到来的提示信息进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;

      case  POPUP_LINK_LIST_NEW_WARNING :   //当前是报警信息在首次显示

        //提示信息可以立即打断报警信息
        //Step 1：打断当前的报警信息显示
        Popup_Link_List_Remove(PopupScheduling.Current);                                //将原信息转移至报警列表中
        if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_DELETE)
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_OFF;
        else
        {
          if (PopupAttributeTable[PopupScheduling.Current].DispMode == POPUP_MODE_SINGLE)
          {
            Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupScheduling.Current);
            PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_MASKED;             //标记原信息为已屏蔽状态

            i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;                     //查找最后一个已屏蔽报警
            while (i)
            {
              i--;

              if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
              {
                PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
                break;
              }
            }
          }
          else
          {
            Popup_Link_List_Insert(POPUP_LINK_LIST_WARNING, PopupScheduling.Current);
            PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;              //标记原信息进入循环显示
            PopupLinkList[POPUP_LINK_LIST_WARNING].Cur  = PopupScheduling.Current;        //重定向指针  //----hyq--20180424
            if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果原信息是一个报警类
            {
              for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
              {
                PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
                if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                  PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                       //标记成员进入循环显示
              }
            }
          }
        }
        //PopupLinkList[POPUP_LINK_LIST_WARNING].Cur  = PopupScheduling.Current;          //重定向指针

        //Step 2：将所有新提示信息转入提示信息显示队列中
        PopupID = PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          Popup_Link_List_Insert(POPUP_LINK_LIST_HINT, PopupID);
          PopupID   = PopupNext;
        }
        PopupLinkList[POPUP_LINK_LIST_HINT].Cur = PopupStatus[PopupLinkList[POPUP_LINK_LIST_HINT].Cur].Next;

        //Step 3：从提示信息显示队列中提取信息显示
        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_HINT].Cur;              //新到来的提示信息进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;

      case  POPUP_LINK_LIST_WARNING :       //当前是报警信息在循环显示
      default :                             //意外情况

        //Step 1：将所有新提示信息转入提示信息显示队列中
        PopupID = PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur;
        while (PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cnt)
        {
          PopupNext = PopupStatus[PopupID].Next;
          Popup_Link_List_Remove(PopupID);
          Popup_Link_List_Insert(POPUP_LINK_LIST_HINT, PopupID);
          PopupID   = PopupNext;
        }
        PopupLinkList[POPUP_LINK_LIST_HINT].Cur = PopupStatus[PopupLinkList[POPUP_LINK_LIST_HINT].Cur].Next;

        //Step 2：从提示信息显示队列中提取信息显示
        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_HINT].Cur;              //新到来的提示信息进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;
      }
    }
    else                                      //此信息到来时并无其他信息显示
    {
      //Step 1：将所有新提示信息转入提示信息显示队列中
      PopupID = PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cur;
      while (PopupLinkList[POPUP_LINK_LIST_NEW_HINT].Cnt)
      {
        PopupNext = PopupStatus[PopupID].Next;
        Popup_Link_List_Remove(PopupID);
        Popup_Link_List_Insert(POPUP_LINK_LIST_HINT, PopupID);
        PopupID   = PopupNext;
      }
      PopupLinkList[POPUP_LINK_LIST_HINT].Cur = PopupStatus[PopupLinkList[POPUP_LINK_LIST_HINT].Cur].Next;

      //Step 2：从提示信息显示队列中提取信息显示
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_HINT].Cur;                      //新到来的提示信息进入当前显示
      PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;                       //标记此信息进入首次显示
      PopupScheduling.Timer = 0;                                                              //重置显示时间
    }
  }

  /*** #4.3：处理新到来的报警信息 ***/
  else if ((PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur != POPUP_NONE) && \
           (PopupStatus[PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur].Status == POPUP_STATUS_NEW))
  {
    if (PopupScheduling.Current != POPUP_NONE)
    {
      switch (PopupStatus[PopupScheduling.Current].LinkList)
      {
      case  POPUP_LINK_LIST_NEW_FATAL :     //当前是严重报警信息在首次显示
      case  POPUP_LINK_LIST_FATAL :         //当前是严重报警信息在循环显示

        //报警信息不可以打断严重报警信息显示
        break;

      case  POPUP_LINK_LIST_HINT :          //当前是提示信息在首次显示

        //报警信息可以打断提示信息,但提示信息必须至少显示达到或超过最小显示时间,打断后先前的提示信息不需要再接着显示
        if (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)
        {
          PopupID = PopupScheduling.Current;
          while (PopupLinkList[POPUP_LINK_LIST_HINT].Cnt)
          {
            PopupNext = PopupStatus[PopupID].Next;
            Popup_Link_List_Remove(PopupID);
            PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
            PopupID   = PopupNext;
          }

          PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur;     //新到来的报警进入当前显示
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;             //标记此信息进入首次显示
          if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果是一个报警类
          {
            for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
            {
              PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
              if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
                PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                      //标记成员进入首次显示
            }

            if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                //更新声音请求码
              PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
            else
              PopupStatus[PopupScheduling.Current].SndReqCode++;
          }

          PopupScheduling.Timer = 0;                                                    //重置显示时间
        }
        break;

      case  POPUP_LINK_LIST_NEW_WARNING :   //当前是报警信息在首次显示

        //报警信息可以打断报警信息,但被打断的报警信息必须至少显示达到或超过最小显示时间
        if (PopupScheduling.Timer >= POPUP_DISP_TIME_MIN * 10)
        {
          if (PopupScheduling.Current != PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur)
          {
            Popup_Link_List_Remove(PopupScheduling.Current);

            if (PopupAttributeTable[PopupScheduling.Current].DispMode == POPUP_MODE_SINGLE)
            {
              Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupScheduling.Current);
              PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_MASKED;           //标记原信息为已屏蔽状态

              i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;                   //查找最后一个已屏蔽报警
              while (i)
              {
                i--;

                if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
                {
                  PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
                  break;
                }
              }
            }
            else
            {
              Popup_Link_List_Insert(POPUP_LINK_LIST_WARNING, PopupScheduling.Current);
              PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;            //标记原信息进入循环显示
              if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)          //如果原信息是一个报警类
              {
                for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++) //更新该类下所有成员的状态
                {
                  PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
                  if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                    PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                     //标记成员进入循环显示
                }
              }
            }
          }
          else
          {
            if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果原信息是一个报警类
            {
              for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
              {
                PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
                if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                  PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                       //标记成员进入循环显示
              }
            }
          }

          PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur;     //新到来的报警进入当前显示
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;             //标记此信息进入首次显示
          if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)            //如果是一个报警类
          {
            for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)   //更新该类下所有成员的状态
            {
              PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
              if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
                PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                      //标记成员进入首次显示
            }

            if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                  //更新声音请求码
              PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
            else
              PopupStatus[PopupScheduling.Current].SndReqCode++;
          }

          PopupScheduling.Timer = 0;                                                    //重置显示时间
        }
        break;

      case  POPUP_LINK_LIST_WARNING :       //当前是报警信息在循环显示
      default :                             //意外情况

        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur;       //新到来的报警进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;               //标记此信息进入首次显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)              //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)     //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                        //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                  //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }

        PopupScheduling.Timer = 0;                                                      //重置显示时间
        break;
      }
    }
    else                                      //此信息到来时并无其他信息显示
    {
      if (PopupLinkList[POPUP_LINK_LIST_FATAL].Cnt == 0)                                      //如果没有严重报警信息要显示
      {
        PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur;             //新到来的报警进入当前显示
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;                     //标记此信息进入首次显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)                    //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)           //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                              //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                        //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }

        PopupScheduling.Timer = 0;                                                            //重置显示时间
      }
    }
  }

  /*===========================================================================
  5.当前显示的弹出信息被重置为新信息
  ============================================================================*/
  if ((PopupScheduling.Current != POPUP_NONE) && \
      (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_NEW))
  {
    PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;                         //重新转入首次显示
    if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)                        //如果是一个报警类
    {
      PopupScheduling.Timer = 0;                                                              //只有报警类允许重置,因此只有报警类重置显示时间

      for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)               //更新该类下所有成员的状态
      {
        PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
        if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
          PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                                  //标记成员进入首次显示
      }

      if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                            //更新声音请求码
        PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
      else
        PopupStatus[PopupScheduling.Current].SndReqCode++;
    }
  }

  /*===========================================================================
  6.当前弹出信息显示时间到
  ============================================================================*/
  //只在显示时间到的那个时间点做处理,超出时间认为当前无弹出信息显示
  if (PopupScheduling.Timer == POPUP_DISP_TIME_NORMAL * 10)
  {
    /*** #6.1：处理显示完的报警 ***/
    if (PopupScheduling.Current < POPUP_NUMBER_TOTAL)
    {
      switch (PopupStatus[PopupScheduling.Current].LinkList)
      {
      case POPUP_LINK_LIST_NEW_FATAL :

        Popup_Link_List_Remove(PopupScheduling.Current);                                 //将原信息转移至严重报警列表中
        Popup_Link_List_Insert(POPUP_LINK_LIST_FATAL, PopupScheduling.Current);
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;                 //标记原信息进入循环显示
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)               //如果原信息是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)      //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                          //标记成员进入循环显示
          }
        }
        PopupLinkList[POPUP_LINK_LIST_FATAL].Cur = PopupStatus[PopupScheduling.Current].Next;
        break;

      case POPUP_LINK_LIST_FATAL :

        PopupLinkList[POPUP_LINK_LIST_FATAL].Cur = PopupStatus[PopupScheduling.Current].Next;
        break;

      case POPUP_LINK_LIST_HINT :

        Popup_Link_List_Remove(PopupScheduling.Current);
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;                 //标记原信息进入循环显示
        break;

      case POPUP_LINK_LIST_NEW_WARNING :

        Popup_Link_List_Remove(PopupScheduling.Current);                                 //将原信息转移至报警列表中

        if (PopupAttributeTable[PopupScheduling.Current].DispMode == POPUP_MODE_SINGLE)
        {
          Popup_Link_List_Insert(POPUP_LINK_LIST_MASKED_WARNING, PopupScheduling.Current);
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_MASKED;             //标记原信息为已屏蔽状态

          i = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum;                     //查找最后一个已屏蔽报警
          while (i)
          {
            i--;

            if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last != POPUP_NONE)
            {
              PopupScheduling.LastMasked = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].Last;
              break;
            }
          }
        }
        else
        {
          Popup_Link_List_Insert(POPUP_LINK_LIST_WARNING, PopupScheduling.Current);
          PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;               //标记原信息进入循环显示
          if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)             //如果原信息是一个报警类
          {
            for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)    //更新该类下所有成员的状态
            {
              PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
              if (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST)
                PopupStatus[PopupMbr].Status = POPUP_STATUS_LOOP;                        //标记成员进入循环显示
            }
          }
          PopupLinkList[POPUP_LINK_LIST_WARNING].Cur = PopupStatus[PopupScheduling.Current].Next;
        }
        break;

      case POPUP_LINK_LIST_WARNING :

        PopupLinkList[POPUP_LINK_LIST_WARNING].Cur = PopupStatus[PopupScheduling.Current].Next;
        break;

      default :

        break;
      }
    }

    /*** #6.2：查找下一个显示的报警 ***/
    PopupScheduling.Current = POPUP_NONE;

    if (PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cnt)
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_FATAL].Cur;
    else if (PopupLinkList[POPUP_LINK_LIST_FATAL].Cnt)
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_FATAL].Cur;
    else if (PopupLinkList[POPUP_LINK_LIST_HINT].Cnt)
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_HINT].Cur;
    else if (PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cnt)
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cur;
    else if (PopupLinkList[POPUP_LINK_LIST_WARNING].Cnt)
      PopupScheduling.Current = PopupLinkList[POPUP_LINK_LIST_WARNING].Cur;

    if (PopupScheduling.Current < POPUP_NUMBER_TOTAL)
    {
      PopupScheduling.Timer = 0;

      if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_NEW)
      {
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_FIRST;
        if (PopupAttributeTable[PopupScheduling.Current].pMbrList != NULL)                    //如果是一个报警类
        {
          for (i = 0; i < PopupAttributeTable[PopupScheduling.Current].MbrCnt; i++)           //更新该类下所有成员的状态
          {
            PopupMbr = PopupAttributeTable[PopupScheduling.Current].pMbrList[i];
            if (PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW)
              PopupStatus[PopupMbr].Status = POPUP_STATUS_FIRST;                              //标记成员进入首次显示
          }

          if (PopupStatus[PopupScheduling.Current].SndReqCode == 0xFF)                        //更新声音请求码
            PopupStatus[PopupScheduling.Current].SndReqCode = 0x01;
          else
            PopupStatus[PopupScheduling.Current].SndReqCode++;
        }
      }
      else
        PopupStatus[PopupScheduling.Current].Status = POPUP_STATUS_LOOP;
    }
  }

  /*===========================================================================
  7.更新报警存在状态
  ============================================================================*/
  if ((PopupLinkList[POPUP_LINK_LIST_NEW_WARNING].Cnt != 0) || \
      (PopupLinkList[POPUP_LINK_LIST_WARNING].Cnt != 0) || \
      (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cnt != 0))
    PopupScheduling.WarningExist = 1;
  else
    PopupScheduling.WarningExist = 0;

  /*===========================================================================
  8.复位已屏蔽报警指针(用于报警查询)
  ============================================================================*/
  if (PopupScheduling.MaskedPolling)
  {
    if (PopupScheduling.Current != POPUP_NONE)
    {
      PopupScheduling.MaskedPolling = 0;
      PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = PopupStatus[PopupScheduling.LastMasked].Next;
    }
  }
}

/******************************************************************************
函数名：Popup_Request
功  能：请求显示一个弹出信息
参  数：PopupID：请求显示的弹出信息
返回值：无
******************************************************************************/
void Popup_Request(uint8_t PopupID)
{
  if (PopupStatus[PopupID].Status == POPUP_STATUS_OFF)
  {
    if (PopupAttributeTable[PopupID].MbrCnt == 0)       //申请的报警是某报警类的成员
    {
      PopupStatus[PopupID].Status = POPUP_STATUS_NEW;   //置该弹出信息状态为新信息状态

      PopupID = PopupAttributeTable[PopupID].Class;     //类成员不进入链表,获取该报警对应的报警类进行调度
      Popup_Link_List_Remove(PopupID);                  //将该报警类移出原报警列表
    }

    PopupStatus[PopupID].Status = POPUP_STATUS_NEW;     //置该弹出信息状态为新信息状态

    switch (PopupAttributeTable[PopupID].Type)
    {
    case POPUP_TYPE_FATAL   :
      Popup_Link_List_Insert(POPUP_LINK_LIST_NEW_FATAL, PopupID);
      break;

    case POPUP_TYPE_HINT    :
      Popup_Link_List_Insert(POPUP_LINK_LIST_NEW_HINT, PopupID);
      break;

    case POPUP_TYPE_WARNING :
      Popup_Link_List_Insert(POPUP_LINK_LIST_NEW_WARNING, PopupID);
      break;

    default                 :
      break;
    }
  }
  else if (PopupStatus[PopupID].Status == POPUP_STATUS_DELETE)
  {
    //有POPUP_STATUS_DELETE标志的一定是正在显示的信息
    //直接根据所在链表恢复状态即可
    if ((PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_NEW_FATAL) || \
        (PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_NEW_WARNING) || \
        (PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_HINT))
      PopupStatus[PopupID].Status = POPUP_STATUS_FIRST;
    else if ((PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_FATAL) || \
             (PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_WARNING))
      PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
    else if (PopupStatus[PopupID].LinkList == POPUP_LINK_LIST_MASKED_WARNING)
      PopupStatus[PopupID].Status = POPUP_STATUS_MASKED;
  }
}

/******************************************************************************
函数名：Popup_Delete
功  能：请求解除显示一个弹出信息
参  数：PopupID：请求解除显示的弹出信息
返回值：无
******************************************************************************/
void Popup_Delete(uint8_t PopupID)
{
  uint8_t i;
  uint8_t PopupCls;
  uint8_t PopupMbr;

  if ((PopupStatus[PopupID].Status == POPUP_STATUS_OFF) || \
      (PopupStatus[PopupID].Status == POPUP_STATUS_DELETE) || \
      (PopupStatus[PopupID].Status == POPUP_STATUS_CLEAR))
    return;

  if (PopupAttributeTable[PopupID].MbrCnt == 0)                 //要删除的报警是某报警类的成员
  {
    Popup_Link_List_Remove(PopupID);
    PopupStatus[PopupID].Status = POPUP_STATUS_OFF;

    PopupCls = PopupAttributeTable[PopupID].Class;               //获取该报警对应的报警类
    for (i = 0; i < PopupAttributeTable[PopupCls].MbrCnt; i++)   //检查该类报警下的成员
    {
      PopupMbr = PopupAttributeTable[PopupCls].pMbrList[i];

      if ((PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_LOOP) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_MASKED))
        return;
    }

    PopupID = PopupCls;
  }

  if (PopupScheduling.Current == PopupID)         //正在显示中的报警不能立即删除,置标志,由调度程序删除
  {
    PopupStatus[PopupID].Status = POPUP_STATUS_DELETE;
    return;
  }

  Popup_Link_List_Remove(PopupID);
  PopupStatus[PopupID].Status = POPUP_STATUS_OFF;
}

/******************************************************************************
函数名：Popup_Clear
功  能：请求立即清除显示一个弹出信息,无论该信息是否达到最小显示时间
        用于IGN OFF时,立即清除弹出信息显示
参  数：PopupID：请求解除显示的弹出信息
返回值：无
******************************************************************************/
void Popup_Clear(uint8_t PopupID)
{
  uint8_t i;
  uint8_t PopupCls;
  uint8_t PopupMbr;

  if ((PopupStatus[PopupID].Status == POPUP_STATUS_OFF) || \
      (PopupStatus[PopupID].Status == POPUP_STATUS_CLEAR))
    return;

  if (PopupAttributeTable[PopupID].MbrCnt == 0)                 //要删除的报警是某报警类的成员
  {
    Popup_Link_List_Remove(PopupID);
    PopupStatus[PopupID].Status = POPUP_STATUS_OFF;

    PopupCls = PopupAttributeTable[PopupID].Class;               //获取该报警对应的报警类
    for (i = 0; i < PopupAttributeTable[PopupCls].MbrCnt; i++)   //检查该类报警下的成员
    {
      PopupMbr = PopupAttributeTable[PopupCls].pMbrList[i];

      if ((PopupStatus[PopupMbr].Status == POPUP_STATUS_NEW) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_FIRST) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_LOOP) || \
          (PopupStatus[PopupMbr].Status == POPUP_STATUS_MASKED))
        return;
    }

    PopupID = PopupCls;
  }

  if (PopupScheduling.Current == PopupID)         //正在显示中的报警不能立即删除,置标志,由调度程序删除
  {
    PopupStatus[PopupID].Status = POPUP_STATUS_CLEAR;
    return;
  }

  Popup_Link_List_Remove(PopupID);
  PopupStatus[PopupID].Status = POPUP_STATUS_OFF;
}

/******************************************************************************
函数名：Popup_Mask_Request
功  能：请求屏蔽报警信息
        可以在任意时刻发出屏蔽请求,只有满足屏蔽条件时,报警信息才会被屏蔽
参  数：无
返回值：无
******************************************************************************/
void Popup_Mask_Request(void)
{
  PopupScheduling.MaskReq = 1;
}

/******************************************************************************
函数名：Popup_Mask_Request
功  能：请求屏蔽报警信息
        可以在任意时刻发出屏蔽请求,只有满足屏蔽条件时,报警信息才会被屏蔽
参  数：无
返回值：无
******************************************************************************/
void Popup_Hint_Mask_Request(uint8_t PopupID)
{
  if (PopupID < POPUP_NUMBER_TOTAL)
  {
    if (PopupAttributeTable[PopupID].Type == POPUP_TYPE_HINT)
    {
      if (PopupScheduling.Current == PopupID)         //正在显示中的提示信息不能立即屏蔽,置标志,由调度程序屏蔽
      {
        PopupStatus[PopupID].Status = POPUP_STATUS_MASKED;
        return;
      }

      PopupStatus[PopupID].Status = POPUP_STATUS_LOOP;
      Popup_Link_List_Remove(PopupScheduling.Current);
    }
  }
}

/******************************************************************************
函数名：Popup_Get_Status
功  能：获取弹出信息的当前状态
参  数：PopupID：弹出信息名称
返回值：弹出信息的当前状态
******************************************************************************/
uint8_t Popup_Get_Status(uint8_t PopupID)
{
  return PopupStatus[PopupID].Status;
}

/******************************************************************************
函数名：Popup_Get_Current_Type
功  能：获取当前显示的弹出信息的类型
参  数：无
返回值：当前显示的弹出信息的类型
******************************************************************************/
uint8_t Popup_Get_Current_Type(void)
{
  if (PopupScheduling.Current >= POPUP_NUMBER_TOTAL)
    return 0xFF;

  return PopupAttributeTable[PopupScheduling.Current].Type;
}

/******************************************************************************
函数名：Popup_Get_Current_Message
功  能：获取当前应显示的弹出信息
参  数：无
返回值：当前应显示的弹出信息
******************************************************************************/
uint8_t Popup_Get_Current_Message(void)
{
  if (PopupScheduling.Current >= POPUP_NUMBER_TOTAL)
    return POPUP_MSG_NONE;

  return PopupAttributeTable[PopupScheduling.Current].Message;
}

/******************************************************************************
函数名：Popup_Get_Current_Sound
功  能：获取当前应播放的声音
参  数：无
返回值：当前应播放的声音
******************************************************************************/
uint8_t Popup_Get_Current_Sound(void)
{
  if (PopupScheduling.Current >= POPUP_NUMBER_TOTAL)
    return SND_NONE;

  return PopupAttributeTable[PopupScheduling.Current].Snd;
}

/******************************************************************************
函数名：Popup_Get_Current_Sound_Req_Code
功  能：获取当前应播放的声音的请求码
参  数：无
返回值：请求码
******************************************************************************/
uint8_t Popup_Get_Current_Sound_Req_Code(void)
{
  if (PopupScheduling.Current >= POPUP_NUMBER_TOTAL)
    return 0;

  if (PopupAttributeTable[PopupScheduling.Current].SndMode == POPUP_MODE_MULTI)
    return PopupStatus[PopupScheduling.Current].SndReqCode;

  if (PopupStatus[PopupScheduling.Current].Status == POPUP_STATUS_FIRST)
    return PopupStatus[PopupScheduling.Current].SndReqCode;

  return 0;
}

/******************************************************************************
函数名：Popup_Get_Warning_Status
功  能：获取报警信息的状态,用于惊叹号标志的显示
参  数：无
返回值：0 - 当前没有报警信息
        1 - 当前有报警信息(新报警信息 或 循环显示报警信息 或 已屏蔽的报警信息)
******************************************************************************/
uint8_t Popup_Get_Warning_Status(void)
{
  return PopupScheduling.WarningExist;
}

/******************************************************************************
函数名：Popup_Get_First_Masked_Warning
功  能：获取屏蔽的报警信息中的第一个报警信息
        当前没有已屏蔽的报警信息时,返回 POPUP_NONE
参  数：无
返回值：已屏蔽的第一个报警信息
******************************************************************************/
uint8_t Popup_Get_First_Masked_Warning(void)
{
  uint8_t i;
  uint8_t PopupID;

  if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cnt)
  {
    i = 0;
    while (i < PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum)
    {
      PopupID = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[i].First;
      if (PopupID != POPUP_NONE)
        return PopupID;

      i++;
    }
  }
  return POPUP_NONE;
}

/******************************************************************************
函数名：Popup_Get_Last_Masked_Warning
功  能：获取屏蔽的报警信息中的最后一个报警信息
        当前没有已屏蔽的报警信息时,返回 POPUP_NONE
参  数：无
返回值：已屏蔽的最后一个报警信息
******************************************************************************/
uint8_t Popup_Get_Last_Masked_Warning(void)
{
  uint8_t i;
  uint8_t j;
  uint8_t PopupID;

  if (PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cnt)
  {
    i = 0;
    while (i < PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum)
    {
      i++;
      j = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].PrioNum - i;

      PopupID = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Prio[j].Last;
      if (PopupID != POPUP_NONE)
        return PopupID;
    }
  }
  return POPUP_NONE;
}

/******************************************************************************
函数名：Popup_Get_Masked_Warning_Msg
功  能：获取屏蔽的报警信息
        当前没有已屏蔽的报警信息时,返回 POPUP_NONE
参  数：无
返回值：已屏蔽的报警信息
******************************************************************************/
uint8_t Popup_Get_Masked_Warning_Msg(void)
{
  uint8_t PopupID;

  PopupID = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur;

  if (PopupID >= POPUP_NUMBER_TOTAL)
    return POPUP_MSG_NONE;

  return PopupAttributeTable[PopupID].Message;
}

/******************************************************************************
函数名：Popup_Masked_Warning_Polling_Reset
功  能：重置已屏蔽的报警查询起点
参  数：Mode：查询模式 POPUP_POLLING_FORWARD - 正向查找模式
                       POPUP_POLLING_REVERSE - 逆向查找模式
返回值：无
******************************************************************************/
void Popup_Masked_Warning_Polling_Reset(uint8_t Mode)
{
  uint8_t PopupID;

  if (Mode == POPUP_POLLING_FORWARD)
    PopupID = Popup_Get_First_Masked_Warning();
  else
    PopupID = Popup_Get_Last_Masked_Warning();

  PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = PopupID;
}

/******************************************************************************
函数名：Popup_Masked_Warning_Polling
功  能：查询已屏蔽的报警

        每调用一次此函数,已屏蔽报警指针会按指定方向移动一位,当指针已移指定方向
        上的最后一个报警信息时,再次向同一方向查询,当前的已屏蔽报警信息会变为
        POPUP_NONE 表示报警查询已结束

        例如:当前有已屏蔽报警 A、B、C、D,调用Popup_Masked_Warning_Polling_Reset
        函数,设定方向为 POPUP_POLLING_FORWARD 时,已屏蔽报警指针会指向报警A,而后,
        调用该函数设定方向为 POPUP_POLLING_FORWARD 时已屏蔽报警指针即指向报警B.
        重复调用此函数且方向不变至已屏蔽报警指针指向报警D后,再以相同方向调用此函
        数则返回 POPUP_NONE,表示查询已结束

        通过调用Popup_Get_Masked_Warning可读出当前已屏蔽报警指针指向的报警

参  数：Mode：查询模式 POPUP_POLLING_FORWARD - 正向查找模式
                       POPUP_POLLING_REVERSE - 逆向查找模式
返回值：无
******************************************************************************/
void Popup_Masked_Warning_Polling(uint8_t Mode)
{
  uint8_t PopupEnd;
  uint8_t PopupID;

  PopupID  = PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur;

  if (PopupID != POPUP_NONE)
  {
    if (Mode == POPUP_POLLING_FORWARD)
    {
      PopupEnd = Popup_Get_Last_Masked_Warning();

      if (PopupEnd != POPUP_NONE)
      {
        if (PopupID == PopupEnd)
          PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = POPUP_NONE;
        else
          PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = PopupStatus[PopupID].Next;
      }
    }
    else
    {
      PopupEnd = Popup_Get_First_Masked_Warning();

      if (PopupEnd != POPUP_NONE)
      {
        if (PopupID == PopupEnd)
          PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = POPUP_NONE;
        else
          PopupLinkList[POPUP_LINK_LIST_MASKED_WARNING].Cur = PopupStatus[PopupID].Prev;
      }
    }
  }
}

/******************************************************************************
函数名：Popup_Link_List_Init
功  能：初始化链表
参  数：LinkListID：链表名称
        PrioNum   ：该链表下优先级数
返回值：无
******************************************************************************/
void Popup_Link_List_Init(uint8_t LinkListID, uint8_t PrioNum)
{
  uint8_t i;

  PopupLinkList[LinkListID].Cnt     = 0;
  PopupLinkList[LinkListID].Cur     = POPUP_NONE;
  PopupLinkList[LinkListID].PrioNum = PrioNum;

  for (i = 0; i < PrioNum; i++)
  {
    PopupLinkList[LinkListID].Prio[i].First = POPUP_NONE;
    PopupLinkList[LinkListID].Prio[i].Last  = POPUP_NONE;
  }
}

/******************************************************************************
函数名：Popup_Link_List_Insert
功  能：向链表中插入弹出信息
参  数：LinkListID：链表名称
        PopupID   ：弹出信息名称
返回值：无
******************************************************************************/
void Popup_Link_List_Insert(uint8_t LinkListID, uint8_t PopupID)
{
  uint8_t   i;
  uint8_t   FoundID;
  uint8_t   Prio;
  uint8_t   InsResult;

  if (PopupStatus[PopupID].LinkList == LinkListID)
    return;                                       //弹出信息已经在当前链表中则返回

  Prio = PopupAttributeTable[PopupID].Priority;   //获取弹出信息优先级

  if (PopupLinkList[LinkListID].Cnt == 0)         //当前链表下没有任何弹出信息
  {
    PopupStatus[PopupID].Prev = PopupID;          //因只有一个弹出信息,前后弹出信息均指向自己
    PopupStatus[PopupID].Next = PopupID;

    PopupLinkList[LinkListID].Cur = PopupID;      //当前此链表指针指向该弹出信息

    PopupLinkList[LinkListID].Prio[Prio].First = PopupID;         //优先级维护
    PopupLinkList[LinkListID].Prio[Prio].Last  = PopupID;
  }
  else                                            //当前链表已有弹出信息
  {
    InsResult = 0;                                //清插入成功标示

    for (i = 0; i <= Prio; i++)                   //从当前优先级起前向查找新弹出信息的接入点
    {
      FoundID = PopupLinkList[LinkListID].Prio[Prio - i].Last;

      if (FoundID != POPUP_NONE)                  //找到插入点
      {
        PopupStatus[PopupID].Prev = FoundID;      //插入弹出信息,维护链表
        PopupStatus[PopupID].Next = PopupStatus[FoundID].Next;
        PopupStatus[PopupStatus[FoundID].Next].Prev = PopupID;
        PopupStatus[FoundID].Next = PopupID;

        InsResult = 1;                            //插入成功
        break;
      }
    }

    if (InsResult == 0)                           //前向查找时未能成功插入新弹出信息则转入后向查找
    {
      for (i = Prio + 1; i < PopupLinkList[LinkListID].PrioNum; i++)
      {
        FoundID = PopupLinkList[LinkListID].Prio[i].First;

        if (FoundID != POPUP_NONE)                //找到插入点
        {
          PopupStatus[PopupID].Next = FoundID;    //插入弹出信息,维护链表
          PopupStatus[PopupID].Prev = PopupStatus[FoundID].Prev;
          PopupStatus[PopupStatus[FoundID].Prev].Next = PopupID;
          PopupStatus[FoundID].Prev = PopupID;

          break;
        }
      }
    }

    if (Prio < PopupAttributeTable[PopupLinkList[LinkListID].Cur].Priority)
      PopupLinkList[LinkListID].Cur = PopupID;    //将当前此链表指针指向更高优先级弹出信息

    if(PopupLinkList[LinkListID].Prio[Prio].First == POPUP_NONE)  //当前优先级下尚无弹出信息
    {
      PopupLinkList[LinkListID].Prio[Prio].First = PopupID;       //则当前优先级下的首末弹出信息均为此新弹出信息
      PopupLinkList[LinkListID].Prio[Prio].Last  = PopupID;
    }
    else                                                          //当前优先级下有弹出信息
      PopupLinkList[LinkListID].Prio[Prio].Last  = PopupID;       //依照插入规则,新弹出信息排列于此优先级下的末位
  }

  PopupLinkList[LinkListID].Cnt++;
  PopupStatus[PopupID].LinkList = LinkListID;     //标记弹出信息所在链表
}

/******************************************************************************
函数名：Popup_Link_List_Remove
功  能：从弹出信息所在链表中移除弹出信息
参  数：PopupID   ：弹出信息名称
返回值：无
******************************************************************************/
void Popup_Link_List_Remove(uint8_t PopupID)
{
  uint8_t   Prio;
  uint8_t   LinkListID;

  LinkListID = PopupStatus[PopupID].LinkList;

  if (LinkListID == POPUP_LINK_LIST_NONE)
    return;                                       //弹出信息不在链表中则返回

  if (PopupLinkList[LinkListID].Cnt)
    PopupLinkList[LinkListID].Cnt--;

  Prio = PopupAttributeTable[PopupID].Priority;   //获取弹出信息优先级

  if (PopupLinkList[LinkListID].Cnt == 0)         //删除后当前链表已下没有任何弹出信息
  {
    PopupLinkList[LinkListID].Prio[Prio].First = POPUP_NONE;         //优先级维护
    PopupLinkList[LinkListID].Prio[Prio].Last  = POPUP_NONE;

    PopupLinkList[LinkListID].Cur = POPUP_NONE;   //重置当前此链表指针
  }
  else
  {
    if (PopupID == PopupLinkList[LinkListID].Prio[Prio].First)
    {
      if (PopupLinkList[LinkListID].Prio[Prio].First == PopupLinkList[LinkListID].Prio[Prio].Last)
      {
        PopupLinkList[LinkListID].Prio[Prio].First = POPUP_NONE;
        PopupLinkList[LinkListID].Prio[Prio].Last  = POPUP_NONE;
      }
      else
        PopupLinkList[LinkListID].Prio[Prio].First = PopupStatus[PopupID].Next;
    }
    else if (PopupID == PopupLinkList[LinkListID].Prio[Prio].Last)
      PopupLinkList[LinkListID].Prio[Prio].Last = PopupStatus[PopupID].Prev;

    if (PopupLinkList[LinkListID].Cur == PopupID)
      PopupLinkList[LinkListID].Cur = PopupStatus[PopupID].Next;

    PopupStatus[PopupStatus[PopupID].Prev].Next = PopupStatus[PopupID].Next;
    PopupStatus[PopupStatus[PopupID].Next].Prev = PopupStatus[PopupID].Prev;
  }

  PopupStatus[PopupID].Prev = PopupID;                      //弹出信息被删除,前后弹出信息均指向自己
  PopupStatus[PopupID].Next = PopupID;

  PopupStatus[PopupID].LinkList = POPUP_LINK_LIST_NONE;     //弹出信息已不在任何链表中
}
