2025-03-12 14:17:53 +08:00

416 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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<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);
}