首页 > 其他分享 >「 Modbus-RTU报文解析」解析03、06、10功能码报文示例

「 Modbus-RTU报文解析」解析03、06、10功能码报文示例

时间:2023-02-04 10:31:07浏览次数:42  
标签:示例 int 报文 apps char str input 解析


文章目录

  • ​​背景介绍​​
  • ​​方案思路​​
  • ​​报文示例​​
  • ​​需求分解​​
  • ​​简要思路​​
  • ​​代码示例​​
  • ​​共赢共享​​
  • ​​番外​​

背景介绍

项目用到modbus-rtu通讯协议与三方平台通讯,由于三方平台没有寄存器地址点表信息,只提供了报文数据,故需要对报文进行二次解析,从而获得三方平台使用到的寄存器地址信息。

方案思路

报文示例

报文示例无包尾校验位,从站地址为1,数据位高前低后,一个寄存器占用两个字节。
​​​01030001002B​

从站地址

功能码

寄存器起始地址(高位)

寄存器起始地址(低位)

读取寄存器个数(高位)

读取寄存器个数(低位)

0x01

0x03

0x00

0x04

0x00

0x2B

​010600580000​

从站地址

功能码

寄存器地址(高位)

寄存器地址(低位)

写入值(高位)

写入值((低位)

0x01

0x06

0x00

0x58

0x00

0x00

​0110003300020400010001​

从站地址

功能码

寄存器起始地址(高位)

寄存器起始地址(低位)

设置寄存器个数(高位)

设置寄存器个数(低位)

字节数

字节1

字节2

字节3

字节4

0x01

0x10

0x00

0x33

0x00

0x02

0x04

0x00

0x01

0x00

0x01

需求分解

1.三方平台报文以excel形式提供;
2.三方平台报文里很多重复报文需要剔除;
3.统计输出时希望可以按照顺序输出,便于统计与观看;

简要思路

需要根据提供的报文,解析出modbus主站所使用的寄存器地址与个数,方便点表的统计与维护。
1.把excel报文复制到txt文档中,解析程序读取txt文档,这样方便后期其他报文导入解析,只需要替换txt文档即可,程序灵活,可扩展性强;
2.报文有重复,需要去重,由于我近期使用​​​unordered_map​​​比较多,所以使用了​​unordered_map​​​,其实​​map​​​更合适;
3.由于使用了​​​unordered_map​​,所以还需要做下排序处理;

代码示例

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <cctype>
#include <unordered_map>
#include <algorithm>

using namespace std;

vector<string> str_apps_input; ///< 文本输入

///< 利用unordered_map实现去重
unordered_map<string,int> str_apps_output_F703; ///< 文本输出 F703
unordered_map<string,int> str_apps_output_F706; ///< 文本输出 F706
unordered_map<string,int> str_apps_output_F710; ///< 文本输出 F710

void parseProtocolFile(const char *input_file);
int hex2dec(char *hex);
int c2i(char ch);

///< 对unordered_map进行排序
bool comp(const pair<string, int>& a, const pair<string, int> &b)
{
return a.second < b.second;
}

int main(int argc, char ** argv)
{
int count = 0;

//打开本地文件,解析报文
char filepath[128] = "./test.txt";

parseProtocolFile(filepath);

int n = str_apps_input.size();

for (int i = 0; i < n ; i++)
{
//printf("(*str_apps[i].c_str()) is %s\n", *str_apps[i].c_str());

char str_addr1[16] = { 0 };
char str_addr2[16] = { 0 };
char str_addr3[16] = { 0 };
char str_addr[128] = { 0 };

if (str_apps_input[i].find("F703") != string::npos)
{
sprintf_s(str_addr1, "%c%c", *((char*)(str_apps_input[i].c_str()) + 4), *((char*)(str_apps_input[i].c_str()) + 5));
sprintf_s(str_addr2, "%c%c", *((char*)(str_apps_input[i].c_str()) + 6), *((char*)(str_apps_input[i].c_str()) + 7));
sprintf_s(str_addr3, "%c%c", *((char*)(str_apps_input[i].c_str()) + 10), *((char*)(str_apps_input[i].c_str()) + 11));

int address = hex2dec(str_addr1) * 256 + hex2dec(str_addr2);
int number = hex2dec(str_addr3);

sprintf_s(str_addr, "address is %d, number is %d\n", address, number);

str_apps_output_F703[str_addr] = address;
}
else if (str_apps_input[i].find("F706") != string::npos)
{
sprintf_s(str_addr1, "%c%c", *((char*)(str_apps_input[i].c_str()) + 4), *((char*)(str_apps_input[i].c_str()) + 5));
sprintf_s(str_addr2, "%c%c", *((char*)(str_apps_input[i].c_str()) + 6), *((char*)(str_apps_input[i].c_str()) + 7));

int address = hex2dec(str_addr1) * 256 + hex2dec(str_addr2);

sprintf_s(str_addr, "address is %d\n", address);

str_apps_output_F706[str_addr] = address;
}
else if (str_apps_input[i].find("F710") != string::npos)
{
sprintf_s(str_addr1, "%c%c", *((char*)(str_apps_input[i].c_str()) + 4), *((char*)(str_apps_input[i].c_str()) + 5));
sprintf_s(str_addr2, "%c%c", *((char*)(str_apps_input[i].c_str()) + 6), *((char*)(str_apps_input[i].c_str()) + 7));
sprintf_s(str_addr3, "%c%c", *((char*)(str_apps_input[i].c_str()) + 10), *((char*)(str_apps_input[i].c_str()) + 11));

int address = hex2dec(str_addr1) * 256 + hex2dec(str_addr2);
int number = hex2dec(str_addr3);

sprintf_s(str_addr, "address is %d, number is %d\n", address, number);

str_apps_output_F710[str_addr] = address;
}
else
{
printf("can not parse:%s\n", str_apps_input[i].c_str());
}
}

///< F703
vector<pair<string, int>> vec_F703;
for (auto x : str_apps_output_F703)
{
vec_F703.push_back(x);
}

sort(vec_F703.begin(), vec_F703.end(),comp);

printf("\nF703 protocol\n");
for (auto x : vec_F703)
{
printf("%s", x.first.c_str());
}


///< F706
vector<pair<string, int>> vec_F706;
for (auto x : str_apps_output_F706)
{
vec_F706.push_back(x);
}

sort(vec_F706.begin(), vec_F706.end(), comp);

printf("\nF706 protocol\n");
for (auto x : vec_F706)
{
printf("%s", x.first.c_str());
}


///< F710
vector<pair<string, int>> vec_F710;
for (auto x : str_apps_output_F710)
{
vec_F710.push_back(x);
}

sort(vec_F710.begin(), vec_F710.end(), comp);

printf("\nF710 protocol\n");
for (auto x : vec_F710)
{
printf("%s", x.first.c_str());
}

///< 解析规约报文文件
void parseProtocolFile(const char *map_file)
{
FILE* fp_cfg;

if (0 == (fopen_s(&fp_cfg,(const char*)map_file, (const char*)"rt")))
{
char line[1024] = { 0 };
void* ret = NULL;
while (true) {
memset(line, 0, sizeof(line));
ret = fgets(line, sizeof(line), fp_cfg);
if (ret == NULL) break;
if (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r') {
line[strlen(line) - 1] = '\0';
}
if (line[strlen(line) - 1] == '\r' || line[strlen(line) - 1] == '\n') {
line[strlen(line) - 1] = '\0';
}

//printf("%s\n", line);

str_apps_input.push_back(line);
}

fclose(fp_cfg);
}
}

int c2i(char ch)
{
if (isdigit(ch))
return ch - 48;

if (ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z')
return -1;
if (isalpha(ch))
return isupper(ch) ? ch - 55 : ch - 87;

return -1;
}

int hex2dec(char *hex)
{
int len;
int num = 0;
int temp;
int bits;
int i;
len = strlen(hex);

for (i = 0, temp = 0; i < len; i++, temp = 0)
{
temp = c2i(*(hex + i));
bits = (len - i - 1) * 4;
temp = temp << bits;
num = num | temp;
}

// 返回结果
return num;
}

共赢共享

示例代码已上传,可运行。​​vs2019工程可运行,供参考​​

番外

由于我这里需求只需要寄存器地址与个数,所以只解析了部分。有全部解析需求的同学可以在此基础上做二次开发。
1.针对技术方案选型,我分享几点想法吧。考虑到程序的适应性,我选择了从文件读取数据的方式,这样比较灵活,只要把海量的数据拷贝进文件即可,无需其他复杂的操作。后期还方便其他功能码报文的导入与解析,只需要加解析分支即可。
2.针对乱序报文的情况,我采用预筛选的策略,读取报文文件时按行读取内容,根据报文类型,插入到对应的​​​unordered_map​​​中,便于后面打印输出;
3.另外针对去重与排序的需求点,应该是使用​​​map​​​更合适,有兴趣的同学可以使用​​map​​​实现下这个功能,还有余力的话,可以了解了解​​map​​​、​​unordered_map​​​两者的异同、优缺点等。
最后祝大家代码一把过,全都没bug!互相学习,共同进行!


标签:示例,int,报文,apps,char,str,input,解析
From: https://blog.51cto.com/u_15953444/6036778

相关文章