modbus rtu
This commit is contained in:
428
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.cpp
Normal file
428
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
#include "message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.h"
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "message_bus/pipeline/PipelineContext.h"
|
||||
#include "message_bus/pipeline/stages/1_framers/ModbusRtuFraming.h"
|
||||
|
||||
namespace softbus::message_bus::pipeline::protocol
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using softbus::message_bus::pipeline::BusDirection;
|
||||
using softbus::message_bus::pipeline::stages::framers::modbusRtuCrc16;
|
||||
using softbus::message_bus::pipeline::stages::framers::modbusRtuCrcOk;
|
||||
|
||||
void appendCrcLe(QByteArray& adu)
|
||||
{
|
||||
const auto crc = modbusRtuCrc16(reinterpret_cast<const std::uint8_t*>(adu.constData()),
|
||||
static_cast<std::size_t>(adu.size()));
|
||||
adu.append(static_cast<char>(crc & 0xFF));
|
||||
adu.append(static_cast<char>((crc >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// 功能 :解码Modbus RTU帧 如果解码失败 则返回false 如果解码成功 则返回true
|
||||
bool decodeModbusRtu(BusDirection dir,
|
||||
const std::uint8_t* p,
|
||||
std::size_t n,
|
||||
ModbusRtuPdu& out,
|
||||
QString* errMsg)
|
||||
{
|
||||
auto fail = [&](const char* msg) {
|
||||
if (errMsg) {
|
||||
*errMsg = QString::fromUtf8(msg);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!p || n < 4) {
|
||||
return fail("adu_too_short");
|
||||
}
|
||||
|
||||
if (p[1] & 0x80) {
|
||||
if (n < 5) {
|
||||
return fail("exception_incomplete");
|
||||
}
|
||||
if (!modbusRtuCrcOk(p, 5)) {
|
||||
return fail("exception_crc");
|
||||
}
|
||||
out = ModbusExceptionPdu{p[0], p[1], p[2]};
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::uint8_t unit = p[0];
|
||||
const std::uint8_t fc = p[1];
|
||||
auto parseReadReq = [&]() -> bool {
|
||||
if (n != 8 || !modbusRtuCrcOk(p, 8)) {
|
||||
return false;
|
||||
}
|
||||
const std::uint16_t addr = static_cast<std::uint16_t>((p[2] << 8) | p[3]);
|
||||
const std::uint16_t qty = static_cast<std::uint16_t>((p[4] << 8) | p[5]);
|
||||
switch (fc) {
|
||||
case 0x01:
|
||||
out = ReadCoilsRequest{unit, addr, qty};
|
||||
return true;
|
||||
case 0x02:
|
||||
out = ReadDiscreteInputsRequest{unit, addr, qty};
|
||||
return true;
|
||||
case 0x03:
|
||||
out = ReadHoldingRegistersRequest{unit, addr, qty};
|
||||
return true;
|
||||
case 0x04:
|
||||
out = ReadInputRegistersRequest{unit, addr, qty};
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
auto parseWriteSingleReqOrResp = [&]() -> bool {
|
||||
if (n != 8 || !modbusRtuCrcOk(p, 8)) {
|
||||
return false;
|
||||
}
|
||||
const std::uint16_t addr = static_cast<std::uint16_t>((p[2] << 8) | p[3]);
|
||||
const std::uint16_t val16 = static_cast<std::uint16_t>((p[4] << 8) | p[5]);
|
||||
if (fc == 0x05) {
|
||||
const std::uint8_t coil = (val16 == 0xFF00) ? 1 : 0;
|
||||
if (dir == BusDirection::Upstream) {
|
||||
out = WriteSingleCoilResponse{unit, addr, coil};
|
||||
} else {
|
||||
out = WriteSingleCoilRequest{unit, addr, coil};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (fc == 0x06) {
|
||||
if (dir == BusDirection::Upstream) {
|
||||
out = WriteSingleRegisterResponse{unit, addr, val16};
|
||||
} else {
|
||||
out = WriteSingleRegisterRequest{unit, addr, val16};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto parseWriteMultiReq = [&]() -> bool {
|
||||
if (n < 9) {
|
||||
return false;
|
||||
}
|
||||
const std::uint16_t start = static_cast<std::uint16_t>((p[2] << 8) | p[3]);
|
||||
const std::uint16_t qty = static_cast<std::uint16_t>((p[4] << 8) | p[5]);
|
||||
const std::uint8_t byteCount = p[6];
|
||||
if (n != static_cast<std::size_t>(9) + byteCount) {
|
||||
return false;
|
||||
}
|
||||
if (!modbusRtuCrcOk(p, n)) {
|
||||
return false;
|
||||
}
|
||||
if (fc == 0x0F) {
|
||||
QVector<std::uint8_t> vals;
|
||||
vals.reserve(byteCount);
|
||||
for (std::uint8_t i = 0; i < byteCount; ++i) {
|
||||
vals.append(p[7 + i]);
|
||||
}
|
||||
out = WriteMultipleCoilsRequest{unit, start, qty, std::move(vals)};
|
||||
return true;
|
||||
}
|
||||
if (fc == 0x10) {
|
||||
QVector<std::uint16_t> vals;
|
||||
vals.reserve(byteCount / 2);
|
||||
for (std::uint8_t i = 0; i + 1 < byteCount; i += 2) {
|
||||
vals.append(static_cast<std::uint16_t>((p[7 + i] << 8) | p[7 + i + 1]));
|
||||
}
|
||||
out = WriteMultipleRegistersRequest{unit, start, qty, std::move(vals)};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto parseWriteMultiResp = [&]() -> bool {
|
||||
if (n != 8 || !modbusRtuCrcOk(p, 8)) {
|
||||
return false;
|
||||
}
|
||||
const std::uint16_t start = static_cast<std::uint16_t>((p[2] << 8) | p[3]);
|
||||
const std::uint16_t qty = static_cast<std::uint16_t>((p[4] << 8) | p[5]);
|
||||
if (fc == 0x0F) {
|
||||
out = WriteMultipleCoilsResponse{unit, start, qty, {}};
|
||||
return true;
|
||||
}
|
||||
if (fc == 0x10) {
|
||||
out = WriteMultipleRegistersResponse{unit, start, qty, {}};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 功能 :解析Modbus的读取响应帧
|
||||
// function code range 01 02 03 04
|
||||
auto parseReadResp = [&]() -> bool {
|
||||
if (n < 5) {
|
||||
return false;
|
||||
}
|
||||
const std::uint8_t bc = p[2];
|
||||
const std::size_t total = static_cast<std::size_t>(5) + bc;
|
||||
if (n < total || !modbusRtuCrcOk(p, total)) {
|
||||
return false;
|
||||
}
|
||||
if (fc == 0x01) {
|
||||
QVector<std::uint8_t> coils;
|
||||
coils.reserve(bc);
|
||||
for (std::uint8_t i = 0; i < bc; ++i) {
|
||||
coils.append(p[3 + i]);
|
||||
}
|
||||
out = ReadCoilsResponse{unit, std::move(coils)};
|
||||
return true;
|
||||
}
|
||||
if (fc == 0x02) {
|
||||
QVector<std::uint8_t> inputs;
|
||||
inputs.reserve(bc);
|
||||
for (std::uint8_t i = 0; i < bc; ++i) {
|
||||
inputs.append(p[3 + i]);
|
||||
}
|
||||
out = ReadDiscreteInputsResponse{unit, std::move(inputs)};
|
||||
return true;
|
||||
}
|
||||
if (fc == 0x03 || fc == 0x04) {
|
||||
QVector<std::uint16_t> regs;
|
||||
regs.reserve(bc / 2);
|
||||
for (std::uint8_t i = 0; i + 1 < bc; i += 2) {
|
||||
regs.append(static_cast<std::uint16_t>((p[3 + i] << 8) | p[3 + i + 1]));
|
||||
}
|
||||
if (fc == 0x03) {
|
||||
out = ReadHoldingRegistersResponse{unit, std::move(regs)};
|
||||
} else {
|
||||
out = ReadInputRegistersResponse{unit, std::move(regs)};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// if (dir == BusDirection::Downstream) {
|
||||
// // 功能 :解析Modbus的下行请求帧
|
||||
// // function code range 01 02 03 04 05 06 0F 10
|
||||
// if (parseReadReq() || parseWriteSingleReqOrResp() || parseWriteMultiReq()) {
|
||||
// return true;
|
||||
// }
|
||||
// out = ModbusRtuUnsupportedPdu{unit, fc};
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (dir == BusDirection::Upstream) {
|
||||
// // 功能 :解析Modbus的上行响应帧
|
||||
// // function code range 01 02 03 04 05 06 0F 10
|
||||
// if (parseReadResp() || parseWriteSingleReqOrResp() || parseWriteMultiResp()) {
|
||||
// return true;
|
||||
// }
|
||||
// // 功能 :解析Modbus的下行请求帧
|
||||
// if (parseReadReq() || parseWriteMultiReq()) {
|
||||
// return true;
|
||||
// }
|
||||
// out = ModbusRtuUnsupportedPdu{unit, fc};
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (parseReadReq() || parseWriteSingleReqOrResp() || parseWriteMultiReq() || parseReadResp()
|
||||
|| parseWriteMultiResp()) {
|
||||
return true;
|
||||
}
|
||||
out = ModbusRtuUnsupportedPdu{unit, fc};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool encodeModbusRtu(const ModbusRtuPdu& pdu, QByteArray& out, QString* errMsg)
|
||||
{
|
||||
auto fail = [&](const char* msg) {
|
||||
if (errMsg) {
|
||||
*errMsg = QString::fromUtf8(msg);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
out.clear();
|
||||
|
||||
if (const auto* ex = std::get_if<ModbusExceptionPdu>(&pdu)) {
|
||||
out.append(static_cast<char>(ex->unitId));
|
||||
out.append(static_cast<char>(ex->function));
|
||||
out.append(static_cast<char>(ex->exceptionCode));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
auto encodeReadReq = [&](std::uint8_t unit, std::uint8_t fc, std::uint16_t start, std::uint16_t qty) {
|
||||
out.append(static_cast<char>(unit));
|
||||
out.append(static_cast<char>(fc));
|
||||
out.append(static_cast<char>((start >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(start & 0xFF));
|
||||
out.append(static_cast<char>((qty >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(qty & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
};
|
||||
auto encodeReadRegResp = [&](std::uint8_t unit, std::uint8_t fc, const QVector<std::uint16_t>& regs) {
|
||||
if (regs.size() > 127) {
|
||||
return false;
|
||||
}
|
||||
out.append(static_cast<char>(unit));
|
||||
out.append(static_cast<char>(fc));
|
||||
out.append(static_cast<char>(regs.size() * 2));
|
||||
for (std::uint16_t v : regs) {
|
||||
out.append(static_cast<char>((v >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(v & 0xFF));
|
||||
}
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
};
|
||||
auto encodeReadBitsResp = [&](std::uint8_t unit, std::uint8_t fc, const QVector<std::uint8_t>& bytes) {
|
||||
if (bytes.size() > 255) {
|
||||
return false;
|
||||
}
|
||||
out.append(static_cast<char>(unit));
|
||||
out.append(static_cast<char>(fc));
|
||||
out.append(static_cast<char>(bytes.size()));
|
||||
for (std::uint8_t b : bytes) {
|
||||
out.append(static_cast<char>(b));
|
||||
}
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
};
|
||||
if (const auto* req = std::get_if<ReadCoilsRequest>(&pdu)) {
|
||||
return encodeReadReq(req->unitId, 0x01, req->startAddress, req->quantity);
|
||||
}
|
||||
if (const auto* req = std::get_if<ReadDiscreteInputsRequest>(&pdu)) {
|
||||
return encodeReadReq(req->unitId, 0x02, req->startAddress, req->quantity);
|
||||
}
|
||||
if (const auto* req = std::get_if<ReadHoldingRegistersRequest>(&pdu)) {
|
||||
return encodeReadReq(req->unitId, 0x03, req->startAddress, req->quantity);
|
||||
}
|
||||
if (const auto* req = std::get_if<ReadInputRegistersRequest>(&pdu)) {
|
||||
return encodeReadReq(req->unitId, 0x04, req->startAddress, req->quantity);
|
||||
}
|
||||
if (const auto* resp = std::get_if<ReadHoldingRegistersResponse>(&pdu)) {
|
||||
if (!encodeReadRegResp(resp->unitId, 0x03, resp->registers)) {
|
||||
return fail("too_many_registers");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<ReadInputRegistersResponse>(&pdu)) {
|
||||
if (!encodeReadRegResp(resp->unitId, 0x04, resp->inputRegisters)) {
|
||||
return fail("too_many_registers");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<ReadCoilsResponse>(&pdu)) {
|
||||
if (!encodeReadBitsResp(resp->unitId, 0x01, resp->coils)) {
|
||||
return fail("too_many_bytes");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<ReadDiscreteInputsResponse>(&pdu)) {
|
||||
if (!encodeReadBitsResp(resp->unitId, 0x02, resp->discreteInputs)) {
|
||||
return fail("too_many_bytes");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (const auto* req = std::get_if<WriteSingleCoilRequest>(&pdu)) {
|
||||
out.append(static_cast<char>(req->unitId));
|
||||
out.append(static_cast<char>(0x05));
|
||||
out.append(static_cast<char>((req->address >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->address & 0xFF));
|
||||
const std::uint16_t coilWord = req->value ? 0xFF00 : 0x0000;
|
||||
out.append(static_cast<char>((coilWord >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(coilWord & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<WriteSingleCoilResponse>(&pdu)) {
|
||||
out.append(static_cast<char>(resp->unitId));
|
||||
out.append(static_cast<char>(0x05));
|
||||
out.append(static_cast<char>((resp->address >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->address & 0xFF));
|
||||
const std::uint16_t coilWord = resp->value ? 0xFF00 : 0x0000;
|
||||
out.append(static_cast<char>((coilWord >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(coilWord & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* req = std::get_if<WriteSingleRegisterRequest>(&pdu)) {
|
||||
out.append(static_cast<char>(req->unitId));
|
||||
out.append(static_cast<char>(0x06));
|
||||
out.append(static_cast<char>((req->address >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->address & 0xFF));
|
||||
out.append(static_cast<char>((req->value >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->value & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<WriteSingleRegisterResponse>(&pdu)) {
|
||||
out.append(static_cast<char>(resp->unitId));
|
||||
out.append(static_cast<char>(0x06));
|
||||
out.append(static_cast<char>((resp->address >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->address & 0xFF));
|
||||
out.append(static_cast<char>((resp->value >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->value & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* req = std::get_if<WriteMultipleCoilsRequest>(&pdu)) {
|
||||
if (req->values.size() > 255) {
|
||||
return fail("too_many_bytes");
|
||||
}
|
||||
out.append(static_cast<char>(req->unitId));
|
||||
out.append(static_cast<char>(0x0F));
|
||||
out.append(static_cast<char>((req->startAddress >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->startAddress & 0xFF));
|
||||
out.append(static_cast<char>((req->quantity >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->quantity & 0xFF));
|
||||
out.append(static_cast<char>(req->values.size()));
|
||||
for (std::uint8_t b : req->values) {
|
||||
out.append(static_cast<char>(b));
|
||||
}
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<WriteMultipleCoilsResponse>(&pdu)) {
|
||||
out.append(static_cast<char>(resp->unitId));
|
||||
out.append(static_cast<char>(0x0F));
|
||||
out.append(static_cast<char>((resp->startAddress >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->startAddress & 0xFF));
|
||||
out.append(static_cast<char>((resp->quantity >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->quantity & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* req = std::get_if<WriteMultipleRegistersRequest>(&pdu)) {
|
||||
if (req->values.size() > 127) {
|
||||
return fail("too_many_registers");
|
||||
}
|
||||
out.append(static_cast<char>(req->unitId));
|
||||
out.append(static_cast<char>(0x10));
|
||||
out.append(static_cast<char>((req->startAddress >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->startAddress & 0xFF));
|
||||
out.append(static_cast<char>((req->quantity >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(req->quantity & 0xFF));
|
||||
out.append(static_cast<char>(req->values.size() * 2));
|
||||
for (std::uint16_t v : req->values) {
|
||||
out.append(static_cast<char>((v >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(v & 0xFF));
|
||||
}
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
if (const auto* resp = std::get_if<WriteMultipleRegistersResponse>(&pdu)) {
|
||||
out.append(static_cast<char>(resp->unitId));
|
||||
out.append(static_cast<char>(0x10));
|
||||
out.append(static_cast<char>((resp->startAddress >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->startAddress & 0xFF));
|
||||
out.append(static_cast<char>((resp->quantity >> 8) & 0xFF));
|
||||
out.append(static_cast<char>(resp->quantity & 0xFF));
|
||||
appendCrcLe(out);
|
||||
return true;
|
||||
}
|
||||
return fail("unsupported_encode");
|
||||
}
|
||||
|
||||
} // namespace softbus::message_bus::pipeline::protocol
|
||||
27
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.h
Normal file
27
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
#include "message_bus/pipeline/protocol/modbusrtu/ModbusRtuPdu.h"
|
||||
|
||||
namespace softbus::message_bus::pipeline
|
||||
{
|
||||
enum class BusDirection;
|
||||
}
|
||||
|
||||
namespace softbus::message_bus::pipeline::protocol
|
||||
{
|
||||
|
||||
bool decodeModbusRtu(softbus::message_bus::pipeline::BusDirection dir,
|
||||
const std::uint8_t* p,
|
||||
std::size_t n,
|
||||
ModbusRtuPdu& out,
|
||||
QString* errMsg = nullptr);
|
||||
|
||||
bool encodeModbusRtu(const ModbusRtuPdu& pdu, QByteArray& out, QString* errMsg = nullptr);
|
||||
|
||||
} // namespace softbus::message_bus::pipeline::protocol
|
||||
304
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuPdu.h
Normal file
304
src/message_bus/pipeline/protocol/modbusrtu/ModbusRtuPdu.h
Normal file
@@ -0,0 +1,304 @@
|
||||
#pragma once
|
||||
// 定义ModbusRTU PDU 类型 包括
|
||||
// 异常响应、
|
||||
// 读保持寄存器请求、
|
||||
// 读保持寄存器响应、不支持的PDU
|
||||
#include <cstdint>
|
||||
|
||||
#include <QChar>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <type_traits>
|
||||
#include <variant> // 用于定义variant类型 variant类型可以存储多种类型的数据
|
||||
|
||||
namespace softbus::message_bus::pipeline::protocol
|
||||
{
|
||||
|
||||
struct ModbusExceptionPdu
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint8_t function{0};
|
||||
std::uint8_t exceptionCode{0};
|
||||
};
|
||||
// 01 功能码 读线圈
|
||||
struct ReadCoilsRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
};
|
||||
// 01 功能码 读线圈响应
|
||||
struct ReadCoilsResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
QVector<std::uint8_t> coils;
|
||||
};
|
||||
|
||||
// 02 功能码 读离散输入
|
||||
struct ReadDiscreteInputsRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
};
|
||||
// 02 功能码 读离散输入响应
|
||||
struct ReadDiscreteInputsResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
QVector<std::uint8_t> discreteInputs;
|
||||
};
|
||||
|
||||
// 03 功能码 读保持寄存器
|
||||
struct ReadHoldingRegistersRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
};
|
||||
|
||||
// 03 功能码 读保持寄存器响应
|
||||
struct ReadHoldingRegistersResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
QVector<std::uint16_t> registers;
|
||||
};
|
||||
|
||||
// 04 功能码 读输入寄存器
|
||||
struct ReadInputRegistersRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
};
|
||||
// 04 功能码 读输入寄存器响应
|
||||
struct ReadInputRegistersResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
QVector<std::uint16_t> inputRegisters;
|
||||
};
|
||||
|
||||
// 05 功能码 写单个线圈
|
||||
struct WriteSingleCoilRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t address{0};
|
||||
std::uint8_t value{0};
|
||||
};
|
||||
// 05 功能码 写单个线圈响应
|
||||
struct WriteSingleCoilResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t address{0};
|
||||
std::uint8_t value{0};
|
||||
};
|
||||
// 06 功能码 写单个寄存器
|
||||
struct WriteSingleRegisterRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t address{0};
|
||||
std::uint16_t value{0};
|
||||
};
|
||||
// 06 功能码 写单个寄存器响应
|
||||
struct WriteSingleRegisterResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t address{0};
|
||||
std::uint16_t value{0};
|
||||
};
|
||||
// 15 功能码 写多个线圈
|
||||
struct WriteMultipleCoilsRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
QVector<std::uint8_t> values;
|
||||
};
|
||||
// 15 功能码 写多个线圈响应
|
||||
struct WriteMultipleCoilsResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
QVector<std::uint8_t> values;
|
||||
};
|
||||
|
||||
// 16 功能码 写多个寄存器
|
||||
struct WriteMultipleRegistersRequest
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
QVector<std::uint16_t> values;
|
||||
};
|
||||
// 16 功能码 写多个寄存器响应
|
||||
struct WriteMultipleRegistersResponse
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint16_t startAddress{0};
|
||||
std::uint16_t quantity{0};
|
||||
QVector<std::uint16_t> values;
|
||||
};
|
||||
|
||||
struct ModbusRtuUnsupportedPdu
|
||||
{
|
||||
std::uint8_t unitId{0};
|
||||
std::uint8_t functionCode{0};
|
||||
};
|
||||
|
||||
using ModbusRtuPdu = std::variant<ModbusExceptionPdu,
|
||||
ReadCoilsRequest,
|
||||
ReadCoilsResponse,
|
||||
ReadDiscreteInputsRequest,
|
||||
ReadDiscreteInputsResponse,
|
||||
ReadHoldingRegistersRequest,
|
||||
ReadHoldingRegistersResponse,
|
||||
ReadInputRegistersRequest,
|
||||
ReadInputRegistersResponse,
|
||||
WriteSingleCoilRequest,
|
||||
WriteSingleCoilResponse,
|
||||
WriteSingleRegisterRequest,
|
||||
WriteSingleRegisterResponse,
|
||||
WriteMultipleCoilsRequest,
|
||||
WriteMultipleCoilsResponse,
|
||||
WriteMultipleRegistersRequest,
|
||||
WriteMultipleRegistersResponse,
|
||||
ModbusRtuUnsupportedPdu>;
|
||||
//
|
||||
|
||||
inline QString toText(const ModbusRtuPdu& pdu)
|
||||
{
|
||||
return std::visit([](const auto& value) -> QString {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
|
||||
auto bytesToHex = [](const QVector<std::uint8_t>& bytes) -> QString {
|
||||
QStringList parts;
|
||||
parts.reserve(bytes.size());
|
||||
for (const std::uint8_t b : bytes) {
|
||||
parts.push_back(QStringLiteral("0x%1").arg(b, 2, 16, QChar('0')));
|
||||
}
|
||||
return QStringLiteral("[%1]").arg(parts.join(QStringLiteral(", ")));
|
||||
};
|
||||
auto wordsToHex = [](const QVector<std::uint16_t>& words) -> QString {
|
||||
QStringList parts;
|
||||
parts.reserve(words.size());
|
||||
for (const std::uint16_t w : words) {
|
||||
parts.push_back(QStringLiteral("0x%1").arg(w, 4, 16, QChar('0')));
|
||||
}
|
||||
return QStringLiteral("[%1]").arg(parts.join(QStringLiteral(", ")));
|
||||
};
|
||||
|
||||
if constexpr (std::is_same_v<T, ModbusExceptionPdu>) {
|
||||
return QStringLiteral("ModbusExceptionPdu: unitId=%1, function=0x%2, exceptionCode=0x%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.function, 2, 16, QChar('0'))
|
||||
.arg(value.exceptionCode, 2, 16, QChar('0'));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadCoilsRequest>) {
|
||||
const ReadCoilsRequest& request = value;
|
||||
return QStringLiteral("ReadCoilsRequest: unitId=%1, startAddress=%2, quantity=%3")
|
||||
.arg(request.unitId)
|
||||
.arg(request.startAddress)
|
||||
.arg(request.quantity);
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadCoilsResponse>) {
|
||||
return QStringLiteral("ReadCoilsResponse: unitId=%1, coils=%2")
|
||||
.arg(value.unitId)
|
||||
.arg(bytesToHex(value.coils));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadDiscreteInputsRequest>) {
|
||||
return QStringLiteral("ReadDiscreteInputsRequest: unitId=%1, startAddress=%2, quantity=%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity);
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadDiscreteInputsResponse>) {
|
||||
return QStringLiteral("ReadDiscreteInputsResponse: unitId=%1, discreteInputs=%2")
|
||||
.arg(value.unitId)
|
||||
.arg(bytesToHex(value.discreteInputs));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadHoldingRegistersRequest>) {
|
||||
return QStringLiteral("ReadHoldingRegistersRequest: unitId=%1, startAddress=%2, quantity=%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity);
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadHoldingRegistersResponse>) {
|
||||
return QStringLiteral("ReadHoldingRegistersResponse: unitId=%1, registers=%2")
|
||||
.arg(value.unitId)
|
||||
.arg(wordsToHex(value.registers));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadInputRegistersRequest>) {
|
||||
return QStringLiteral("ReadInputRegistersRequest: unitId=%1, startAddress=%2, quantity=%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity);
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ReadInputRegistersResponse>) {
|
||||
return QStringLiteral("ReadInputRegistersResponse: unitId=%1, inputRegisters=%2")
|
||||
.arg(value.unitId)
|
||||
.arg(wordsToHex(value.inputRegisters));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteSingleCoilRequest>) {
|
||||
return QStringLiteral("WriteSingleCoilRequest: unitId=%1, address=%2, value=0x%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.address)
|
||||
.arg(value.value, 2, 16, QChar('0'));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteSingleCoilResponse>) {
|
||||
return QStringLiteral("WriteSingleCoilResponse: unitId=%1, address=%2, value=0x%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.address)
|
||||
.arg(value.value, 2, 16, QChar('0'));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteSingleRegisterRequest>) {
|
||||
return QStringLiteral("WriteSingleRegisterRequest: unitId=%1, address=%2, value=0x%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.address)
|
||||
.arg(value.value, 4, 16, QChar('0'));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteSingleRegisterResponse>) {
|
||||
return QStringLiteral("WriteSingleRegisterResponse: unitId=%1, address=%2, value=0x%3")
|
||||
.arg(value.unitId)
|
||||
.arg(value.address)
|
||||
.arg(value.value, 4, 16, QChar('0'));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteMultipleCoilsRequest>) {
|
||||
return QStringLiteral("WriteMultipleCoilsRequest: unitId=%1, startAddress=%2, quantity=%3, values=%4")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity)
|
||||
.arg(bytesToHex(value.values));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteMultipleCoilsResponse>) {
|
||||
return QStringLiteral("WriteMultipleCoilsResponse: unitId=%1, startAddress=%2, quantity=%3, values=%4")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity)
|
||||
.arg(bytesToHex(value.values));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteMultipleRegistersRequest>) {
|
||||
return QStringLiteral("WriteMultipleRegistersRequest: unitId=%1, startAddress=%2, quantity=%3, values=%4")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity)
|
||||
.arg(wordsToHex(value.values));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, WriteMultipleRegistersResponse>) {
|
||||
return QStringLiteral("WriteMultipleRegistersResponse: unitId=%1, startAddress=%2, quantity=%3, values=%4")
|
||||
.arg(value.unitId)
|
||||
.arg(value.startAddress)
|
||||
.arg(value.quantity)
|
||||
.arg(wordsToHex(value.values));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, ModbusRtuUnsupportedPdu>) {
|
||||
return QStringLiteral("ModbusRtuUnsupportedPdu: unitId=%1, functionCode=0x%2")
|
||||
.arg(value.unitId)
|
||||
.arg(value.functionCode, 2, 16, QChar('0'));
|
||||
}
|
||||
return QStringLiteral("Unknown");
|
||||
}, pdu);
|
||||
}
|
||||
|
||||
} // namespace softbus::message_bus::pipeline::protocol
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include "message_bus/pipeline/protocol/modbusrtu/ModbusRtuProtocolPlugin.h"
|
||||
|
||||
#include "core/plugin_system/IProtocolPlugin.h"
|
||||
#include "message_bus/pipeline/PipelineContext.h"
|
||||
#include "message_bus/pipeline/protocol/ProtocolEnvelope.h"
|
||||
#include "message_bus/pipeline/protocol/modbusrtu/ModbusRtuCodec.h"
|
||||
#include "message_bus/pipeline/stages/1_framers/ModbusRtuFraming.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace softbus::core::plugin_system
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using softbus::message_bus::pipeline::protocol::ModbusExceptionPdu;
|
||||
using softbus::message_bus::pipeline::protocol::ModbusRtuPdu;
|
||||
using softbus::message_bus::pipeline::protocol::ModbusRtuUnsupportedPdu;
|
||||
using softbus::message_bus::pipeline::protocol::ProtocolFamily;
|
||||
using softbus::message_bus::pipeline::protocol::ReadCoilsRequest;
|
||||
using softbus::message_bus::pipeline::protocol::ReadCoilsResponse;
|
||||
using softbus::message_bus::pipeline::protocol::ReadDiscreteInputsRequest;
|
||||
using softbus::message_bus::pipeline::protocol::ReadDiscreteInputsResponse;
|
||||
using softbus::message_bus::pipeline::protocol::ReadHoldingRegistersRequest;
|
||||
using softbus::message_bus::pipeline::protocol::ReadHoldingRegistersResponse;
|
||||
using softbus::message_bus::pipeline::protocol::ReadInputRegistersRequest;
|
||||
using softbus::message_bus::pipeline::protocol::ReadInputRegistersResponse;
|
||||
using softbus::message_bus::pipeline::protocol::WriteSingleCoilRequest;
|
||||
using softbus::message_bus::pipeline::protocol::WriteSingleCoilResponse;
|
||||
using softbus::message_bus::pipeline::protocol::WriteSingleRegisterRequest;
|
||||
using softbus::message_bus::pipeline::protocol::WriteSingleRegisterResponse;
|
||||
using softbus::message_bus::pipeline::protocol::WriteMultipleCoilsRequest;
|
||||
using softbus::message_bus::pipeline::protocol::WriteMultipleCoilsResponse;
|
||||
using softbus::message_bus::pipeline::protocol::WriteMultipleRegistersRequest;
|
||||
using softbus::message_bus::pipeline::protocol::WriteMultipleRegistersResponse;
|
||||
using softbus::message_bus::pipeline::protocol::decodeModbusRtu;
|
||||
|
||||
template <class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
template <class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
void syncLegacyJson(const ModbusRtuPdu& pdu, QJsonObject& o)
|
||||
{
|
||||
o = QJsonObject();
|
||||
std::visit(
|
||||
overloaded{
|
||||
[&](const ModbusExceptionPdu& e) {
|
||||
o.insert(QStringLiteral("unitId"), e.unitId);
|
||||
o.insert(QStringLiteral("function"), e.function);
|
||||
o.insert(QStringLiteral("exceptionCode"), e.exceptionCode);
|
||||
o.insert(QStringLiteral("exception"), true);
|
||||
},
|
||||
[&](const ReadHoldingRegistersResponse& r) {
|
||||
QJsonArray regs;
|
||||
for (std::uint16_t v : r.registers) {
|
||||
regs.append(static_cast<int>(v));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 3);
|
||||
o.insert(QStringLiteral("byteCount"), r.registers.size() * 2);
|
||||
o.insert(QStringLiteral("registers"), regs);
|
||||
},
|
||||
[&](const ReadHoldingRegistersRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 3);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const ReadCoilsRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 1);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const ReadDiscreteInputsRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 2);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const ReadInputRegistersRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 4);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const ReadCoilsResponse& r) {
|
||||
QJsonArray bits;
|
||||
for (std::uint8_t b : r.coils) {
|
||||
bits.append(static_cast<int>(b));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 1);
|
||||
o.insert(QStringLiteral("byteCount"), r.coils.size());
|
||||
o.insert(QStringLiteral("coils"), bits);
|
||||
},
|
||||
[&](const ReadDiscreteInputsResponse& r) {
|
||||
QJsonArray bits;
|
||||
for (std::uint8_t b : r.discreteInputs) {
|
||||
bits.append(static_cast<int>(b));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 2);
|
||||
o.insert(QStringLiteral("byteCount"), r.discreteInputs.size());
|
||||
o.insert(QStringLiteral("discreteInputs"), bits);
|
||||
},
|
||||
[&](const ReadInputRegistersResponse& r) {
|
||||
QJsonArray regs;
|
||||
for (std::uint16_t v : r.inputRegisters) {
|
||||
regs.append(static_cast<int>(v));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 4);
|
||||
o.insert(QStringLiteral("byteCount"), r.inputRegisters.size() * 2);
|
||||
o.insert(QStringLiteral("inputRegisters"), regs);
|
||||
},
|
||||
[&](const WriteSingleCoilRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 5);
|
||||
o.insert(QStringLiteral("address"), r.address);
|
||||
o.insert(QStringLiteral("value"), r.value);
|
||||
},
|
||||
[&](const WriteSingleCoilResponse& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 5);
|
||||
o.insert(QStringLiteral("address"), r.address);
|
||||
o.insert(QStringLiteral("value"), r.value);
|
||||
},
|
||||
[&](const WriteSingleRegisterRequest& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 6);
|
||||
o.insert(QStringLiteral("address"), r.address);
|
||||
o.insert(QStringLiteral("value"), r.value);
|
||||
},
|
||||
[&](const WriteSingleRegisterResponse& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 6);
|
||||
o.insert(QStringLiteral("address"), r.address);
|
||||
o.insert(QStringLiteral("value"), r.value);
|
||||
},
|
||||
[&](const WriteMultipleCoilsRequest& r) {
|
||||
QJsonArray vals;
|
||||
for (std::uint8_t b : r.values) {
|
||||
vals.append(static_cast<int>(b));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 15);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
o.insert(QStringLiteral("values"), vals);
|
||||
},
|
||||
[&](const WriteMultipleCoilsResponse& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 15);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const WriteMultipleRegistersRequest& r) {
|
||||
QJsonArray vals;
|
||||
for (std::uint16_t v : r.values) {
|
||||
vals.append(static_cast<int>(v));
|
||||
}
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 16);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
o.insert(QStringLiteral("values"), vals);
|
||||
},
|
||||
[&](const WriteMultipleRegistersResponse& r) {
|
||||
o.insert(QStringLiteral("unitId"), r.unitId);
|
||||
o.insert(QStringLiteral("function"), 16);
|
||||
o.insert(QStringLiteral("startAddress"), r.startAddress);
|
||||
o.insert(QStringLiteral("quantity"), r.quantity);
|
||||
},
|
||||
[&](const ModbusRtuUnsupportedPdu&) {},
|
||||
[&](const auto&) {}},
|
||||
pdu);
|
||||
}
|
||||
|
||||
class ModbusRtuSession final : public IProtocolSession
|
||||
{
|
||||
public:
|
||||
bool feed(softbus::message_bus::pipeline::PipelineContext& ctx) override
|
||||
{
|
||||
using softbus::message_bus::pipeline::FrameKind;
|
||||
if (ctx.frameKind != FrameKind::CompleteFrame || !ctx.payload.valid()) {
|
||||
return false;
|
||||
}
|
||||
const std::size_t n = ctx.payloadSize ? ctx.payloadSize : ctx.payload.length;
|
||||
const std::uint8_t* p = ctx.payload.bytes();
|
||||
if (!p || n < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ModbusRtuPdu pdu;
|
||||
if (!decodeModbusRtu(ctx.direction, p, n, pdu, nullptr)) {
|
||||
ctx.protocol.family = ProtocolFamily::None;
|
||||
ctx.protocol.pdu = {};
|
||||
ctx.parsed = QJsonObject();
|
||||
return false;
|
||||
}
|
||||
ctx.protocol.family = ProtocolFamily::ModbusRtu;
|
||||
ctx.protocol.pdu = pdu;
|
||||
syncLegacyJson(pdu, ctx.parsed);
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset() override {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class ModbusRtuProtocolPlugin final : public IProtocolPlugin
|
||||
{
|
||||
public:
|
||||
QString pluginId() const override { return QStringLiteral("modbus_rtu"); }
|
||||
|
||||
bool supports(const QString& protocolHint) const override
|
||||
{
|
||||
return softbus::message_bus::pipeline::stages::framers::protocolHintIsModbusRtu(protocolHint);
|
||||
}
|
||||
|
||||
std::unique_ptr<IProtocolSession> createSession() override
|
||||
{
|
||||
return std::make_unique<ModbusRtuSession>();
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<IProtocolPlugin> makeModbusRtuProtocolPlugin()
|
||||
{
|
||||
return std::make_shared<ModbusRtuProtocolPlugin>();
|
||||
}
|
||||
|
||||
} // namespace softbus::core::plugin_system
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/plugin_system/IProtocolPlugin.h"
|
||||
|
||||
namespace softbus::core::plugin_system
|
||||
{
|
||||
|
||||
std::shared_ptr<IProtocolPlugin> makeModbusRtuProtocolPlugin();
|
||||
|
||||
} // namespace softbus::core::plugin_system
|
||||
Reference in New Issue
Block a user