Bladeren bron

V0.3
1、修改完成了线程控制需要的结构体
2、修改完成了派发任务的线程
3、修改完成了按照任务创建线程的方式
4、修改完成了普通工作线程

Apple 6 maanden geleden
bovenliggende
commit
f0fb7d75e4

+ 319 - 45
SecurePlayAuxServer/GlobalInfo/GlobalInfo.cpp

@@ -94,6 +94,30 @@ AlarmInfo::AlarmInfo()
     BboxList = "";
 }
 
+
+AlarmInfo::AlarmInfo(const AlarmInfo& other)
+{
+    Is_Alarm = other.Is_Alarm;
+    AlarmID = other.AlarmID;
+    DeviceID = other.DeviceID;
+    RoomID = other.RoomID;
+    ChannelID = other.ChannelID;
+    State = other.State;
+    OnWork = other.OnWork;
+    StartTime = other.StartTime;
+    EndTime = other.EndTime;
+    EventTime = other.EventTime;
+    PicUrl = other.PicUrl;
+    ImageInfo = other.ImageInfo;
+    AppID = other.AppID;
+    ActionID = other.ActionID;
+    ActionDes = other.ActionDes;
+    FaceIDList = other.FaceIDList;
+    FaceNameList = other.FaceNameList;
+    BboxList = other.BboxList;
+    vecPersonInfo = other.vecPersonInfo;
+}
+
 AlarmInfo& AlarmInfo::operator=(AlarmInfo& other)
 {
     if(this != &other)
@@ -144,6 +168,46 @@ void AlarmInfo::reInit()
     BboxList = "";
 }
 
+/**
+ * @brief 添加报警信息
+ * 
+ * @param info 
+ * @return true 
+ * @return false 
+ */
+bool ListAlarmInfo::addAlarmInfo(AlarmInfo& info)
+{
+    /* 先查找有没有重复的 */
+    auto p = findAlarmInfo(info);
+    if(p != nullptr)
+    {
+        return false;
+    }
+    listAlarmInfo.push_back(info);
+    return true;
+}
+
+
+/**
+ * @brief 检查列表中是是否有这个报警信息,这里只检查ChannelID、RoomID、CameraID、ActionID是否相等
+ * 
+ * @param info 
+ * @return AlarmInfo* 
+ */
+AlarmInfo* ListAlarmInfo::findAlarmInfo(AlarmInfo& info)
+{
+    for(auto& it0 : listAlarmInfo)
+    {
+        if(it0.ChannelID == info.ChannelID && it0.RoomID == info.RoomID && it0.DeviceID == info.DeviceID && it0.ActionID == info.ActionID)
+        {
+            return &it0;
+        }
+    }
+    return nullptr;
+}
+
+
+
 AlarmRuleInfo::AlarmRuleInfo()
 {
     LiveMinEnable = false;
@@ -502,8 +566,8 @@ FuncActionInfo::FuncActionInfo()
     appFunction = AppFunction::APP_NONE;
     RunState = RunTimeState::RUN_STATE_NONE;
     strFunctionName = "";
-    StartTime = std::chrono::system_clock::now();
-    EndTime = std::chrono::system_clock::now();
+    StartTime = QDateTime::currentDateTime();
+    EndTime = QDateTime::currentDateTime();
     listRoomCamActInfo.clear();
 }
 FuncActionInfo& FuncActionInfo::operator=(FuncActionInfo& other)
@@ -553,63 +617,255 @@ bool FuncActionInfo::addActionInfo(const ActionInfo& info)
     return true;
 }
 
+/* 清空算法信息 */
+void FuncActionInfo::clearActionList()
+{
+    listRoomCamActInfo.clear();
+}
+
 /**
- * @brief 添加功能信息,一个应用功能在一个频道内只有一个实例
+ * @brief 添加应用信息,一个应用功能在一个频道内只有一个实例
+ *        这里是添加应用功能和时间段信息
  * 
- * @param func 应用功能
- * @return true 添加成功,或者已有这个应用功能
+ * @param func 
+ * @return true 
  * @return false 
  */
-bool ListFuncActInfo::addFuncActionInfo(AppFunction func)
+bool ListFuncActInfo::addFuncActionInfo(const AppAndTimeInfo& func)
 {
-    if(func == AppFunction::APP_NONE)
+    if(func.AppType == 0)
     {
         return false;
     }
-    /* 先查找有没有这个应用信息 */
-    if(findAppFunction(func))
-    {
-        return true;
-    }
-    FuncActionInfo* pFuncActionInfo = new FuncActionInfo;
-    pFuncActionInfo->appFunction = func;
-    if(func == AppFunction::APP_ONWORK)
-    {
-        pFuncActionInfo->strFunctionName = "人员在岗识别";
-    }
-    else if(func == AppFunction::APP_ILLEGAL)
-    {
-        pFuncActionInfo->strFunctionName = "非法入侵检测";
-    }
-    else if(func == AppFunction::APP_REGIONAL)
-    {
-        pFuncActionInfo->strFunctionName = "人员计数";
-    }
-    else if(func == AppFunction::APP_CONTRABAND)
+    /* 解出这条信息里包含几个App,AppType按位计算,总共8个应用信息 */
+    for(int i = 0; i < 8; ++i)
     {
-        pFuncActionInfo->strFunctionName = "违禁物品";
-    }
-    else if(func == AppFunction::APP_PLAYPHONE)
-    {
-        pFuncActionInfo->strFunctionName = "玩手机";
-    }
-    else if(func == AppFunction::APP_FATIGUE)
-    {
-        pFuncActionInfo->strFunctionName = "疲劳检测";
-    }
-    else if(func == AppFunction::APP_MOUSE)
-    {
-        pFuncActionInfo->strFunctionName = "动物识别";
-    }
-    else if(func == AppFunction::APP_NOMASK)
-    {
-        pFuncActionInfo->strFunctionName = "口罩识别";
+        if(func.AppType & 0x01)
+        {
+            /* 查找有没有这个应用 */
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_ONWORK);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_ONWORK;
+            fa->strFunctionName = "人员在岗识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if(func.AppType & 0x02)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_CONTRABAND);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_CONTRABAND;
+            fa->strFunctionName = "违禁品识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x04)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_ILLEGAL);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_ILLEGAL;
+            fa->strFunctionName = "非法入侵检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x08)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_FATIGUE);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_FATIGUE;
+            fa->strFunctionName = "疲劳检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x10)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_REGIONAL);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_REGIONAL;
+            fa->strFunctionName = "区域人员检测";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x20)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_MOUSE);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_MOUSE;
+            fa->strFunctionName = "老鼠识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x40)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_PLAYPHONE);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_PLAYPHONE;
+            fa->strFunctionName = "玩手机识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x80)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_NOMASK);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_NOMASK;
+            fa->strFunctionName = "未戴口罩识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
+        else if (func.AppType & 0x0100)
+        {
+            auto pFuncActionInfo = findAppFunction(func.ChannelID, AppFunction::APP_ALLDOWN);
+            if(pFuncActionInfo != nullptr)
+            {
+                /* 更新时间信息 */
+                pFuncActionInfo->StartTime = func.StartTime;
+                pFuncActionInfo->EndTime = func.EndTime;
+                continue;
+            }
+            FuncActionInfo* fa = new FuncActionInfo;
+            fa->ChannelID = func.ChannelID;
+            fa->appFunction = AppFunction::APP_ALLDOWN;
+            fa->strFunctionName = "摔倒识别";
+            fa->StartTime = func.StartTime;
+            fa->EndTime = func.EndTime;
+            listFuncActionInfo.push_back(fa);
+        }
     }
-    listFuncActionInfo.push_back(pFuncActionInfo);
+
 
     return true;
 }
 
+// /**
+//  * @brief 添加功能信息,一个应用功能在一个频道内只有一个实例
+//  * 
+//  * @param func 应用功能
+//  * @return true 添加成功,或者已有这个应用功能
+//  * @return false 
+//  */
+// bool ListFuncActInfo::addFuncActionInfo(AppFunction& func)
+// {
+//     if(func == AppFunction::APP_NONE)
+//     {
+//         return false;
+//     }
+//     /* 先查找有没有这个应用信息 */
+//     if(findAppFunction(func))
+//     {
+//         return true;
+//     }
+//     FuncActionInfo* pFuncActionInfo = new FuncActionInfo;
+//     pFuncActionInfo->appFunction = func;
+//     if(func == AppFunction::APP_ONWORK)
+//     {
+//         pFuncActionInfo->strFunctionName = "人员在岗识别";
+//     }
+//     else if(func == AppFunction::APP_ILLEGAL)
+//     {
+//         pFuncActionInfo->strFunctionName = "非法入侵检测";
+//     }
+//     else if(func == AppFunction::APP_REGIONAL)
+//     {
+//         pFuncActionInfo->strFunctionName = "人员计数";
+//     }
+//     else if(func == AppFunction::APP_CONTRABAND)
+//     {
+//         pFuncActionInfo->strFunctionName = "违禁物品";
+//     }
+//     else if(func == AppFunction::APP_PLAYPHONE)
+//     {
+//         pFuncActionInfo->strFunctionName = "玩手机";
+//     }
+//     else if(func == AppFunction::APP_FATIGUE)
+//     {
+//         pFuncActionInfo->strFunctionName = "疲劳检测";
+//     }
+//     else if(func == AppFunction::APP_MOUSE)
+//     {
+//         pFuncActionInfo->strFunctionName = "动物识别";
+//     }
+//     else if(func == AppFunction::APP_NOMASK)
+//     {
+//         pFuncActionInfo->strFunctionName = "口罩识别";
+//     }
+//     listFuncActionInfo.push_back(pFuncActionInfo);
+
+//     return true;
+// }
+
 /**
  * @brief 添加算法信息,根据传进来的算法ID,将其加入到对应的功能中
  * 
@@ -766,6 +1022,24 @@ FuncActionInfo* ListFuncActInfo::findAppFunction(const int ChannelID, const AppF
     return nullptr;
 }
 
+/**
+ * @brief 查找这个应用信息
+ * 
+ * @param func 
+ * @return FuncActionInfo* 
+ */
+FuncActionInfo* ListFuncActInfo::findAppFunction(const FuncActionInfo& func)
+{
+    for(const auto& it0 : listFuncActionInfo)
+    {
+        if(it0->ChannelID == func.ChannelID && it0->appFunction == func.appFunction)
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
 
 /* ====================================================================================
  * **************************    GlobalConfig成员函数    ******************************

+ 48 - 6
SecurePlayAuxServer/GlobalInfo/GlobalInfo.h

@@ -6,6 +6,7 @@
 #include <list>
 #include <map>
 #include <mutex>
+#include <QDateTime>
 #include "nlohmann/json.hpp"
 
 
@@ -41,14 +42,14 @@ enum class RunTimeState
 enum class AppFunction
 {
     APP_NONE = 0,               /* 无功能 */
-    APP_ONWORK = 1,             /* 人员在岗识别 */
+    APP_ONWORK = 1,             /* 人员在岗识别(需要多个摄像机配合) */
     APP_CONTRABAND,             /* 违禁品识别 */
     APP_ILLEGAL,                /* 非法入侵检测 */
     APP_FATIGUE,                /* 疲劳检测 */
-    APP_REGIONAL,               /* 区域人员检测 */
+    APP_REGIONAL,               /* 区域人员检测(需要多个摄像机配合) */
     APP_MOUSE,                  /* 老鼠识别 */
     APP_PLAYPHONE,              /* 玩手机识别 */
-    APP_NOMASK,                 /* 口罩识别 */
+    APP_NOMASK,                 /* 未戴口罩识别 */
     APP_ALLDOWN,                /* 摔倒识别 */
 };
 
@@ -231,12 +232,26 @@ struct AlarmInfo
     std::vector<PersonInfo> vecPersonInfo;    /* 人员信息 */
 
     AlarmInfo();
+    AlarmInfo(const AlarmInfo& other);
     AlarmInfo& operator=(AlarmInfo& other);
 
     void reInit();
+};
+
+/**
+ * @brief 报警信息容器,并提供一些函数
+ * 
+ */
+struct ListAlarmInfo
+{
+    std::list<AlarmInfo> listAlarmInfo;    /* 报警信息列表 */
 
+    /* 添加报警信息 */
+    bool addAlarmInfo(AlarmInfo& info);
+    AlarmInfo* findAlarmInfo(AlarmInfo& info);
 };
 
+
 /**
  * @brief 报警规则
  * 
@@ -442,6 +457,29 @@ public:
  };
 
 
+/**
+ * @brief 读取到的应用信息和启用时段
+ * 
+ */
+ struct AppAndTimeInfo
+ {
+    uint8_t AppType;                /* 应用信息,按位计算 */
+    int ChannelID;                  /* 通道ID */
+    QDateTime StartTime;    /* 开始时间 */
+    QDateTime EndTime;      /* 结束时间 */
+
+    AppAndTimeInfo() = default;
+    AppAndTimeInfo& operator=(AppAndTimeInfo& other) {
+        if (this != &other) {
+            AppType = other.AppType;
+            ChannelID = other.ChannelID;
+            StartTime = other.StartTime;
+            EndTime = other.EndTime;
+        }
+        return *this;
+    }
+ };
+
 /**
  * @brief 按照功能分类的线程信息,一个实例就是一个功能,
             比如区域入侵检测,需要多个算法多个摄像机共同配合
@@ -453,14 +491,16 @@ public:
     AppFunction appFunction;        /* 任务功能 */
     RunTimeState RunState;          /* 线程运行状态 */
     std::string strFunctionName;    /* 功能名称 */
-    std::chrono::system_clock::time_point StartTime;    /* 开始时间 */
-    std::chrono::system_clock::time_point EndTime;      /* 结束时间 */
+    QDateTime StartTime;            /* 开始时间 */
+    QDateTime EndTime;              /* 结束时间 */
     std::list<RoomCamActInfo> listRoomCamActInfo;       /* 房间内的摄像机和算法关联信息 */
 
     FuncActionInfo();
     FuncActionInfo& operator=(FuncActionInfo& other);
     /* 添加算法信息 */
     bool addActionInfo(const ActionInfo& info);
+    /* 清空算法信息 */
+    void clearActionList();
     
  };
 
@@ -473,7 +513,8 @@ public:
     ListFuncActInfo() = default;
 
     /* 添加功能信息 */
-    bool addFuncActionInfo(AppFunction func);
+    bool addFuncActionInfo(const AppAndTimeInfo& func);
+    // bool addFuncActionInfo(AppFunction& func);
     /* 添加算法信息 */
     bool addActionInfo(const ActionInfo& info);
     /* 清空无用的功能信息 */
@@ -488,6 +529,7 @@ public:
     /* 查找应用信息 */
     bool findAppFunction(const AppFunction func);
     FuncActionInfo* findAppFunction(const int ChannelID, const AppFunction func);
+    FuncActionInfo* findAppFunction(const FuncActionInfo& func);
 
     std::list<FuncActionInfo*> listFuncActionInfo;    /* 功能信息列表 */
  };

+ 221 - 216
SecurePlayAuxServer/SPAServer.cpp

@@ -762,94 +762,67 @@ void SPAServer::threadRoomCamera()
 {
     /* 房间相机关联信息 */
     std::list<RoomCameraInfo> listRC;
+    /* 存储获取到的应用和启用时间的信息 */
+    std::list<AppAndTimeInfo> listAppAndTime;
     /* 创建连接数据库实例 */
     std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
 
     while (m_threadRunning)
     {
+        m_mutexRunFAI.lock();
+        /* 先清理已经退出的线程所用到的Action或者RoomAction */
+        m_runListFuncActInfo.clearNoneFuncActionInfo();
+
+        /* 创建应用信息,根据从EQM数据库读取到的配置的应用信息创建 */
+        toEQMDataBase->getAlarmAppInfo(listAppAndTime);
+        for(const auto& it : listAppAndTime)
+        {
+            /* 创建应用信息,如果已有该应用,就更新时间 */
+            m_runListFuncActInfo.addFuncActionInfo(it);
+        }
+
         /* 先获取EQM数据库信息,取出房间和摄像机关联信息 */
         m_mutexActionInfo.lock();
         toEQMDataBase->getActionInfo(m_listActionInfo);
-        /* 取出每个房间的所有算法,int是RoomID,string是Action */
-        // std::multimap<int, std::string> mapCameraActionID;
-        m_mutexRunRAI.lock();
-        m_mutexRunAI.lock();
-        /* 先清理已经退出的线程所用到的Action或者RoomAction */
-        m_runListRoomActionInfo.clearStopRoomAction();
-        m_runListActionInfo.clearStopAction();
-
-        /* 将算法信息加入到不同的列表中
-         * 需要多个摄像机配合的加入到m_runListRoomActionInfo列表
-         * 不需要多个摄像机配合的加入到m_runListActionInfo列表
-         * */
-        m_runListRoomActionInfo.clearCameraList();
-        m_runListActionInfo.clearCameraList();
+        /* 将算法信息加入到不同的列表中 */
+        m_runListFuncActInfo.clearActionList();
         for(const auto& it : m_listActionInfo.getData())
         {
-            if(it->ActionID == ActPersonWork || it->ActionID == ActPersonNumber)
+            m_runListFuncActInfo.addActionInfo(*it);
+        }
+
+        /* 检查算法信息的状态,频率里的应用没有配置摄像机就设置为线程运行状态为停止,退出该线程 */
+        for(const auto& it : m_runListFuncActInfo.getData())
+        {
+            if(it->listRoomCamActInfo.size() == 0)
             {
-                m_runListRoomActionInfo.addActionInfo(*it);
-            }else {
-                m_runListActionInfo.addActionCamera(it);
+                it->RunState = RunTimeState::RUN_STATE_STOP;
             }
         }
         m_mutexActionInfo.unlock();
-        /* 这个容器只用于多个摄像机融合的算法,一个功能是一个线程 */
-        for(const auto& it0 : m_runListRoomActionInfo.getData())
+        /* 开启线程 */
+        for(const auto& it0 : m_runListFuncActInfo.getData())
         {
             /* 人员在岗识别 */
-            if(it0->ActionID == ActPersonWork)
-            {
-                SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 人员在岗识别", it0->RoomID);
-                /* 判断是否需要创建新的线程 */
-                if(it0->RunState == RunTimeState::RUN_STATE_INIT)
-                {
-                    /* 创建新的线程 */
-                    CPPTP.add_task(&SPAServer::threadActPersonWork, this, it0);
-                }
-            }
+
             /* 区域人员检测 */
-            else if (it0->ActionID == ActPersonNumber)
-            {
-                SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 区域人员检测", it0->RoomID);
-                if(it0->RunState == RunTimeState::RUN_STATE_INIT)
-                {
-                    CPPTP.add_task(&SPAServer::threadActRegionalPersonnelDetection, this, it0);
-                }
-            }
-            /* 非法入侵 */
-            else if( it0->ActionID == ActIllegalInvasion)
-            {
 
-            }
-        }
-        /* 这个容器用于不关联的算法信息,每个设备上的每个算法是一个线程
-         * ActionInfo.RunState = RUN_STATE_INIT ,就是新增的算法,需要创建新的线程 */
-        for(const auto& it0 : m_runListActionInfo.getData())
-        {
-            /* 违禁物品识别,不需要多个摄像机融合判断,多少个报警都直接上报 */
-            if (it0->ActionID == ActContraband)
+            /* 非法入侵检测 */
+
+            /* 违禁品识别 */
+            
+            /* 普通任务线程,一个任务对应一个摄像机和一个算法ID,无需联动 */
+            if(it0->appFunction == AppFunction::APP_ALLDOWN)
             {
-                SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 违禁品检测", it0->RoomID);
-                it0->strActionName = "违禁品检测";
                 if(it0->RunState == RunTimeState::RUN_STATE_INIT)
                 {
                     CPPTP.add_task(&SPAServer::threadActNormal, this, it0);
                 }
             }
-            /* 非法入侵检测,这个也不需要摄像机融合 */
-            else if (it0->ActionID == ActIllegalInvasion)
-            {
-                SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 非法入侵检测", it0->RoomID);
-            }
-            /* 疲劳检测,不需要摄像机融合检测,直接上报 */
-            else if (it0->ActionID == ActFatigueDetection)
-            {
-                SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 疲劳检测", it0->RoomID);
-            }
         }
-        m_mutexRunRAI.unlock();
-        m_mutexRunAI.unlock();
+        
+
+        m_mutexRunFAI.unlock();
 
         /* 休眠n秒,默认应该是300秒 */
         std::this_thread::sleep_for(std::chrono::seconds(g_config.CheckSet));
@@ -857,93 +830,6 @@ void SPAServer::threadRoomCamera()
 }
 
 
-/* 将该算法对应的摄像机放入摄像机列表 */
-bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID)
-{
-    for(const auto& rci : listRC)
-    {
-        if(rci.RoomID == pRAInfo->RoomID)
-        {
-            /* 这个摄像机在这个房间内,再判断这个摄像机有没有这个算法 */
-            for(const auto& camID : rci.listCameraID)
-            {
-                for(const auto& cai : mapCameraActionID)
-                {
-                    if(camID == cai.first)
-                    {
-                        /* 再判断这个摄像机的算法是否是当前需要的 */
-                        if(cai.second == pRAInfo->ActionID)
-                        {
-                            pRAInfo->listCameraID.push_back(camID);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return true;
-}
-
-/* 更新房间、算法需要的摄像机个数,从内存中更新 */
-bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunRAI);
-    for(auto& it : m_runListRoomActionInfo.getData())
-    {
-        if((it->RoomID == pRAInfo->RoomID) && (it->ActionID == pRAInfo->ActionID))
-        {
-            it->listCameraID = pRAInfo->listCameraID;
-            break;
-        }
-    }
-
-    return true;
-}
-
-/* 更新算法的摄像机ID,这里是从内存中的数组里获取 */
-bool SPAServer::updateActionCameraID(std::shared_ptr<FuncActionInfo> pInfo)
-{
-    pInfo->listRoomCamActInfo = -1;
-    std::lock_guard<std::mutex> look(m_mutexRunAI);
-    for(auto& it : m_runListActionInfo.getData())
-    {
-        if(it->isEqualBaseInfo(*pInfo))
-        {
-            pInfo->CameraID = it->CameraID;
-            break;
-        }
-    }
-    return true;
-}
-
-/* 设置线程状态 */
-void SPAServer::setThreadState(std::shared_ptr<ActionInfo> pInfo, RunTimeState state)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunAI);
-    for(auto& it : m_runListActionInfo.getData())
-    {
-        if(it->isEqualBaseInfo(*pInfo))
-        {
-            it->RunState = state;
-            break;
-        }
-    }
-}
-
-/* 设置线程状态 */
-void SPAServer::setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state)
-{
-    std::lock_guard<std::mutex> look(m_mutexRunRAI);
-    for(auto& it : m_runListRoomActionInfo.getData())
-    {
-        if(it->isEqualBaseInfo(*pInfo))
-        {
-            it->RunState = state;
-            break;
-        }
-    }
-}
-
 
 
 /**
@@ -1069,7 +955,7 @@ void SPAServer::threadActRegionalPersonnelDetection(RoomActionInfo* RAInfo)
  */
 void SPAServer::threadActNormal(FuncActionInfo* info)
 {
-    SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程, ChannelID:{} ,Action:{}",info->strFunctionName, info->ChannelID, info->listRoomCamActInfo.front().mapCameraAction.begin()->second);
+    SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程, ChannelID:{} ,App:{}",info->strFunctionName, info->ChannelID, info->strFunctionName);
     /* 创建读取Redis的实例 */
     std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
     /* 创建写入EQM数据库实例 */
@@ -1078,93 +964,119 @@ void SPAServer::threadActNormal(FuncActionInfo* info)
     std::shared_ptr<FuncActionInfo> pFuncAct = std::make_shared<FuncActionInfo>();
     *pFuncAct = *info;
     /* 保存报警数据 */
-    std::shared_ptr<AlarmInfo> pAlarmInfo = std::make_shared<AlarmInfo>();
+    std::shared_ptr<ListAlarmInfo> listAlarmInfo = std::make_shared<ListAlarmInfo>();
 
     while (m_threadRunning)
     {
         /* 更新算法关联的摄像机ID */
-        updateActionCameraID(pFuncAct);
-        /* 如果摄像机ID是小于0,那么这个算法就没有对应的摄像机了,线程就退出了 */
-        if(pActInfo->CameraID < 0)
+        updateFuncInfo(pFuncAct);
+        /* 如果线程的运行状态为 */
+        if(pFuncAct->RunState == RunTimeState::RUN_STATE_STOP)
         {
+            pFuncAct->appFunction = AppFunction::APP_NONE;
             break;
         }
-        /* 读取Redis数据 */
-        std::string strKey = std::to_string(pActInfo->CameraID) + ":" + pActInfo->ActionID;
-        std::string strRetValue;
-        if(!fromRedis->getRedisString(strKey, strRetValue))
-        {
-            SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
-            std::this_thread::sleep_for(std::chrono::milliseconds(100));
-            continue;
-        }
-        /* 解析数据 */
-        AlarmInfo alarmInfo;
-        parseRedisBaseData(strRetValue, alarmInfo);
-        parseRedisBBoxesData(strRetValue, alarmInfo);
-        /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
-        if(isEventTimeVaild(alarmInfo.EventTime))
-        {
-            SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
-            std::this_thread::sleep_for(std::chrono::milliseconds(100));
-            continue;
-        }
-        /* 判断有无报警记录,新的报警就写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,
-         * 结束报警就更新tAlarmInfo的报警数据的结束时间,并清空pAlarmInfo */
-        if(pAlarmInfo->Is_Alarm)
+        /* 读取Redis信息,处理数据 */
+        for(const auto& roomInfo : pFuncAct->listRoomCamActInfo)
         {
-            /* 正在报警中,检查是否报警结束 */
-            if(alarmInfo.Is_Alarm)
+            for(const auto& it : roomInfo.mapCameraAction)
             {
-                /* 更新图片信息 */
-                if(!alarmInfo.ImageInfo.empty())
+                /* 读取Redis数据 */
+                std::string strKey = std::to_string(it.first) + ":" + it.second;
+                std::string strRetValue;
+                if(!fromRedis->getRedisString(strKey, strRetValue))
                 {
-                    pAlarmInfo->ImageInfo = alarmInfo.ImageInfo;
+                    SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                    continue;
                 }
-            } else {
-                /* 报警结束,判断时长,更新数据库结束时间,结束时间是此时电脑时间 */
-                if(timeDiffWithNow(pAlarmInfo->EventTime) > g_config.Contraband)
+                /* 解析数据 */
+                AlarmInfo alarmInfo;
+                parseRedisBaseData(strRetValue, alarmInfo);
+                parseRedisBBoxesData(strRetValue, alarmInfo);
+                /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+                if(isEventTimeVaild(alarmInfo.EventTime))
                 {
-                    pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
-                    toEQMDataBase->updateAlarmEndTime(*pAlarmInfo);
-                }else {
-                    /* 不够报警时间,目前不做任何处理,不删除EQM报警记录 */
+                    SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                    continue;
                 }
+                /* 找出数组中与当前报警ID相同的的报警信息 */
+                auto pAlarmInfo = listAlarmInfo->findAlarmInfo(alarmInfo);
+                if(pAlarmInfo == nullptr)
+                {
+                    /* 没有找到报警记录,就新建一个 */
+                    AlarmInfo newAlarmInfo = alarmInfo;
+                    listAlarmInfo->addAlarmInfo(newAlarmInfo);
+                    /* 重新查找该报警信息 */
+                    pAlarmInfo = listAlarmInfo->findAlarmInfo(alarmInfo);
+                    if(pAlarmInfo == nullptr)
+                    {
+                        SPDLOG_LOGGER_ERROR(m_logger, "查找报警信息失败, Key:{}", strKey);
+                        continue;
+                    }
+                }
+                /* 判断有无报警记录,新的报警就写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,
+                * 结束报警就更新tAlarmInfo的报警数据的结束时间,并清空pAlarmInfo */
+                if(pAlarmInfo->Is_Alarm)
+                {
+                    /* 正在报警中,检查是否报警结束 */
+                    if(alarmInfo.Is_Alarm)
+                    {
+                        /* 更新图片信息 */
+                        if(!alarmInfo.ImageInfo.empty())
+                        {
+                            pAlarmInfo->ImageInfo = alarmInfo.ImageInfo;
+                        }
+                    } else {
+                        /* 报警结束,判断时长,更新数据库结束时间,结束时间是此时电脑时间 */
+                        if(timeDiffWithNow(pAlarmInfo->EventTime) > g_config.Contraband)
+                        {
+                            pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
+                            toEQMDataBase->updateAlarmEndTime(*pAlarmInfo);
+                        }else {
+                            /* 不够报警时间,目前不做任何处理,不删除EQM报警记录 */
+                        }
 
-                /* 清空报警信息 */
-                pAlarmInfo->reInit();
-            }
-        }
-        else
-        {
-            /* 是新的报警 */
-            if(alarmInfo.Is_Alarm)
-            {
-                /* 布片不能是空,如果是空的,就不写入数据库 */
-                if(!alarmInfo.ImageInfo.empty())
+                        /* 清空报警信息 */
+                        pAlarmInfo->reInit();
+                    }
+                }
+                else
                 {
-                    /* 违禁品检测,开始时间是事件时间 */
-                    alarmInfo.StartTime = alarmInfo.EventTime;
-                    alarmInfo.EndTime = "";
-                    if(toEQMDataBase->insertAlarmInfo(alarmInfo))
+                    /* 是新的报警 */
+                    if(alarmInfo.Is_Alarm)
                     {
-                        /* 保存新的报警记录 */
-                        *pAlarmInfo = alarmInfo;
-                    }else {
-                        SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, Key: {}", strKey);
+                        /* 图片不能是空,如果是空的,就不写入数据库 */
+                        if(!alarmInfo.ImageInfo.empty())
+                        {
+                            /* 违禁品检测,开始时间是事件时间 */
+                            alarmInfo.StartTime = alarmInfo.EventTime;
+                            alarmInfo.EndTime = "";
+                            if(toEQMDataBase->insertAlarmInfo(alarmInfo))
+                            {
+                                /* 保存新的报警记录 */
+                                *pAlarmInfo = alarmInfo;
+                            }else {
+                                SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, Key: {}", strKey);
+                            }
+                        }else {
+                            SPDLOG_LOGGER_ERROR(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", pFuncAct->ChannelID, roomInfo.RoomID, it.first, it.second);
+                        }
                     }
-                }else {
-                    SPDLOG_LOGGER_ERROR(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", pActInfo->ChannelID, pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
                 }
+
             }
         }
-
+        
+        
+        
         /* 休眠设置的时间 */
         std::this_thread::sleep_for(std::chrono::seconds(g_config.ThreadSleepMS));
     }
     /* 设置线程退出的状态 */
-    setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
-    SPDLOG_LOGGER_INFO(m_logger, "{} 线程退出,RoomID:{} ,CameraID, Action:{}",pActInfo->strActionName, pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
+    setThreadState(pFuncAct, RunTimeState::RUN_STATE_STOP);
+    SPDLOG_LOGGER_INFO(m_logger, "{} 线程退出,Channel:{}",pFuncAct->strFunctionName, pFuncAct->ChannelID);
 }
 
 /**
@@ -1188,7 +1100,7 @@ void SPAServer::threadActIllegalInvasion(ActionInfo* info)
     while (m_threadRunning)
     {
         /* 更新算法关联的摄像机ID */
-        updateActionCameraID(pActInfo);
+        // updateActionCameraID(pActInfo);
         /* 如果摄像机ID是小于0,那么这个算法就没有对应的摄像机了,线程就退出了 */
         if(pActInfo->CameraID < 0)
         {
@@ -1214,10 +1126,103 @@ void SPAServer::threadActIllegalInvasion(ActionInfo* info)
         /* 判断有无报警记录,写入到EQM数据库 */
     }
     /* 设置线程退出的状态 */
-    setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
+    // setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
     SPDLOG_LOGGER_INFO(m_logger, "非法入侵检测线程退出,RoomID:{} ,CameraID:{}, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
 }
 
+
+
+/* 将该算法对应的摄像机放入摄像机列表 */
+bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID)
+{
+    for(const auto& rci : listRC)
+    {
+        if(rci.RoomID == pRAInfo->RoomID)
+        {
+            /* 这个摄像机在这个房间内,再判断这个摄像机有没有这个算法 */
+            for(const auto& camID : rci.listCameraID)
+            {
+                for(const auto& cai : mapCameraActionID)
+                {
+                    if(camID == cai.first)
+                    {
+                        /* 再判断这个摄像机的算法是否是当前需要的 */
+                        if(cai.second == pRAInfo->ActionID)
+                        {
+                            pRAInfo->listCameraID.push_back(camID);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+
+/* 更新房间、算法需要的摄像机个数,从内存中更新 */
+bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunRAI);
+    for(auto& it : m_runListRoomActionInfo.getData())
+    {
+        if((it->RoomID == pRAInfo->RoomID) && (it->ActionID == pRAInfo->ActionID))
+        {
+            it->listCameraID = pRAInfo->listCameraID;
+            break;
+        }
+    }
+
+    return true;
+}
+
+/**
+ * @brief 功能线程更新功能信息,这里是从内存中的数组里获取
+ * 
+ * @param pInfo 
+ * @return true 
+ * @return false 
+ */
+ bool SPAServer::updateFuncInfo(std::shared_ptr<FuncActionInfo> pInfo)
+{
+    pInfo->clearActionList();
+    std::lock_guard<std::mutex> look(m_mutexRunAI);
+    auto fa = m_runListFuncActInfo.findAppFunction(*pInfo);
+    if(fa == nullptr)
+    {
+        return false;
+    }
+    *pInfo = *fa;
+
+    return true;
+}
+
+/* 设置线程状态 */
+void SPAServer::setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunAI);
+    auto p = m_runListFuncActInfo.findAppFunction(*pInfo);
+    if(p != nullptr)
+    {
+        p->RunState = state;
+    }
+}
+
+/* 设置线程状态 */
+void SPAServer::setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunRAI);
+    for(auto& it : m_runListRoomActionInfo.getData())
+    {
+        if(it->isEqualBaseInfo(*pInfo))
+        {
+            it->RunState = state;
+            break;
+        }
+    }
+}
+
+
+
 /* 计算与当前时间的时间差,返回秒 */
 int SPAServer::timeDiffWithNow(const std::string& strTime)
 {

+ 13 - 9
SecurePlayAuxServer/SPAServer.h

@@ -45,15 +45,6 @@ private:
 
     /* 分派任务的线程 */
     void threadRoomCamera();
-    /* 将该算法对应的摄像机放入摄像机列表 */
-    bool insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID);
-    /* 更新房间、算法需要的摄像机个数 */
-    bool updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo);
-    /* 更新算法的摄像机ID */
-    bool updateActionCameraID(std::shared_ptr<FuncActionInfo> pInfo);
-    /* 设置线程状态 */
-    void setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state);
-    void setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state);
     
     /* 人员在岗识别线程,应该是人脸识别线程,这个需要房间内多个摄像机共同识别 */
     void threadActPersonWork(RoomActionInfo* RAInfo);
@@ -65,6 +56,16 @@ private:
     void threadActIllegalInvasion(ActionInfo* info);
     /* 人员计数 */
 
+    /* 将该算法对应的摄像机放入摄像机列表 */
+    bool insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID);
+    /* 更新房间、算法需要的摄像机个数 */
+    bool updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo);
+    /* 更新算法的摄像机ID */
+    bool updateFuncInfo(std::shared_ptr<FuncActionInfo> pInfo);
+    /* 设置线程状态 */
+    void setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state);
+    void setThreadState(std::shared_ptr<RoomActionInfo> pInfo, RunTimeState state);
+
 
     /* 计算与当前时间的时间差,返回秒 */
     int timeDiffWithNow(const std::string& strTime);
@@ -109,6 +110,9 @@ private:
     /* 运行时的算法信息列表,这个容器存储的是不需要摄像机融合的算法 */
     std::mutex m_mutexRunAI;
     ListActionInfo m_runListActionInfo;
+    /* 运行时应用线程功能相关信息 */
+    std::mutex m_mutexRunFAI;
+    ListFuncActInfo m_runListFuncActInfo;
 
 };
 

+ 54 - 1
SecurePlayAuxServer/communication/ToEQMDataBase.cpp

@@ -3,7 +3,7 @@
 #include <QJsonDocument>
 #include <QJsonObject>
 #include <QVector>
-
+#include <QString>
 
 ToEQMDataBase::ToEQMDataBase()
 {
@@ -932,3 +932,56 @@ bool ToEQMDataBase::getAlarmRuleInfo(std::vector<AlarmRuleInfo>& vecInfo)
     return true;
 }
 
+/* 获取报警时段,也同时获取报警的应用信息 */
+bool ToEQMDataBase::getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo)
+{
+    nJson json0;
+    json0["opName"] = "SPSS_SelectPeriod";
+    QString strCmd = QString::fromStdString(json0.dump());
+    QString strRet;
+    auto ret = m_httpApi->DBQDoInterface(enDBOperatorType::EDBOT_Select, strCmd, strRet);
+    if(ret < 0)
+    {
+        SPDLOG_LOGGER_DEBUG(m_logger,"获取AlarmApp失败:{}, 错误信息:{}",ret,m_httpApi->DoGetLastError(&ret).toStdString());
+        return false;
+    }
+    try 
+    {
+        nJson json1 = nJson::parse(strRet.toStdString());
+        int retCode = json1["code"].get<int>();
+        if(retCode != 0)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger,"获取tAlarmApp失败");
+            return false;
+        }
+        nJson result = json1["result"];
+        if(result.empty())
+        {
+            return false;
+        }
+        listInfo.clear();
+        for(const auto& it : result)
+        {
+            AppAndTimeInfo info;
+            info.ChannelID = it["chnId"].get<int>();
+            info.AppType = it["appType"].get<int>();
+            QString strStart = QString::fromStdString(it["startTime"].get<std::string>());
+            QString strEnd = QString::fromStdString(it["endTime"].get<std::string>());
+            info.StartTime = QDateTime::fromString(strStart, "yyyy-MM-ss hh:mm:ss");
+            info.EndTime = QDateTime::fromString(strEnd, "yyyy-MM-ss hh:mm:ss");
+            listInfo.push_back(info);
+        }
+    } 
+    catch (const nJson::parse_error& e) {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析AlarmApp数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+    catch(const nJson::type_error& e)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger,"解析AlarmApp数据失败:{}, 错误ID:{}",e.what(), e.id);
+        return false;
+    }
+
+    return true;
+}
+

+ 2 - 0
SecurePlayAuxServer/communication/ToEQMDataBase.h

@@ -52,6 +52,8 @@ public:
 
     /* 获取报警规则表 */
     bool getAlarmRuleInfo(std::vector<AlarmRuleInfo>& vecInfo);
+    /* 获取报警时段,也同时获取报警的应用信息 */
+    bool getAlarmAppInfo(std::list<AppAndTimeInfo>& listInfo);
     
 
 private:

+ 12 - 0
安播辅助服务程序说明.md

@@ -123,6 +123,18 @@
 4. `tFaceUser`用户信息表,读取到超脑返回的用户数据,写入该表
 5. `tRuleInfo`报警规则表,区域人员检测(人员计数)会使用到
 6. `tWorkOnInfo`人员在岗信息表,主要给客户端同步用的
+7. `tPeriod` 报警时段和频道与App对应表
+    |标号|App|
+    |:--|:--|
+    |0x01|人员在岗识别|
+    |0x02|违禁物品识别|
+    |0x04|区域非法入侵识别|
+    |0x08|疲劳检测识别|
+    |0x10|区域人员统计|
+    |0x20|老鼠识别|
+    |0x40|玩手机识别|
+    |0x80|未戴口罩识别|
+    |0x0100|摔倒识别|
 
 ## 启动程序,可能需要从EQM获取的数据
 1. `tCamerinfo`获取摄像机信息