416 lines
18 KiB
C++
Raw Normal View History

#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 kbd_public;
using namespace kbd_app;
// using namespace kbd_net;
// using namespace kbd_dbms;
kbd_app::CDownloadTimetable::CDownloadTimetable(const kbd_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<STableTimetableInfo> 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);
}