250 lines
10 KiB
C++
250 lines
10 KiB
C++
#include "plugins/protocols/modbusrtu/parser/ModbusRtuProtocolPlugin.h"
|
|
|
|
#include "core/plugin_system/IProtocolPlugin.h"
|
|
#include "message_bus/pipeline/PipelineContext.h"
|
|
#include "message_bus/pipeline/protocol/ProtocolEnvelope.h"
|
|
#include "plugins/protocols/modbusrtu/codec/ModbusRtuCodec.h"
|
|
#include "plugins/protocols/modbusrtu/framer/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::protocol::modbusrtu::isModbusRtuHint(protocolHint);
|
|
}
|
|
|
|
std::unique_ptr<IProtocolSession> createSession() override
|
|
{
|
|
return std::make_unique<ModbusRtuSession>();
|
|
}
|
|
};
|
|
|
|
std::shared_ptr<IProtocolPlugin> makeModbusRtuProtocolPlugin()
|
|
{
|
|
return std::make_shared<ModbusRtuProtocolPlugin>();
|
|
}
|
|
|
|
IProtocolPlugin* createModbusRtuProtocolPluginRaw()
|
|
{
|
|
return new ModbusRtuProtocolPlugin();
|
|
}
|
|
|
|
} // namespace softbus::core::plugin_system
|