diff --git a/Modbus/include/modbus_master.h b/Modbus/include/modbus_master.h new file mode 100644 index 0000000..9765419 --- /dev/null +++ b/Modbus/include/modbus_master.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +/** + * 实现Modbus主站的所有方法 + */ +class Modbus_Master : public QObject +{ + Q_OBJECT + +public: + Modbus_Master(QObject *parent); + ~Modbus_Master(); + + + // 构建Modbus RTU数据包 + QByteArray build_modbus_pkg( + quint8 slave_addr, + quint8 func_code, + const QByteArray& work_data + ); + + // 解析Modbus RTU数据包 + bool parse_modbus_pkg( + const QByteArray& pkg, + quint8& slave_addr, + quint8& func_code, + QByteArray& work_data + ); + +private: + // 私有方法 + // 计算Modbus CRC16 + quint16 calc_crc(const QByteArray& frame_data) const; + + // 私有变量 + const QByteArray frame; + quint8 slave_addr; + quint8 func_code; + QByteArray work_data; +}; + diff --git a/Modbus/include/modbus_msg.h b/Modbus/include/modbus_msg.h new file mode 100644 index 0000000..36c28a9 --- /dev/null +++ b/Modbus/include/modbus_msg.h @@ -0,0 +1,17 @@ +#pragma once + +#include + + +/** + * 实现消息日志和错误日志的记录导出和存储 + */ +class Modbus_Msg : public QObject +{ + Q_OBJECT + +public: + Modbus_Msg(QObject *parent); + ~Modbus_Msg(); +}; + diff --git a/Modbus/src/modbus_master.cpp b/Modbus/src/modbus_master.cpp new file mode 100644 index 0000000..f958996 --- /dev/null +++ b/Modbus/src/modbus_master.cpp @@ -0,0 +1,98 @@ +#include "../include/modbus_master.h" + +Modbus_Master::Modbus_Master(QObject *parent) + : QObject(parent) +{ + +} + +Modbus_Master::~Modbus_Master() +{ + +} + +QByteArray Modbus_Master::build_modbus_pkg(quint8 slave_addr, quint8 func_code, const QByteArray & work_data) +{ + QByteArray pkg; + + try { + // 添加设备地址 + pkg.append(slave_addr); + // 添加功能码 + pkg.append(func_code); + // 添加工作数据 + pkg.append(work_data); + + // 计算CRC + quint16 crc = calc_crc(pkg); + + // 添加CRC,小端序 + // 低字节 + pkg.append(static_cast(crc & 0xFF)); + // 高字节 + pkg.append(static_cast((crc >> 8) & 0xFF)); + } + catch (const std::exception& ex) { + // TODO:抛出异常 + + + } + + return pkg; +} + +bool Modbus_Master::parse_modbus_pkg(const QByteArray& pkg, quint8& slave_addr, quint8& func_code, QByteArray& work_data) +{ + // 检查数据包长度 + if (pkg.size() < 4) + { + // TODO:抛出异常 + + return false; + } + + // 提取设备地址 + slave_addr = pkg[0]; + // 提取功能码 + func_code = pkg[1]; + // 提取工作数据 + work_data.clear(); + if (pkg.size() > 4) + { + work_data = pkg.mid(2, pkg.size() - 4); + } + // 提取数据包自带的CRC + quint16 crc_bring = static_cast(pkg[pkg.size() - 2]) | + (static_cast(pkg[pkg.size() - 1]) << 8); + // 计算接收数据CRC + QByteArray pkg_data = pkg.mid(0, pkg.size() - 2); + quint16 crc_after_calc = calc_crc(pkg_data); + // CRC校验 + if (crc_after_calc != crc_bring) + { + // TODO:抛出异常 + + return false; + } + + return true; +} + +quint16 Modbus_Master::calc_crc(const QByteArray& pkg_data) const +{ + static const quint16 crcTable[] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841 + }; + + quint16 crc = 0xFFFF; + for (int i = 0; i < pkg_data.size(); ++i) { + crc ^= static_cast(pkg_data[i]); + crc = (crc >> 8) ^ crcTable[crc & 0x0F]; + crc = (crc >> 8) ^ crcTable[crc & 0x0F]; + } + return crc; +} + diff --git a/Modbus/src/modbus_msg.cpp b/Modbus/src/modbus_msg.cpp new file mode 100644 index 0000000..3df7a97 --- /dev/null +++ b/Modbus/src/modbus_msg.cpp @@ -0,0 +1,13 @@ +#include "../include/modbus_log.h" + +Modbus_Log::Modbus_Log(QObject *parent) + : QObject(parent) +{ + +} + +Modbus_Log::~Modbus_Log() +{ + +} +