modbus rtu 1.1 plugins
This commit is contained in:
@@ -5,9 +5,6 @@
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
#include "plugins/protocols/modbusrtu/framer/ModbusRtuFraming.h"
|
||||
#include "plugins/protocols/modbusrtu/framer/ModbusRtuFramerPlugin.h"
|
||||
#include "message_bus/pipeline/stages/3_filters/ProtocolParseFilter.h"
|
||||
#include "utils/logs/logging.h"
|
||||
|
||||
@@ -91,9 +88,6 @@ void PipelineEngine::loadRuntimeConfigFromJson(const QJsonObject& obj)
|
||||
std::max(64, obj.value(QStringLiteral("framedQueueMax")).toInt(4096)));
|
||||
m_rtConfig.maxReorderDepth = static_cast<std::size_t>(
|
||||
std::max(16, obj.value(QStringLiteral("maxReorderDepth")).toInt(256)));
|
||||
m_rtConfig.modbusMaxAdu = static_cast<std::size_t>(
|
||||
std::max(8, obj.value(QStringLiteral("modbusRtuMaxFrameBytes")).toInt(256)));
|
||||
m_rtConfig.modbusInterFrameTimeoutMs = obj.value(QStringLiteral("modbusRtuInterFrameTimeoutMs")).toInt(0);
|
||||
}
|
||||
|
||||
void PipelineEngine::start()
|
||||
@@ -110,13 +104,6 @@ void PipelineEngine::start()
|
||||
|
||||
m_passthroughFramer =
|
||||
std::make_shared<softbus::message_bus::pipeline::stages::framers::PassthroughFramer>(m_pool);
|
||||
if (m_pluginManager) {
|
||||
softbus::message_bus::pipeline::protocol::modbusrtu::ModbusRtuFramerPluginConfig cfg;
|
||||
cfg.maxAdu = m_rtConfig.modbusMaxAdu;
|
||||
cfg.interFrameTimeoutMs = m_rtConfig.modbusInterFrameTimeoutMs;
|
||||
m_pluginManager->registerProtocolFramerPlugin(
|
||||
softbus::message_bus::pipeline::protocol::modbusrtu::makeModbusRtuFramerPlugin(m_pool, cfg));
|
||||
}
|
||||
|
||||
// 如果启用并行管道 则创建帧队列和解析线程 如果启用有序出口 则创建合并队列和合并线程
|
||||
// 并行管道是用来处理多个端点的数据流的
|
||||
@@ -183,6 +170,14 @@ void PipelineEngine::stop()
|
||||
std::lock_guard<std::mutex> lk(m_framerSessionMutex);
|
||||
m_framerSessions.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_parserSessionMutex);
|
||||
m_parserSessions.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mapperSessionMutex);
|
||||
m_mapperSessions.clear();
|
||||
}
|
||||
}
|
||||
// 功能 :清空 ingress 队列
|
||||
// 参数 :无
|
||||
@@ -294,10 +289,7 @@ void PipelineEngine::dispatchFramer(PipelineContext& chunkIn, std::vector<Pipeli
|
||||
std::lock_guard<std::mutex> lk(m_framerSessionMutex);
|
||||
auto it = m_framerSessions.find(key);
|
||||
if (it == m_framerSessions.end() || !it.value()) {
|
||||
QJsonObject params;
|
||||
params.insert(QStringLiteral("modbusRtuMaxFrameBytes"), static_cast<int>(m_rtConfig.modbusMaxAdu));
|
||||
params.insert(QStringLiteral("modbusRtuInterFrameTimeoutMs"), m_rtConfig.modbusInterFrameTimeoutMs);
|
||||
auto s = plugin->createFramerSession(chunkIn.endpoint, params);
|
||||
auto s = plugin->createFramerSession(chunkIn.endpoint, QJsonObject{});
|
||||
m_framerSessions.insert(
|
||||
key, s ? std::shared_ptr<softbus::core::plugin_system::IProtocolFramerSession>(std::move(s)) : nullptr);
|
||||
it = m_framerSessions.find(key);
|
||||
@@ -454,44 +446,19 @@ bool PipelineEngine::runStages234(PipelineContext& ctx)
|
||||
if (ctx.frameKind != FrameKind::CompleteFrame) {
|
||||
return false;
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setfill('0');
|
||||
for (std::size_t i = 0; i < ctx.payload.block->size; ++i) {
|
||||
oss << std::setw(2) << static_cast<int>(ctx.payload.block->data[i]);
|
||||
if (i + 1 < ctx.payload.block->size) {
|
||||
oss << ' ';
|
||||
auto messages = stage2Parser(ctx);
|
||||
LOG_INFO() << "PipelineEngine: stage2Parser messages size=" << messages.size();
|
||||
if (messages.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto& msg : messages) {
|
||||
if (!stage3Filter(msg)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const QString hexPreview = QString::fromStdString(oss.str());
|
||||
LOG_INFO() << "the data is"<< hexPreview;
|
||||
LOG_INFO() << "the protocol hint is"<< ctx.protocolHint;
|
||||
const QString directionText = (ctx.direction == BusDirection::Upstream)
|
||||
? QStringLiteral("Upstream")
|
||||
: (ctx.direction == BusDirection::Downstream)
|
||||
? QStringLiteral("Downstream")
|
||||
: QStringLiteral("Unknown");
|
||||
LOG_INFO() << "the direction is" << directionText;
|
||||
if (!stage2Parser(ctx)) {
|
||||
return false;
|
||||
}
|
||||
QJsonObject parsed = ctx.parsed;
|
||||
LOG_INFO() << "the parsed is"<< parsed;
|
||||
|
||||
softbus::message_bus::pipeline::protocol::ProtocolEnvelope protocol = ctx.protocol;
|
||||
if (const auto* modbusPdu = std::get_if<softbus::message_bus::pipeline::protocol::ModbusRtuPdu>(&protocol.pdu)) {
|
||||
LOG_INFO() << "the protocol text is" << softbus::message_bus::pipeline::protocol::toText(*modbusPdu);
|
||||
} else {
|
||||
LOG_INFO() << "the protocol text is" << QStringLiteral("ProtocolEnvelopePdu::monostate");
|
||||
}
|
||||
// @TODO 以后需要测试是否丢包和解析延迟
|
||||
// m_count++;
|
||||
// LOG_INFO() << "the count of command is" << m_count;
|
||||
|
||||
if (!stage3Filter(ctx)) {
|
||||
return false;
|
||||
}
|
||||
if (!stage4Validator(ctx)) {
|
||||
return false;
|
||||
if (!stage4Validator(msg)) {
|
||||
continue;
|
||||
}
|
||||
(void)applyTransformAndEnrich(ctx, msg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -500,47 +467,97 @@ bool PipelineEngine::runStages234(PipelineContext& ctx)
|
||||
// 参数 :ctx 数据
|
||||
// 返回值 :是否成功
|
||||
// 逻辑 :如果有效载荷无效 则返回false 如果都成功 则返回true
|
||||
bool PipelineEngine::stage4Validator(PipelineContext& ctx)
|
||||
bool PipelineEngine::stage4Validator(const softbus::core::models::DOMMessage& message) const
|
||||
{
|
||||
if (!ctx.payload.valid()) {
|
||||
return false;
|
||||
}
|
||||
if (ctx.endpoint.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!ctx.timestamp.isValid()) {
|
||||
ctx.timestamp = QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
if (ctx.frameKind != FrameKind::CompleteFrame) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !message.messageId.isEmpty();
|
||||
}
|
||||
|
||||
// 功能 :运行阶段2解析器
|
||||
// 参数 :ctx 数据
|
||||
// 返回值 :是否成功
|
||||
// 逻辑 :如果插件管理器为空 则返回true 如果插件管理器不为空 则选择合适的插件 创建会话 如果会话为空 则返回false 如果会话不为空 则返回true
|
||||
bool PipelineEngine::stage2Parser(PipelineContext& ctx)
|
||||
std::vector<softbus::core::models::DOMMessage> PipelineEngine::stage2Parser(const PipelineContext& ctx)
|
||||
{
|
||||
if (!m_pluginManager) {
|
||||
return true;
|
||||
return {};
|
||||
}
|
||||
auto plugin = m_pluginManager->selectProtocolPlugin(ctx.protocolHint);
|
||||
if (!plugin) {
|
||||
return true;
|
||||
auto parserPlugin = m_pluginManager->selectProtocolPlugin(ctx.protocolHint);
|
||||
if (!parserPlugin) {
|
||||
return {};
|
||||
}
|
||||
auto session = plugin->createSession();
|
||||
if (!session) {
|
||||
return false;
|
||||
const QString parserKey = ctx.endpoint + QStringLiteral("|") + parserPlugin->pluginId();
|
||||
std::shared_ptr<softbus::core::plugin_system::IProtocolSession> parserSession;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_parserSessionMutex);
|
||||
auto it = m_parserSessions.find(parserKey);
|
||||
if (it == m_parserSessions.end() || !it.value()) {
|
||||
auto s = parserPlugin->createSession();
|
||||
m_parserSessions.insert(
|
||||
parserKey,
|
||||
s ? std::shared_ptr<softbus::core::plugin_system::IProtocolSession>(std::move(s)) : nullptr);
|
||||
it = m_parserSessions.find(parserKey);
|
||||
}
|
||||
if (it == m_parserSessions.end() || !it.value()) {
|
||||
return {};
|
||||
}
|
||||
parserSession = it.value();
|
||||
}
|
||||
return session->feed(ctx);
|
||||
softbus::message_bus::pipeline::protocol::ProtocolEnvelope envelope; // 协议封装
|
||||
if (!parserSession->parse(ctx, envelope)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto mapperPlugin = m_pluginManager->selectProtocolMapperPlugin(ctx.protocolHint);
|
||||
if (!mapperPlugin) {
|
||||
return {};
|
||||
}
|
||||
const QString key = ctx.endpoint + QStringLiteral("|") + mapperPlugin->pluginId();
|
||||
std::shared_ptr<softbus::core::plugin_system::IProtocolMapperSession> session;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mapperSessionMutex);
|
||||
auto it = m_mapperSessions.find(key);
|
||||
if (it == m_mapperSessions.end() || !it.value()) {
|
||||
auto s = mapperPlugin->createMapperSession();
|
||||
m_mapperSessions.insert(
|
||||
key,
|
||||
s ? std::shared_ptr<softbus::core::plugin_system::IProtocolMapperSession>(std::move(s)) : nullptr);
|
||||
it = m_mapperSessions.find(key);
|
||||
}
|
||||
if (it == m_mapperSessions.end() || !it.value()) {
|
||||
return {};
|
||||
}
|
||||
session = it.value();
|
||||
}
|
||||
return session->map(ctx, envelope);
|
||||
}
|
||||
|
||||
bool PipelineEngine::stage3Filter(PipelineContext& ctx)
|
||||
bool PipelineEngine::stage3Filter(softbus::core::models::DOMMessage& message)
|
||||
{
|
||||
static softbus::message_bus::pipeline::stages::filters::ProtocolParseFilter s_filter;
|
||||
return s_filter.apply(ctx);
|
||||
return s_filter.process(message);
|
||||
}
|
||||
|
||||
softbus::core::models::EnrichedMessage PipelineEngine::applyTransformAndEnrich(
|
||||
const PipelineContext& rawCtx, softbus::core::models::DOMMessage& message) const
|
||||
{
|
||||
auto rules = softbus::message_bus::pipeline::DynamicRuleRegistry::instance().snapshotTransformRules(
|
||||
rawCtx.endpoint, rawCtx.deviceId, rawCtx.stableKey);
|
||||
for (const auto& rule : rules) {
|
||||
const double base = std::visit([](const auto& x) { return static_cast<double>(x); }, message.value);
|
||||
const double next = base * rule.scale + rule.offset;
|
||||
if (next != base) {
|
||||
message.appendTrace(QStringLiteral("transform:%1 %2->%3")
|
||||
.arg(rule.id)
|
||||
.arg(base, 0, 'g', 12)
|
||||
.arg(next, 0, 'g', 12));
|
||||
}
|
||||
message.value = next;
|
||||
if (!rule.unit.isEmpty()) {
|
||||
message.attributes.insert(QStringLiteral("unit"), rule.unit);
|
||||
}
|
||||
}
|
||||
static softbus::message_bus::pipeline::stages::filters::ProtocolParseFilter s_filter;
|
||||
return s_filter.enrich(message);
|
||||
}
|
||||
|
||||
} // namespace softbus::message_bus::pipeline
|
||||
|
||||
Reference in New Issue
Block a user