#include "DownloadTimetable.h" #include "pub_logger_api/logger.h" #include "pub_utility_api/I18N.h" #include "pub_utility_api/TimeUtil.h" #include "pub_utility_api/CharUtil.h" #include "common/MessageChannel.h" #include "ParamMng.h" using namespace std; using namespace iot_public; using namespace kbd_app; // using namespace iot_net; // using namespace iot_dbms; kbd_app::CDownloadTimetable::CDownloadTimetable(const iot_public::SRunAppInfo &stRunAppInfo, const CParamMngPtr &ptrParamMng, const CTimetableMsgBusMngPtr &ptrMsgMng, const CBasicOperationPtr &ptrBasicOpt) :m_stRunAppInfo(stRunAppInfo), m_ptrParamMng(ptrParamMng), m_ptrMsgMng(ptrMsgMng), m_ptrBasicOpt(ptrBasicOpt) { } kbd_app::CDownloadTimetable::~CDownloadTimetable() { m_ptrBasicOpt.reset(); m_ptrMsgMng.reset(); m_ptrParamMng.reset(); } /* @brief 处理下载命令 */ void kbd_app::CDownloadTimetable::handleDownloadCmd(STimetableCmd &stCmd) { ETimetableCmdState eTemp = ETimetableCmdState_Invalid; while (eTemp != stCmd.eState) { eTemp = stCmd.eState; switch (stCmd.eState) { case ETimetableCmdState_Start: case ETimetableCmdState_CheckFlag: //< 检查时间表控制相关标识 checkFlag(stCmd, ETimetableCmdState_WaitSync, ETimetableCmdState_Complete); break; case ETimetableCmdState_WaitSync: //< 等待在线修改的内容已经同步到内存表中 waitSyncTimetableInfo(stCmd, ETimetableCmdState_SendCustomCmdMsg, ETimetableCmdState_Complete); break; case ETimetableCmdState_SendCustomCmdMsg: sendDownloadCmd(stCmd, ETimetableCmdState_WaitCustomRep, ETimetableCmdState_Complete); break; case ETimetableCmdState_WaitCustomRep: waitDownloadResponse(stCmd, ETimetableCmdState_SetDCFFlag, ETimetableCmdState_Complete); break; case ETimetableCmdState_SetDCFFlag: //< 设置下载相关标志位 setDownloadFlag(stCmd, ETimetableCmdState_VerifyVesion, ETimetableCmdState_Complete); break; // case ETimetableCmdState_WaitDCFRep: // waitDownloadFlagRep(stCmd, ETimetableCmdState_VerifyVesion, ETimetableCmdState_Complete); // break; case ETimetableCmdState_VerifyVesion: verifyVersion(stCmd, ETimetableCmdState_Complete, ETimetableCmdState_Complete); break; case ETimetableCmdState_Complete: downloadCompleted(stCmd); break; default: break; } } } /* @brief 检查DCF、URF、RRF标识 */ void kbd_app::CDownloadTimetable::checkFlag(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { string strErrMsg; if (kbdSuccess == m_ptrBasicOpt->checkFlag(stCmd, strErrMsg)) { stCmd.setResult(true, strErrMsg, eSuccessState); } else { stCmd.setResult(false, strErrMsg, eFailState); } } /* @brief 等待关系库中的配置同步到内存库 */ void kbd_app::CDownloadTimetable::waitSyncTimetableInfo(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { /* @brief 仅手动下载命令需要检查时间表是否已经更新到内存表中 */ if (stCmd.eCmdType != ETimetableCmdType_ManualDownload) { stCmd.setResult(true, "", eSuccessState); return; } int64 lCurTimeMsec = getUTCTimeMsec(); if (lCurTimeMsec - stCmd.lCmdBeginTimeMsec > stCmd.nTimeoutMsec) { LOGERROR("等待时间表同步超时.LocationId=[%d],TimetableId=[%d]", stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(false, I18N("时间表下载命令执行超时"), eFailState); return; } int nTimetableVersion = m_ptrBasicOpt->getTimetableVersion(stCmd.nLocationId, stCmd.nTimetableId); if (nTimetableVersion != CN_InvalidTimetableVersion && nTimetableVersion == stCmd.nTimetableVersion) { LOGINFO("等待在线修改时间表信息成功"); stCmd.setResult(true, "", eSuccessState); return; } } /* @brief 发送下载命令消息 */ void kbd_app::CDownloadTimetable::sendDownloadCmd(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { stCmd.lCurCmdTimeMsec = getUTCTimeMsec(); string strMsg; if (!makeDownloadMsg(stCmd, strMsg)) { stCmd.setResult(false, I18N("生成控制命令失败"), eFailState); return; } if (m_ptrMsgMng->sendMsgToMsgBus(strMsg, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_COMMON_DOWN, CN_InvalidDomainId, m_stRunAppInfo.strLocalNodeName)) { stCmd.setResult(true, I18N("发送时间表下载命令成功"), eSuccessState); LOGINFO("发送下载命令成功.AppId=[%d],CH=[%d],MT=[%d],CmdType=[%d],LocationId=[%d],TimetableId=[%d]", m_stRunAppInfo.nAppId, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_COMMON_DOWN, stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId); } else { stCmd.setResult(false, I18N("发送时间表下载命令失败"), eFailState); LOGERROR("发送下载命令失败.AppId=[%d],CH=[%d],MT=[%d],CmdType=[%d],LocationId=[%d],TimetableId=[%d]", m_stRunAppInfo.nAppId, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_COMMON_DOWN, stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId); } } /* @brief 生成下载命令报文 */ bool kbd_app::CDownloadTimetable::makeDownloadMsg(const STimetableCmd &stCmd, std::string &strMsg) { vector vecInfo; if (kbdSuccess != m_ptrBasicOpt->getTimetableDetail(stCmd.nLocationId, stCmd.nTimetableId, vecInfo) || vecInfo.empty()) { LOGERROR("获取时间表信息失败.LocationId=[%d],TimetableId=[%d]", stCmd.nLocationId, stCmd.nTimetableId); return false; } STableCtrlParam stCtrlParam; if (!m_ptrParamMng->getCtrlParamByLocationId(stCmd.nLocationId, stCtrlParam)) { LOGERROR("获取控制参数信息失败。LocationId=[%d]", stCmd.nLocationId); return false; //< 命令填充到缓冲区时已经进行了判断,必然存在此车站的配置,所以正常不会进入此分支 } SOptCustCtrlRequest stCustomCmd; stCustomCmd.stHead.strSrcTag = CN_ProcName_TimetableServer; stCustomCmd.stHead.nSrcDomainID = m_stRunAppInfo.nDomainId; stCustomCmd.stHead.nDstDomainID = m_stRunAppInfo.nDomainId; stCustomCmd.stHead.nAppID = m_stRunAppInfo.nAppId; stCustomCmd.stHead.strHostName = m_stRunAppInfo.strLocalNodeName; stCustomCmd.stHead.strInstName = CN_ProcName_TimetableServer; stCustomCmd.stHead.strCommName = m_ptrMsgMng->getCommunicatorName(); stCustomCmd.stHead.nUserID = stCmd.nUserId; stCustomCmd.stHead.nUserGroupID = stCmd.nUserGrpId; stCustomCmd.stHead.nOptTime = stCmd.lCurCmdTimeMsec; stCustomCmd.strKeyIdTag = stCtrlParam.szCtrlKeyIdTag; SOptCustCtrlQueue stKV; stKV.strKeyName = KEY_CMD_TYPE; stKV.strKeyValue = CMD_TYPE_DOWNLOAD; stCustomCmd.vecOptCustCtrlQueue.push_back(stKV); stKV.strKeyName = KEY_TIMETABLE_ID; stKV.strKeyValue = IntToString(stCmd.nTimetableId); stCustomCmd.vecOptCustCtrlQueue.push_back(stKV); stKV.strKeyName = KEY_TIMETABLE_VERSION; stKV.strKeyValue = IntToString(stCmd.nTimetableVersion); stCustomCmd.vecOptCustCtrlQueue.push_back(stKV); for (size_t i = 0; i < vecInfo.size(); ++i) { STableTimetableInfo &stInfo = vecInfo[i]; stKV.strKeyName = KEY_MODE_BEGIN_TIME; stKV.strKeyValue = stInfo.stKey.szBeginTime; stCustomCmd.vecOptCustCtrlQueue.push_back(stKV); STableModeDef stModeInfo; if (kbdSuccess != m_ptrBasicOpt->getModeInfo(stInfo.stKey.nLocationId, stInfo.nCraftId, stInfo.nModeId, stModeInfo)) { LOGERROR("获取模式号失败.LocationId=[%d],CraftId=[%d],ModeId=[%d]", stInfo.stKey.nLocationId, stInfo.nCraftId, stInfo.nModeId); return false; } stKV.strKeyName = KEY_MODE_NO; stKV.strKeyValue = IntToString(stModeInfo.stKey.nModeNo); stCustomCmd.vecOptCustCtrlQueue.push_back(stKV); } COptCustCtrlRequest objReq; strMsg = objReq.generate(stCustomCmd); if (strMsg.empty()) { LOGERROR("生成控制命令失败"); return false; } return true; } /* @brief 检查下载命令反馈结果 */ void kbd_app::CDownloadTimetable::waitDownloadResponse(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { int64 lCurTimeMsec = getUTCTimeMsec(); if (lCurTimeMsec - stCmd.lCmdBeginTimeMsec > stCmd.nTimeoutMsec) { LOGERROR("时间表下载命令[%d]执行超时.LocationId=[%d],TimetableId=[%d]", stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(false, I18N("时间表下载命令执行超时"), eFailState); return; } STableCtrlParam stCtrlParam; if (!m_ptrParamMng->getCtrlParamByLocationId(stCmd.nLocationId, stCtrlParam)) { LOGERROR("获取控制参数信息失败。LocationId=[%d]", stCmd.nLocationId); stCmd.setResult(false, I18N("获取控制参数信息失败"), eFailState); return; //< 命令填充到缓冲区时已经进行了判断,必然存在此车站的配置,所以正常不会进入此分支 } //检查反馈,是否执行成功 string strKeyIdTag = stCtrlParam.szCtrlKeyIdTag; //< 开始已经判断,本车站参数配置必然存在 STimetableCmdKey stKey(strKeyIdTag, stCmd.lCurCmdTimeMsec); SOptCustCtrlReply stRep; if (m_ptrParamMng->getCustomRepMsgByKey(stKey, stRep)) { if (stRep.stHead.nIsSuccess == 1) { LOGINFO("接收到下载命令[%d]执行成功反馈.LocationId=[%d],TimetableId=[%d]", stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(true, "", eSuccessState); } else { LOGERROR("接收到下载命令[%d]执行失败反馈.LocationId=[%d],TimetableId=[%d],Error=[%s]", stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId, stRep.stHead.strResultStr.c_str()); stCmd.setResult(false, stRep.stHead.strResultStr, eFailState); } } } /* @brief 设置下载完成标识DCF */ void kbd_app::CDownloadTimetable::setDownloadFlag(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { stCmd.lCurCmdTimeMsec = getUTCTimeMsec(); STableCtrlParam stCtrlParam; if (!m_ptrParamMng->getCtrlParamByLocationId(stCmd.nLocationId, stCtrlParam)) { LOGERROR("获取控制参数信息失败。LocationId=[%d]", stCmd.nLocationId); stCmd.setResult(false, I18N("获取控制参数信息失败"), eFailState); return; //< 命令填充到缓冲区时已经进行了判断,必然存在此车站的配置,所以正常不会进入此分支 } SOptCtrlRequest stReq; stReq.stHead.strSrcTag = CN_ProcName_TimetableServer; stReq.stHead.nSrcDomainID = m_stRunAppInfo.nDomainId; stReq.stHead.nDstDomainID = m_stRunAppInfo.nDomainId; stReq.stHead.nAppID = m_stRunAppInfo.nAppId; stReq.stHead.strHostName = m_stRunAppInfo.strLocalNodeName; stReq.stHead.strInstName = CN_ProcName_TimetableServer; stReq.stHead.strCommName = m_ptrMsgMng->getCommunicatorName(); stReq.stHead.nUserID = stCmd.nUserId; stReq.stHead.nUserGroupID = stCmd.nUserGrpId; stReq.stHead.nOptTime = stCmd.lCurCmdTimeMsec; SOptCtrlReqQueue stCtrlReq; stCtrlReq.strKeyIdTag = stCtrlParam.szDCFTag; stCtrlReq.dTargetValue = 1; stCtrlReq.bIsDeviceOccupy = true; stReq.vecOptCtrlQueue.push_back(stCtrlReq); COptCtrlRequest objGen; string strMsg = objGen.generate(stReq); if (strMsg.empty()) { LOGERROR("生成控制报文失败。KeyIdTag=[%s]", stCtrlReq.strKeyIdTag.c_str()); stCmd.setResult(false, I18N("生成控制报文失败"), eFailState); return; } if (m_ptrMsgMng->sendMsgToMsgBus(strMsg, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_AUTO_CTRL_DOWN, CN_InvalidDomainId, m_stRunAppInfo.strLocalNodeName)) { stCmd.setResult(true, I18N("发送时间表下载标志置位命令成功"), eSuccessState); LOGINFO("发送时间表下载标志置位命令成功.AppId=[%d],CH=[%d],MT=[%d],CmdType=[%d],LocationId=[%d],TimetableId=[%d],KeyIdTag=[%s]", m_stRunAppInfo.nAppId, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_AUTO_CTRL_DOWN, stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId, stCtrlReq.strKeyIdTag.c_str()); } else { stCmd.setResult(false, I18N("发送时间表下载标志置位命令失败"), eFailState); LOGERROR("发送时间表下载标志置位命令失败.AppId=[%d],CH=[%d],MT=[%d],CmdType=[%d],LocationId=[%d],TimetableId=[%d],KeyIdTag=[%s]", m_stRunAppInfo.nAppId, CH_HMI_TO_OPT_OPTCMD_DOWN, MT_OPT_AUTO_CTRL_DOWN, stCmd.eCmdType, stCmd.nLocationId, stCmd.nTimetableId, stCtrlReq.strKeyIdTag.c_str()); } } /* @brief 等待设置下载完成标识DCF的命令反馈 */ void kbd_app::CDownloadTimetable::waitDownloadFlagRep(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { int64 lCurTimeMsec = getUTCTimeMsec(); if (lCurTimeMsec - stCmd.lCmdBeginTimeMsec > stCmd.nTimeoutMsec) { LOGERROR("时间表下载标志置位命令控制超时.LocationId=[%d],TimetableId=[%d]", stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(false, I18N("时间表下载标志置位命令控制超时"), eFailState); return; } STableCtrlParam stCtrlParam; if (!m_ptrParamMng->getCtrlParamByLocationId(stCmd.nLocationId, stCtrlParam)) { LOGERROR("获取控制参数信息失败。LocationId=[%d]", stCmd.nLocationId); stCmd.setResult(false, I18N("获取控制参数信息失败"), eFailState); return; //< 命令填充到缓冲区时已经进行了判断,必然存在此车站的配置,所以正常不会进入此分支 } //检查反馈,是否执行成功 STimetableCmdKey stKey(stCtrlParam.szDCFTag, stCmd.lCurCmdTimeMsec); SOptCtrlReply stRep; if (m_ptrParamMng->getPntRepMsgByKey(stKey, stRep)) { if (stRep.stHead.nIsSuccess == 1) { LOGINFO("接收到下载标志置位命令成功反馈.LocationId=[%d],TimetableId=[%d]", stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(true, "", eSuccessState); } else { LOGERROR("接收到下载标志置位命令失败反馈.LocationId=[%d],TimetableId=[%d],Error=[%s]", stCmd.nLocationId, stCmd.nTimetableId, stRep.stHead.strResultStr.c_str()); stCmd.setResult(false, I18N("时间表下载标志置位失败"), eFailState); } } } void kbd_app::CDownloadTimetable::verifyVersion(STimetableCmd &stCmd, const ETimetableCmdState eSuccessState, const ETimetableCmdState eFailState) { int64 lCurTimeMsec = getUTCTimeMsec(); if (lCurTimeMsec - stCmd.lCmdBeginTimeMsec > stCmd.nTimeoutMsec) { LOGERROR("等待时间表最新的时间表ID和Version超时.预期:LocationId=[%d],TimetableId=[%d],TimetableVersion=[%d]", stCmd.nLocationId, stCmd.nTimetableId, stCmd.nTimetableVersion); stCmd.setResult(false, I18N("时间表下载校验超时"), eFailState); return; } //检查正在运行的时间表ID和版本号,是否跟下载的一致 int nTimetableId = CN_InvalidTimetableId; int nTimetableVersion = CN_InvalidTimetableVersion; if (!m_ptrBasicOpt->getRunTimetableIdAndVersion(stCmd.nLocationId, nTimetableId, nTimetableVersion)) { //LOGERROR("获取当前正在运行的时间表ID和版本号失败"); //获取失败,继续重试,靠超时失败 return; } if (nTimetableId == stCmd.nTimetableId && nTimetableVersion == stCmd.nTimetableVersion) { LOGINFO("时间表下载成功.LocationId=[%d],TimetableId=[%d]", stCmd.nLocationId, stCmd.nTimetableId); stCmd.setResult(true, I18N("时间表下载成功"), eSuccessState); return; } } /* @brief 下载命令完成后的处理 */ void kbd_app::CDownloadTimetable::downloadCompleted(STimetableCmd &stCmd) { //TODO:产生事件 if (stCmd.bIsSuccess) { LOGINFO("时间表下载成功.LocationId=[%d],TimetableId=[%d],ResultDesc=[%s]", stCmd.nLocationId, stCmd.nTimetableId, stCmd.strResultDesc.c_str()); } else { LOGERROR("时间表下载失败.LocationId=[%d],TimetableId=[%d],ResultDesc=[%s]", stCmd.nLocationId, stCmd.nTimetableId, stCmd.strResultDesc.c_str()); } m_ptrBasicOpt->sendResponse(stCmd); }