/** * @content:ModbusRTU组件实现文件 * @time:2016-8-23 * @author:Mr_zhu * @version: V1.0 * @describe: * 1#2016-8-23#V1.0#首次生成 */ #include "ProtocolImpl.h" #include #include #include #include #include #include #include "../../common/GUID.cpp" #include "../../servicemodel/Base.h" #include "../../servicemodel/Channel.h" #include "../../servicemodel/Device.h" #include "../../servicemodel/Item.h" #include "../../servicemodel/Packet.h" using namespace std; bool ProtocolImpl::hasInit = false; uint8_t ProtocolImpl::retBigEndian(uint32_t value, int offset) { uint8_t ret = 0; ret = (value >> offset) & 0xFF; return ret; } int ProtocolImpl::getRegAddrMax(Packet *ppacket, Item *pitem) { std::string sParaRegAddr; int iParaRegAddr; int maxRegAddr = -1; //Base& base = pitem->getBase(); std::vector items = ppacket->getVitem(); for (size_t i = 0; i < items.size(); ++i) //遍历容器中的所有元素 { sParaRegAddr = items[i]->getBase().getParam("起始地址"); iParaRegAddr = strtol(sParaRegAddr.c_str(), NULL, HEX); if (iParaRegAddr > maxRegAddr) //更新寄存器数量最大值 { maxRegAddr = iParaRegAddr; } else { } } log_i("最大的起始地址:0x%x", maxRegAddr); return maxRegAddr; } int ProtocolImpl::getRegAddrMin(Packet *ppacket, Item *pitem) { std::string sMinRegAddr; int iMinRegAddr = 0; std::string sParaRegAddr; int iParaRegAddr; std::vector items = ppacket->getVitem(); log_i("Items size: %zu", items.size()); sMinRegAddr = items[0]->getBase().getParam("起始地址"); iMinRegAddr = strtol(sMinRegAddr.c_str(), NULL, HEX); log_i("Initial minimum register address value: 0x%x", iMinRegAddr); for (size_t i = 0; i < items.size(); ++i) { log_i("Processing item %zu", i); sParaRegAddr = items[i]->getBase().getParam("起始地址"); iParaRegAddr = strtol(sParaRegAddr.c_str(), NULL, HEX); if (iParaRegAddr < iMinRegAddr) { iMinRegAddr = iParaRegAddr; } } log_i("最小的寄存器起始地址:0x%x", iMinRegAddr); return iMinRegAddr; } int ProtocolImpl::retStateResponse(Packet *ppacket, Item *pitem, const int len) { int maxRegAddr = -1; int minRegAddr = 0; int regNum = 0; int datasLen = 0; maxRegAddr = getRegAddrMax(ppacket, pitem); minRegAddr = getRegAddrMin(ppacket, pitem); regNum = maxRegAddr - minRegAddr + 1; log_i("reg:%d", regNum); datasLen = getRealValidLen(regNum); log_i("最大寄存器地址:0x%x,最小寄存器数量:0x%x,寄存器个数:0x%x,数据长度:%d,合法的数据长度=%d", maxRegAddr, minRegAddr, regNum, datasLen, len); if (len >= datasLen) { return S_OK; } else { return S_FALSE; } return S_FALSE; } int ProtocolImpl::getRealValidLen(int maxRegNum) { int len = 0; if (maxRegNum <= 4 && maxRegNum > 0) { len = 4 + 2 * maxRegNum; log_i("寄存器数量小于等于4个,计算得出合法数据长度:%d", len); } else { if (maxRegNum % 4 == 0) { len = 12 * (maxRegNum / 4); log_i("寄存器请求数量:%d,回复帧长度:%d",maxRegNum,len); } else { len = 4*((maxRegNum / 4) +1) + (maxRegNum *2); //帧数据长度+寄存器长度 log_i("寄存器请求数量:%d,回复帧长度:%d",maxRegNum,len); } } return len; } int ProtocolImpl::getRealFrame(PBYTE pbuf, int count) { PBYTE ptemp = pbuf; int id = (((ptemp[0 + count] << 24) & 0xff000000) | ((ptemp[1 + count] << 16) & 0x00ff0000) | ((ptemp[2 + count] << 8) & 0x0000ff00) | ((ptemp[3 + count]) & 0x000000ff)); log_i("帧id:0x%x", id); return id; } std::map ProtocolImpl::handleDataLess(PBYTE pbuf,int len,int regNum,int datasLen) { int iPbufId; std::map dataSet; iPbufId = getRealFrame(pbuf, 0); for (int i = 0; i < regNum; i++) { uint16_t regValue = 0; if (i * 2 + 4 <= datasLen) { regValue = (pbuf[i * 2 + 4] << 8) | pbuf[i * 2 + 5]; // 提取寄存器值 dataSet[iPbufId + i] = regValue; // 绑定到map } else { log_i( "Data insufficient for regNum %d, setting default value 0xFFFF", i); // 数据不足,处理错误或默认值 regValue = 0xFFFF; // 默认值为;0xFFFF dataSet[iPbufId + i] = regValue; // 绑定到map log_i("Added to dataSet: addrFrame=0x%x, value=0x%x", iPbufId + i, regValue); } } for (const auto &entry : dataSet) { log_i("addrFrame = 0x%x, value = 0x%x", entry.first, entry.second); } return dataSet; } std::map ProtocolImpl::handleDataGreater(PBYTE pbuf,int len,int regNum,int datasLen) { int validlen = len; int iPbufId; std::map dataSet; for (int count = 0; ((count < validlen) && ((validlen - count) >= 12)); count += 12) { iPbufId = getRealFrame(pbuf, count); for (int i = 0; i < 4 && regNum > 0; i++,regNum --) // i代表第i个寄存器 { uint16_t regValue = 0; if (i * 2 + 4 + count <= datasLen) //当前寄存器数量的总帧数 { regValue = (pbuf[i * 2 + 4 + count] << 8) | pbuf[i * 2 + 5 + count]; // 提取寄存器值 dataSet[iPbufId + i % 4] = regValue; // 绑定到map } else { // 数据不足,处理错误或默认值 regValue = 0xFFFF; // 默认值为0xFFFF dataSet[iPbufId + i % 4] = regValue; // 绑定到map } } for (const auto &entry : dataSet) { log_i("addrFrame = 0x%x, value = 0x%x", entry.first, entry.second); } } return dataSet; } std::mapProtocolImpl::retDataSet(Packet *ppacket, Item *pitem,PBYTE pbuf,int len) { std::map dataSet; // 存储寄存器地址和值 int maxRegAddr, minRegAddr, regNum; int datasLen = 0; maxRegAddr = getRegAddrMax(ppacket, pitem); minRegAddr = getRegAddrMin(ppacket, pitem); regNum = maxRegAddr - minRegAddr + 1; datasLen = getRealValidLen(regNum); if (datasLen <= 12) { dataSet = handleDataLess(pbuf,len,regNum,datasLen); } else { dataSet = handleDataGreater(pbuf,len,regNum,datasLen); } return dataSet; } int ProtocolImpl::iGetItemParaConfig(Item *pitem,std::string attribute) { Item *t_item = pitem; Base &t_base = t_item->getBase(); string sAttribute = ""; int iAttribute = 0; sAttribute = t_base.getParam(attribute); log_i("%s: %s",attribute.c_str(), sAttribute.c_str()); iAttribute = strtol(sAttribute.c_str(), NULL, HEX); log_i("retV:0x%x",iAttribute); return iAttribute; } std::string ProtocolImpl::sGetItemParaConfig(Item *pitem, std::string attribute) { Item *t_item = pitem; Base &t_base = t_item->getBase(); string sAttribute = ""; sAttribute = t_base.getParam(attribute); log_i("%s: %s",attribute.c_str(), sAttribute.c_str()); return sAttribute; } void ProtocolImpl::setData(Item *pitem,int16_t pbuf,int receiveData,int paraData,std::string t_sDataType,std::string t_sByteOrder,string t_sBits) { Item* t_item = pitem; int16_t buf = pbuf; string t_str; char t[256]; log_i("receiveData:0x%x,paraData:0x%x",receiveData,paraData); if(receiveData == paraData) { log_i("ID匹配,处理数据"); if (t_sDataType == "I") { log_i("数据类型为I,调用merge16函数,buf=0x%x",buf); t_item->setValue(merge16(buf, t_sByteOrder)); } else if (t_sDataType == "UI") { log_i("数据类型为UI,调用merge16函数"); t_item->setValue(merge16(buf, t_sByteOrder)); } else if (t_sDataType == "B") { int index = t_sBits.find("."); if (index != -1) { string t_sBitnum = t_sBits.substr(0,index); int t_iBitnum =(int) (strtol(t_sBitnum.c_str(),NULL, 10)); //----位起始地址 int t_Bits =(int) (strtol(t_sBits.substr(index + 1).c_str(),NULL, 10)); unsigned short t_usdata =(unsigned short) (strtol(merge16_u(buf,t_sByteOrder).c_str(),NULL, 10)); unsigned short bits = 0; for (int i = 0; i < t_Bits; i++) { unsigned short bit = (t_usdata >> (t_iBitnum + i))& 0x0001; bits += bit * pow(2, i); } snprintf(t, 256, "%d", bits); t_str = t; t_item->setValue(t_str); } } } } HRESULT ProtocolImpl::queryInterface(const IID &iid, void **ppv) { if (iid == IID_IProtocol) { log_d( "成功返回Protocol-CANDEXN协议句柄"); *ppv = static_cast(this); } else if (iid == IID_IUnknown) { log_d( "成功返回Protocol-CANDEXN协议IUnknown句柄"); *ppv = static_cast(this); } else { log_d( "未查询到接口"); *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(*ppv)->addRef(); return S_OK; } ULONG ProtocolImpl::addRef(void) { return ++m_cRef; } ULONG ProtocolImpl::release(void) { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; } ULONG ProtocolImpl::getVersion() { return VERSION; } /** * @content:组织读数据报文 * @time:2016-9-9 * @author:Mr_zhu * @param: pdevice(设备句柄),ppacket(包句柄),pitem(点句柄),pbuf(数据缓冲区),len(返回报文长度) * @return: HRESULT(S_OK,S_FALSE) * @decribe * 1#2016-9-9#V1.0#首次生成 */ HRESULT ProtocolImpl::onRead(Device *pdevice, Packet *ppacket, Item *pitem, PBYTE pbuf, int &len) { log_i("onRead"); if (ppacket->getVitem().size() == 0) { return S_FALSE; } pdevice->getBase().setRwstate(READ_WAIT); //----设置设备状态 std::string sParaId; int iParaId; Base &t_base = ppacket->getVitem().at(0)->getBase(); sParaId = t_base.getParam("功能码"); log_i("Parameter ID: %s", sParaId.c_str()); iParaId = strtol(sParaId.c_str(), NULL, HEX); log_i("Parameter ID: %s", sParaId.c_str()); log_i("Converted Parameter ID: 0x%x", iParaId); int frameFuncCode = (iParaId & 0x070000); log_i("frameFuncCode = 0x%x",frameFuncCode); if (ppacket == nullptr || pitem == nullptr) { log_i("Invalid packet or item"); return S_FALSE; } string t_saddr; t_saddr = pdevice->getBase().getParam("站地址"); int t_iaddr = 0; t_iaddr = strtol(t_saddr.c_str(), NULL, HEX); log_i("stationAddr = %d",t_iaddr); iParaId |= (t_iaddr << 19); log_i("onread -addStation-id = 0x%x",iParaId); //判断寄存器是读寄存器 if(frameFuncCode == 0x030000) { int maxRegAddr = getRegAddrMax(ppacket, pitem); int minRegAddr = getRegAddrMin(ppacket, pitem); log_i("MaxRegAddr: 0x%x, MinRegAddr: 0x%x", maxRegAddr, minRegAddr); if (maxRegAddr < minRegAddr) { log_i("Invalid register address range"); return S_FALSE; } int regNum = maxRegAddr - minRegAddr + 1; pbuf[0] = retBigEndian(iParaId + minRegAddr, 24); pbuf[1] = retBigEndian(iParaId + minRegAddr, 16); pbuf[2] = retBigEndian(iParaId + minRegAddr, 8); pbuf[3] = retBigEndian(iParaId + minRegAddr, 0); pbuf[4] = retBigEndian(regNum, 8); pbuf[5] = retBigEndian(regNum, 0); len = 6; if (pbuf == nullptr) { log_i("pbuf is null"); return S_FALSE; } for (int i = 0; i < 6; i++) { log_i("onRead-读数据:pbuf[%d]:0x%x", i, pbuf[i]); } } Channel *pC = pdevice->getParent(); log_i("Channel pointer: %p", pC); if (pC == nullptr) { log_i("Channel pointer is null"); return S_FALSE; } if (pC != NULL) { if (m_tmpItems.count(pC->getBase().getObjid().toString()) == 0) { log_i("Temporary items not found for Channel ID: %s", pC->getBase().getObjid().toString().c_str()); int ccount = pC->getDeviceCount(); log_i("Channel device count: %d", ccount); std::multimap tmpItems; for (int i = 0; i < ccount; i++) { for (size_t j = 0; j < pC->getVDevice().at(i)->getVitem().size(); j++) { string t_sId; Base &t_base = pC->getVDevice().at(i)->getVitem().at(j)->getBase(); t_sId = t_base.getParam("写功能码"); log_i("写功能码: %s", t_sId.c_str()); int t_iId = 0; t_iId = strtol(t_sId.c_str(), NULL, HEX); //----获取帧ID log_i("功能码转换为整数: 0x%x", t_iId); string t_stype; t_stype = t_base.getParam("帧类型"); log_i("帧类型: %s", t_stype.c_str()); if (t_stype == "1") { t_iId |= 0x80000000; log_i("帧类型为1,功能码更新为: 0x%x", t_iId); } string sStartAddr; //sStartAddr = pC->getVDevice().at(i)->getBase().getParam("起始地址"); sStartAddr = t_base.getParam("起始地址"); log_i("起始地址 =%s", sStartAddr.c_str()); int iStartAddr = 0; iStartAddr = strtol(sStartAddr.c_str(), NULL, HEX); log_i("起始地址转换为整数: 0x%x", iStartAddr); t_iId += iStartAddr; string t_saddr; t_saddr = pC->getVDevice().at(i)->getBase().getParam("站地址"); int t_iaddr = 0; t_iaddr = strtol(t_saddr.c_str(), NULL, HEX); t_iId |= (t_iaddr << 19); tmpItems.insert( make_pair(t_iId, pC->getVDevice().at(i)->getVitem().at(j))); log_i("插入临时条目: ID=0x%x", t_iId); } } m_tmpItems.insert( make_pair(pC->getBase().getObjid().toString(), tmpItems)); } else { log_i("Temporary items already exist for Channel ID: %s", pC->getBase().getObjid().toString().c_str()); } } return S_OK; } /** * @content:组织写数据报文 * @time:2016-9-9 * @author:Mr_zhu * @param: pdevice(设备句柄),ppacket(包句柄),pitem(点句柄),pbuf(数据缓冲区),len(返回报文长度) * @param: swritebuf(待写字符串),writelen(待写数据长度) * @return: HRESULT(S_OK,S_FALSE) * @decribe * 1#2016-9-9#V1.0#首次生成 */ HRESULT ProtocolImpl::onWrite(Device *pdevice, Packet *ppacket, Item *pitem, PBYTE pbuf, int &len, string swritebuf, const unsigned int writelen) { log_i("onWrite"); int t_len = 0; Base &base = pitem->getBase(); string t_sRWType; t_sRWType = base.getParam("读写类型"); //----获取点读写类型 if (t_sRWType == "RO") //----只读 { log_w("%s, 对只读点进行非法写操作,点信息(UUID-%s,名称-%s)", pdevice->getBase().getName().c_str(), base.getObjid().toString().c_str(), base.getName().c_str()); return S_FALSE; } string t_sFuncCode; t_sFuncCode = base.getParam("功能码"); int t_iFuncCode = 0; t_iFuncCode = strtol(t_sFuncCode.c_str(), NULL, HEX); //----获取帧ID string t_sStartAddr; int t_iStartAddr = 0; //----起始地址 t_sStartAddr = base.getParam("起始地址"); t_iStartAddr = strtol(t_sStartAddr.c_str(), NULL, 16); t_iFuncCode += t_iStartAddr; string t_saddr; t_saddr = pdevice->getBase().getParam("站地址"); int t_iaddr = 0; t_iaddr = strtol(t_saddr.c_str(), NULL, HEX); t_iFuncCode |= (t_iaddr << 19); *(pbuf + (t_len++)) = HHByte(t_iFuncCode); *(pbuf + (t_len++)) = HLByte(t_iFuncCode); *(pbuf + (t_len++)) = LHByte(t_iFuncCode); *(pbuf + (t_len++)) = LLByte(t_iFuncCode); //----发送帧ID if (ppacket != NULL && pdevice != NULL && pitem != NULL) { struct candata t_data = //{ 0, 0, 0, 0, 0, 0, 0, 0 }; { 0, 0 }; if (m_tmpwritedata.count(t_sFuncCode) > 0) { t_data = m_tmpwritedata.find(t_sFuncCode)->second; } *(pbuf + (t_len++)) = t_data.data0 & 0x00ff; *(pbuf + (t_len++)) = t_data.data1 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data2 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data3 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data4 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data5 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data6 & 0x00ff; // *(pbuf + (t_len++)) = t_data.data7 & 0x00ff; string t_sDataType; //----数据类型 t_sDataType = base.getParam("数据类型"); string t_sByteOrder; t_sByteOrder = base.getParam("字节序"); if (t_sDataType == "I" || t_sDataType == "UI") { long int value = 0; value = strtol(swritebuf.c_str(), NULL, 10); if (t_sByteOrder == "BA") { pbuf[4] = HByte(value); pbuf[5] = LByte(value); } else if (t_sByteOrder == "AB") { pbuf[4] = LByte(value); pbuf[5] = HByte(value); } } } len = 6; struct candata data; data.data0 = pbuf[4] & 0x00ff; data.data1 = pbuf[5] & 0x00ff; // data.data2 = pbuf[6] & 0x00ff; // data.data3 = pbuf[7] & 0x00ff; // data.data4 = pbuf[8] & 0x00ff; // data.data5 = pbuf[9] & 0x00ff; // data.data6 = pbuf[10] & 0x00ff; // data.data7 = pbuf[11] & 0x00ff; std::string sbuf; for (int i = 0; i < 12; i++) { char str[10]; snprintf(str, 10, "%x", pbuf[i]); sbuf = sbuf + str; if (i != (12 - 1)) { sbuf = sbuf + ","; } } log_i( "待发送数据为: %s", sbuf.c_str()); log_i( "%%x, %x", data.data0, data.data1); m_tmpwritedata[t_sFuncCode] = data; pitem->setValue(swritebuf); // pdevice->getBase().setRwstate(WRITE_O); pdevice->getBase().setRwstate(WRITE_WAIT); return S_OK; } /** * @content:判断回复数据是否接收完成 * @time:2016-9-9 * @author:Mr_zhu * @param: pdevice(设备句柄),ppacket(包句柄),pitem(点句柄),pbuf(数据缓冲区),len(返回报文长度) * @return: HRESULT(S_OK,S_FALSE) * @decribe * 1#2016-9-9#V1.0#首次生成 */ HRESULT ProtocolImpl::isResponseOK(Device *pdevice, Packet *ppacket, Item *pitem, PBYTE pbuf, const int len) { log_i("isResponseOk"); int ret; switch (pdevice->getBase().getRwstate()) { case READ_O: case WRITE_WAIT: case READ_WAIT: ret = retStateResponse(ppacket, pitem, len); log_i("isResponseOK返回值:%d", ret); if (ret == S_OK) { return S_OK; } else { if (ret == S_FALSE) { return S_FALSE; } } return S_FALSE; case WRITE_O: //case WRITE_WAIT: return S_OK; } return S_FALSE; } /** * @content:解析数据 * @time:2016-9-9 * @author:Mr_zhu * @param: pdevice(设备句柄),ppacket(包句柄),pitem(点句柄),pbuf(数据缓冲区),len(返回报文长度),deletelen(待删除数据长度) * @return: HRESULT(S_OK,S_FALSE) * @decribe * 1#2016-9-9#V1.0#首次生成 */ HRESULT ProtocolImpl::onResponse(Device *pdevice, Packet *ppacket, Item *pitem, PBYTE pbuf, const int len, int &deletelen) { log_i("onResponse"); int validlen = len; int t_iRWState = pdevice->getBase().getRwstate(); //----设备读写状态 Base *pbase = new Base(); Base &base = *pbase; std::vector items = ppacket->getVitem(); std::map dataSet; // 存储寄存器地址和值 int id; int16_t buf; Channel *pC = pdevice->getParent(); if (pC == NULL) { log_e("%s, 父通道为空, 无法进行数据解析", pdevice->getBase().getName().c_str()); return S_FALSE; } switch (t_iRWState) { case READ_O: case READ_WAIT: case WRITE_WAIT: log_i("WRITE_WAIT"); if (validlen >= 6) { dataSet=retDataSet(ppacket, pitem,pbuf,len); log_i("pbuf[4]= 0x%x,pbuf[5] = 0x%x",pbuf[4],pbuf[5]); for (const auto &entry : dataSet) { log_i("addrFrame = 0x%x, value = 0x%x", entry.first, entry.second); } for (const auto &dataPair : dataSet) { log_i("addData.size=%d", dataSet.size()); id = dataPair.first; id = (0x7fffffff) & id; buf = dataPair.second; log_i("dataPair.second =0x%x",buf); //buf = (PBYTE) &dataPair.second; //log_i("buf[0] =0x%x,buf[1] =0x%x",buf[0],buf[1]); log_i("Processing data pair with ID: 0x%x", id); if (m_tmpItems.count(pC->getBase().getObjid().toString()) > 0) { log_i("Found temporary items for Channel ID: %s", pC->getBase().getObjid().toString().c_str()); std::multimap tmpItms = m_tmpItems.find( pC->getBase().getObjid().toString())->second; //是否有效 for (const auto &data : tmpItms) { log_i("缓存条目中的缓存地址:0x%x,0x%x", data.first, data.second); } log_i("Temporary items size: %zu", tmpItms.size()); std::multimap::size_type cnt = tmpItms.count( id); log_i("Number of items with ID 0x%x: %zu", id, cnt); std::multimap::iterator iter = tmpItms.find(id); if (iter != tmpItms.end()) { for (; cnt > 0; cnt--, iter++) { log_i("Processing item %zu for ID 0x%x", cnt, id); Item *t_item = iter->second; //Device *ptdevice = (Device*) (t_item->getParent()); if (t_item != NULL && pdevice != NULL) { log_i("Item and Device are valid"); int iId = iGetItemParaConfig(t_item,"写功能码"); int iStartAddr = iGetItemParaConfig(t_item,"起始地址"); string t_stype = sGetItemParaConfig(t_item,"帧类型"); string t_sDataType = sGetItemParaConfig(t_item,"数据类型"); string t_sByteOrder = sGetItemParaConfig(t_item,"字节序"); string t_sBits= sGetItemParaConfig(t_item ,"位地址"); iId += iStartAddr; string t_saddr; t_saddr = pdevice->getBase().getParam("站地址"); int t_iaddr = 0; t_iaddr = strtol(t_saddr.c_str(), NULL, HEX); log_i("t_iId = 0x%x,t_iaddr =%d,",iId,t_iaddr); iId |= (t_iaddr << 19); log_i("设置的数据buf=%d,paraID = 0x%x",buf,iId); setData(t_item, buf,id,iId,t_sDataType,t_sByteOrder,t_sBits); } else { if(t_item == NULL) { log_i("......item== NULL......"); } return S_FALSE; } } } } else { log_i("m_tmpItems.count(pC->getBase().getObjid().toString()) <0"); return S_FALSE; } } return S_OK; } if (pitem != nullptr) { delete pitem; } break; case WRITE_O: break; default: break; } if (pbase != NULL) { delete pbase; pbase = NULL; } return S_OK; } #ifdef __cplusplus extern "C" IUnknown* CreateInstance() { IUnknown *pI = static_cast(new ProtocolImpl()); pI->addRef(); return pI; } #endif