| | |
| | | #include "stdafx.h" |
| | | #include "stdafx.h" |
| | | #include "HsmsPassive.h" |
| | | #include "Log.h" |
| | | #include "Model.h" |
| | |
| | | #include <time.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <regex> |
| | | |
| | | |
| | | const char ACK[2] = {0, 1}; |
| | | const char* ACK0 = &ACK[0]; |
| | | const char* ACK1 = &ACK[1]; |
| | | |
| | | unsigned __stdcall CimWorkThreadFunction(LPVOID lpParam) |
| | | { |
| | |
| | | |
| | | void CHsmsPassive::setListener(SECSListener listener) |
| | | { |
| | | m_listener.onEQOffLine = listener.onEQOffLine; |
| | | m_listener.onEQOnLine = listener.onEQOnLine; |
| | | m_listener.onCommand = listener.onCommand; |
| | | m_listener.onEQConstantRequest = listener.onEQConstantRequest; |
| | | m_listener.onEQConstantSend = listener.onEQConstantSend; |
| | | m_listener = listener; |
| | | } |
| | | |
| | | void CHsmsPassive::setActionTimeout(int nSecond) |
| | |
| | | { |
| | | for (auto it = m_mapReportIdToCEID.begin(); it != m_mapReportIdToCEID.end(); ) { |
| | | if (it->second == CEID) { |
| | | m_mapReportIdToCEID.erase(it++); // 更新迭代器 |
| | | m_mapReportIdToCEID.erase(it++); // 更新迭代器 |
| | | } |
| | | else { |
| | | ++it; |
| | |
| | | { |
| | | for (auto it = m_mapValueIdToPRTID.begin(); it != m_mapValueIdToPRTID.end(); ) { |
| | | if (it->second == RPTID) { |
| | | m_mapValueIdToPRTID.erase(it++); // 更新迭代器 |
| | | m_mapValueIdToPRTID.erase(it++); // 更新迭代器 |
| | | } |
| | | else { |
| | | ++it; |
| | |
| | | |
| | | void CHsmsPassive::OnTimer(UINT nTimerid) |
| | | { |
| | | // 所有已发送的Action自加1 |
| | | // 所有已发送的Action自加1 |
| | | Lock(); |
| | | for (auto iter = m_listActionSent.begin(); iter != m_listActionSent.end();) { |
| | | if ((*iter)->incrementAndCheckTimeout()) { |
| | | TRACE("CHsmsPassive::超时\n"); |
| | | TRACE("CHsmsPassive::超时\n"); |
| | | delete (*iter); |
| | | m_listActionSent.erase(iter++); |
| | | } |
| | |
| | | CHsmsAction* pAction = nullptr; |
| | | for (auto iter = m_listActionSent.begin(); iter != m_listActionSent.end(); iter++) { |
| | | if ((*iter)->getSendMessage()->getHeader()->systemBytes == pMessage->getHeader()->systemBytes) { |
| | | LOGI("CHsmsPassive::找到"); |
| | | LOGI("CHsmsPassive::找到"); |
| | | pAction = (*iter); |
| | | m_listActionSent.erase(iter); |
| | | break; |
| | |
| | | Unlock(); |
| | | |
| | | if (pAction != nullptr) { |
| | | LOGI("onRecvMsg::相应处理"); |
| | | LOGI("onRecvMsg::相应处理"); |
| | | delete pAction; |
| | | } |
| | | |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int CHsmsPassive::loadVarialbles(const char* pszFilepath) |
| | | { |
| | | CStdioFile file; |
| | | if (!file.Open(pszFilepath, CFile::modeRead)) { |
| | | return -1; |
| | | } |
| | | |
| | | std::regex pattern("^\\d+,.*"); // 匹配以数字+逗号开头的字符串 |
| | | std::vector<SERVO::CVariable*> variables; |
| | | int index, last; |
| | | CString strLine; |
| | | CString strId, strName, strFormat, strRemark; |
| | | while (file.ReadString(strLine)) { |
| | | if (!std::regex_match((LPTSTR)(LPCTSTR)strLine, pattern)) { |
| | | continue; |
| | | } |
| | | |
| | | last = 0; |
| | | index = strLine.Find(",", last); |
| | | if (index < 0) continue; |
| | | strId = strLine.Left(index); |
| | | last = index + 1; |
| | | |
| | | index = strLine.Find(",", last); |
| | | if (index < 0) continue; |
| | | strName = strLine.Mid(last, index - last); |
| | | last = index + 1; |
| | | |
| | | index = strLine.Find(",", last); |
| | | if (index < 0) continue; |
| | | strFormat = strLine.Mid(last, index - last); |
| | | strRemark = strLine.Right(strLine.GetLength() - index - 1); |
| | | strRemark.Replace(_T("\\r\\n"), _T("\r\n")); |
| | | |
| | | SERVO::CVariable* pVarialble = new SERVO::CVariable( |
| | | (LPTSTR)(LPCTSTR)strId, (LPTSTR)(LPCTSTR)strName, (LPTSTR)(LPCTSTR)strFormat, (LPTSTR)(LPCTSTR)strRemark); |
| | | variables.push_back(pVarialble); |
| | | } |
| | | |
| | | if (!variables.empty()) { |
| | | clearAllVariabel(); |
| | | for (auto item : variables) { |
| | | m_variabels.push_back(item); |
| | | } |
| | | } |
| | | |
| | | |
| | | file.Close(); |
| | | return 0; |
| | | } |
| | | |
| | | std::vector<SERVO::CVariable*>& CHsmsPassive::getVariables() |
| | | { |
| | | return m_variabels; |
| | | } |
| | | |
| | | SERVO::CVariable* CHsmsPassive::getVariable(int variableId) |
| | | { |
| | | for (auto item : m_variabels) { |
| | | if (item->getVarialbleId() == variableId) { |
| | | return item; |
| | | } |
| | | } |
| | | |
| | | return nullptr; |
| | | } |
| | | |
| | | void CHsmsPassive::clearAllVariabel() |
| | | { |
| | | for (auto item : m_variabels) { |
| | | delete item; |
| | | } |
| | | m_variabels.clear(); |
| | | } |
| | | |
| | | int CHsmsPassive::loadReports(const char* pszFilepath) |
| | | { |
| | | CStdioFile file; |
| | | if (!file.Open(pszFilepath, CFile::modeRead)) { |
| | | return -1; |
| | | } |
| | | |
| | | std::regex pattern("^\\d+,\\(\\d+(,\\d+)*\\).*"); // 匹配以数字+逗号开头的字符串 |
| | | std::vector<SERVO::CReport*> reports; |
| | | int index; |
| | | CString strLine, strVariable; |
| | | CString strId, strName, strFormat, strRemark; |
| | | while (file.ReadString(strLine)) { |
| | | if (!std::regex_match((LPTSTR)(LPCTSTR)strLine, pattern)) { |
| | | continue; |
| | | } |
| | | |
| | | index = strLine.Find(",", 0); |
| | | if (index < 0) continue; |
| | | strId = strLine.Left(index); |
| | | strVariable = strLine.Right(strLine.GetLength() - index - 1); |
| | | strVariable.Delete(0); |
| | | strVariable.Delete(strVariable.GetLength() - 1); |
| | | auto vids = parseVidList(strVariable); |
| | | |
| | | |
| | | SERVO::CReport* pReport = new SERVO::CReport(atoi((LPTSTR)(LPCTSTR)strId)); |
| | | for (auto vid : vids) { |
| | | SERVO::CVariable* pVariable = getVariable(vid); |
| | | if (pVariable != nullptr) { |
| | | pReport->addVariable(pVariable); |
| | | } |
| | | } |
| | | |
| | | reports.push_back(pReport); |
| | | } |
| | | |
| | | if (!reports.empty()) { |
| | | clearAllReport(); |
| | | for (auto item : reports) { |
| | | m_reports.push_back(item); |
| | | } |
| | | } |
| | | |
| | | |
| | | file.Close(); |
| | | return 0; |
| | | } |
| | | |
| | | std::vector<SERVO::CReport*>& CHsmsPassive::getReports() |
| | | { |
| | | return m_reports; |
| | | } |
| | | |
| | | void CHsmsPassive::clearAllReport() |
| | | { |
| | | for (auto item : m_reports) { |
| | | delete item; |
| | | } |
| | | m_reports.clear(); |
| | | } |
| | | |
| | | std::vector<int> CHsmsPassive::parseVidList(CString& strNums) |
| | | { |
| | | // 1. 先去掉可能出现的空白符(空格、制表符等) |
| | | strNums.Trim(); |
| | | |
| | | // 2️. |
| | | std::vector<int> result; |
| | | int i = 0; |
| | | CString strVid; |
| | | while (1) { |
| | | if (!AfxExtractSubString(strVid, (LPCTSTR)strNums, i, ',')) { |
| | | break; |
| | | } |
| | | if (!strVid.IsEmpty()) // 防御性检查 |
| | | result.push_back(std::stoi((LPTSTR)(LPCTSTR)strVid)); |
| | | i++; |
| | | |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | int CHsmsPassive::init(CModel* pModel, const char* pszName, unsigned int port) |
| | |
| | | auto onStatusChanged = [&](void* pFrom, STATE state) -> void { |
| | | m_pModel->notifyInt(RX_CODE_PASSIVE_STATUS_CHANGED, (int)state); |
| | | |
| | | // 连上之后发S1F1 |
| | | // 修改为不主动发送,而是响应 |
| | | // 连上之后发S1F1 |
| | | // 修改为不主动发送,而是响应 |
| | | /* |
| | | if (STATE::SELECTED == state) { |
| | | m_bAreYouThereRequest = FALSE; |
| | |
| | | HEADER* pHeader = pMessage->getHeader(); |
| | | int nStream = (pHeader->stream & 0x7F); |
| | | |
| | | LOGI("<HSMS>收到消息 S%dF%d", nStream, pHeader->function); |
| | | LOGI("<HSMS>收到消息 S%dF%d", nStream, pHeader->function); |
| | | if (nStream == 1 && pHeader->function == 1) { |
| | | // S1F1 |
| | | replyAreYouThere(pMessage); |
| | |
| | | listener.funError = onError; |
| | | m_pPassive->setListener(listener); |
| | | |
| | | // 启动工作线程 |
| | | // 启动工作线程 |
| | | m_bCimWorking = TRUE; |
| | | m_hCimWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, ::CimWorkThreadFunction, this, |
| | | 0, &m_nCimWorkThrdaddr); |
| | |
| | | |
| | | int CHsmsPassive::term() |
| | | { |
| | | // 结束线程 |
| | | // 结束线程 |
| | | m_bCimWorking = FALSE; |
| | | SetEvent(m_hCimWorkEvent); |
| | | if (m_hCimWorkThreadHandle != NULL) { |
| | |
| | | m_pPassive = NULL; |
| | | } |
| | | |
| | | clearAllVariabel(); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | |
| | | { |
| | | while (m_bCimWorking) { |
| | | |
| | | // 待退出信号或时间到 |
| | | // 待退出信号或时间到 |
| | | int nRet = WaitForSingleObject(m_hCimWorkEvent, INFINITE); |
| | | ResetEvent(m_hCimWorkEvent); |
| | | if (!m_bCimWorking) break; |
| | | |
| | | // 取出请求列表并进行处理 |
| | | // 取出请求列表并进行处理 |
| | | std::list<CHsmsAction*> list; |
| | | Lock(); |
| | | list.splice(list.end(), m_listAction); |
| | |
| | | LOGI("<HSMS> [SEND] SysByte=%u sessionId:%d", pMessage->getHeader()->systemBytes, pMessage->getHeader()->sessionId); |
| | | |
| | | if (pAction->isNeedWaitReply()) { |
| | | // 如果需要等待回复 |
| | | // 如果需要等待回复 |
| | | int nRet = WaitForSingleObject(pAction->getEvent(), pAction->getTimeout() * 1000); |
| | | if (nRet == WAIT_TIMEOUT) { |
| | | TRACE("Timeout...\n"); |
| | | CContext* pContext = pAction->getContext(); |
| | | if (pContext != NULL) { |
| | | //pContext->setRetCode(CRC_TIMEOUT); |
| | | //pContext->setRetMsg("超时"); |
| | | //pContext->setRetMsg("超时"); |
| | | //pContext->setEvent(); |
| | | } |
| | | } |
| | |
| | | return 0; |
| | | } |
| | | |
| | | // 通用的reply ack函数 |
| | | // 通用的reply ack函数 |
| | | void CHsmsPassive::replyAck(int s, int f, unsigned int systemBytes, BYTE ack, const char* pszAckName) |
| | | { |
| | | IMessage* pMessage = NULL; |
| | |
| | | } |
| | | |
| | | |
| | | // 交由上层应用来获取机器常量值 |
| | | // 交由上层应用来获取机器常量值 |
| | | if (m_listener.onEQOffLine != nullptr) { |
| | | m_listener.onEQOffLine(this); |
| | | } |
| | | |
| | | |
| | | // 回复 |
| | | // 回复 |
| | | replyAck(1, 16, pRecv->getHeader()->systemBytes, BYTE(0), "OFLACK"); |
| | | return 0; |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | // 交由上层应用来获取机器常量值 |
| | | // 交由上层应用来获取机器常量值 |
| | | if (m_listener.onEQOnLine != nullptr) { |
| | | m_listener.onEQOnLine(this); |
| | | } |
| | | |
| | | |
| | | // 回复 |
| | | // 回复 |
| | | replyAck(1, 18, pRecv->getHeader()->systemBytes, BYTE(0), "ONLACK"); |
| | | return 0; |
| | | } |
| | |
| | | ASSERT(pMessage); |
| | | |
| | | ISECS2Item* pItem = pMessage->getBody(); |
| | | pItem->addBinaryItem(BYTE(0), "COMMACK"); |
| | | pItem->addBinaryItem(ACK0, 1, "COMMACK"); |
| | | ISECS2Item* pList = pItem->addItem(); |
| | | pList->addItem(m_strEquipmentModelType.c_str(), "MDLN"); |
| | | pList->addItem(m_strSoftRev.c_str(), "SOFTREV"); |
| | |
| | | } |
| | | |
| | | |
| | | // 要获取的常量表表 |
| | | // 要获取的常量表表 |
| | | BOOL bCheckData = FALSE; |
| | | std::vector<EQConstant> eqcs; |
| | | { |
| | |
| | | } |
| | | |
| | | |
| | | // 交由上层应用来获取机器常量值 |
| | | // 交由上层应用来获取机器常量值 |
| | | if (m_listener.onEQConstantRequest != nullptr) { |
| | | m_listener.onEQConstantRequest(this, eqcs); |
| | | } |
| | | |
| | | |
| | | // 回复 |
| | | // 回复 |
| | | IMessage* pMessage = NULL; |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 14, pRecv->getHeader()->systemBytes); |
| | | ASSERT(pMessage); |
| | |
| | | } |
| | | |
| | | |
| | | // 要设置的常量表表 |
| | | // 要设置的常量表表 |
| | | BOOL bCheckData = FALSE; |
| | | std::vector<EQConstant> eqcs; |
| | | { |
| | |
| | | } |
| | | |
| | | |
| | | // 交由上层应用来保存和设置机器常量值 |
| | | // 交由上层应用来保存和设置机器常量值 |
| | | std::vector<unsigned int> ecvs; |
| | | if (m_listener.onEQConstantSend != nullptr) { |
| | | m_listener.onEQConstantSend(this, eqcs); |
| | | } |
| | | |
| | | |
| | | // 回复 |
| | | // 回复 |
| | | replyAck(2, 16, pRecv->getHeader()->systemBytes, BYTE(0), "EACK"); |
| | | return 0; |
| | | } |
| | |
| | | if (pBody == nullptr || pBody->getType() != SITYPE::A) ER_PARAM_ERROR; |
| | | const char* pszMessage; |
| | | if (pBody->getString(pszMessage)) { |
| | | // 更新时间 |
| | | // 更新时间 |
| | | SYSTEMTIME time; |
| | | char szBuffer[20]; |
| | | memcpy(szBuffer, pszMessage, 16); |
| | |
| | | time.wYear = atoi(&szBuffer[0]); |
| | | time.wMilliseconds = 0; |
| | | SetLocalTime(&time); |
| | | if (m_listener.onDatetimeSync != nullptr) { |
| | | m_listener.onDatetimeSync(this, time); |
| | | } |
| | | } |
| | | |
| | | replyAck(2, 32, pRecv->getHeader()->systemBytes, BYTE(0), "TIACK"); |
| | |
| | | |
| | | |
| | | MYREPLY: |
| | | // 检验结果是否正确 |
| | | // 检验结果是否正确 |
| | | for (auto item : m_mapValueIdToPRTID) { |
| | | LOGE("=== vid:%d, prtid:%d", item.first, item.second); |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | // 检验结果是否正确 |
| | | // 检验结果是否正确 |
| | | for (auto item : m_mapReportIdToCEID) { |
| | | LOGE("=== prtid:%d, ceid:%d", item.first, item.second); |
| | | } |
| | |
| | | } |
| | | } |
| | | bCheckData = TRUE; |
| | | LOGI("EanbleDisableAlarm bEnable:%s", bEnable ? _T("YES") : _T("NO")); |
| | | for (auto item : ids) { |
| | | LOGI("ID:%u", item); |
| | | if (m_listener.onEnableDisableEventReport != nullptr) { |
| | | m_listener.onEnableDisableEventReport(this, bEnable, ids); |
| | | } |
| | | } |
| | | |
| | | |
| | | MYREPLY: |
| | | replyAck(2, 38, pRecv->getHeader()->systemBytes, BYTE(0), "ERACK"); |
| | | replyAck(2, 38, pRecv->getHeader()->systemBytes, |
| | | bCheckData ? BYTE(0) : BYTE(1), "ERACK"); |
| | | return 0; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | // 回调到应用层 |
| | | // 回调到应用层 |
| | | if (bCheckData) { |
| | | if (m_listener.onCommand != nullptr) { |
| | | m_listener.onCommand(this, pszCmdName, params); |
| | |
| | | if (!pItem->getSubItemU4(1, ALID)) goto MYREPLY; |
| | | bCheckData = TRUE; |
| | | LOGI("EanbleDisableAlarmReport ALED:0x%02x, ALID:%d", ALED[0], ALID); |
| | | |
| | | double d; |
| | | float f; |
| | | pItem->getSubItemF4(2, f); |
| | | pItem->getSubItemF8(3, d); |
| | | LOGI("EanbleDisableAlarmReport d:%lf, f:%f", |
| | | d, f); |
| | | /* |
| | | unsigned long long n1; |
| | | unsigned int n2; |
| | | unsigned short n3; |
| | | unsigned char n4; |
| | | long long sn1; |
| | | int sn2; |
| | | short sn3; |
| | | char sn4; |
| | | pItem->getSubItemU8(2, n1); |
| | | pItem->getSubItemU4(3, n2); |
| | | pItem->getSubItemU2(4, n3); |
| | | pItem->getSubItemU1(5, n4); |
| | | pItem->getSubItemI8(6, sn1); |
| | | pItem->getSubItemI4(7, sn2); |
| | | pItem->getSubItemI2(8, sn3); |
| | | pItem->getSubItemI1(9, sn4); |
| | | |
| | | LOGI("EanbleDisableAlarmReport n1:%llu, n2:%u, n3:%hu, n4:%hhu", |
| | | n1, n2, n3, n4); |
| | | LOGI("EanbleDisableAlarmReport sn1:%lld, sn2:%d, sn3:%hd, sn4:%hhd", |
| | | sn1, sn2, sn3, sn4); |
| | | */ |
| | | if (m_listener.onEnableDisableAlarmReport != nullptr) { |
| | | m_listener.onEnableDisableAlarmReport(this, ALED[0] != 0, ALID); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | return ER_NOTSELECT; |
| | | } |
| | | |
| | | char szALCD[1]; |
| | | szALCD[0] = ALCD & 0xff; |
| | | |
| | | Lock(); |
| | | CHsmsAction* pAction = new CHsmsAction(ACTION_ALARM_REPORT, TRUE, m_nActionTimeout); |
| | | m_listAction.push_back(pAction); |
| | |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 5 | REPLY, 1, ++m_nSystemByte); |
| | | ASSERT(pMessage); |
| | | ISECS2Item* pItem = pMessage->getBody(); |
| | | pItem->addBinaryItem(BYTE(ALCD & 0xff), "ALCD"); |
| | | pItem->addBinaryItem(szALCD, 1, "ALCD"); |
| | | pItem->addU4Item(ALID, "ALID"); |
| | | pItem->addItem(ALTX, "ALTX"); |
| | | pAction->setSendMessage(pMessage); |