177 lines
6.1 KiB
C++
177 lines
6.1 KiB
C++
#include "plugins/protocols/modbus_rtu/framer/ModbusRtuFramerPlugin.h"
|
||
|
||
#include <algorithm>
|
||
#include <cstring>
|
||
|
||
#include "plugins/protocols/modbus_rtu/framer/ModbusRtuFraming.h"
|
||
#include "utils/logs/logging.h"
|
||
|
||
namespace softbus::message_bus::pipeline::protocol::modbusrtu
|
||
{
|
||
|
||
namespace
|
||
{
|
||
|
||
class ModbusRtuFramerSession final : public softbus::core::plugin_system::IProtocolFramerSession
|
||
{
|
||
public:
|
||
ModbusRtuFramerSession(std::shared_ptr<softbus::core::memory::MemoryPool> pool,
|
||
ModbusRtuFramerPluginConfig cfg,
|
||
std::uint32_t endpointHash)
|
||
: m_pool(std::move(pool))
|
||
, m_cfg(cfg)
|
||
, m_endpointHash(endpointHash)
|
||
{
|
||
m_buf.resize(m_cfg.maxAdu);
|
||
}
|
||
// 功能 : 处理收到的数据块
|
||
void feedChunk(softbus::core::models::RawBusMessage& in,
|
||
std::vector<softbus::core::models::RawBusMessage>& out) override
|
||
{
|
||
if (!m_pool || !in.payload.valid()) {
|
||
return;
|
||
}
|
||
const std::uint8_t* p = in.payload.bytes();
|
||
const std::size_t n = in.payload.length;
|
||
if (!p || n == 0) {
|
||
return;
|
||
}
|
||
m_lastRx = std::chrono::steady_clock::now();
|
||
|
||
if (m_cfg.interFrameTimeoutMs > 0 && m_len > 0) {
|
||
const auto age = std::chrono::duration_cast<std::chrono::milliseconds>(m_lastRx - m_lastActivity).count();
|
||
if (age >= m_cfg.interFrameTimeoutMs) {
|
||
m_len = 0;
|
||
}
|
||
}
|
||
m_lastActivity = m_lastRx;
|
||
|
||
if (m_len + n > m_cfg.maxAdu) {
|
||
// 功能 : 如果数据块超过最大长度,则丢弃
|
||
LOG_WARNING() << "ModbusRtuFramerPlugin: overflow endpointHash=0x"
|
||
<< QString::number(m_endpointHash, 16);
|
||
m_len = 0;
|
||
return;
|
||
}
|
||
std::memcpy(m_buf.data() + m_len, p, n);
|
||
m_len += n;
|
||
|
||
while (m_len > 0) {
|
||
auto pred = predictAduLength(m_buf.data(), m_len, m_cfg.maxAdu);
|
||
if (!pred || m_len < *pred) {
|
||
break;
|
||
}
|
||
if (!crcOk(m_buf.data(), *pred)) {
|
||
if (m_len <= 1) {
|
||
m_len = 0;
|
||
break;
|
||
}
|
||
std::memmove(m_buf.data(), m_buf.data() + 1, m_len - 1);
|
||
--m_len;
|
||
continue;
|
||
}
|
||
|
||
auto blk = m_pool->allocate(*pred);
|
||
if (!blk || !blk->data || blk->capacity < *pred) {
|
||
return;
|
||
}
|
||
std::memcpy(blk->data, m_buf.data(), *pred);
|
||
blk->size = *pred;
|
||
|
||
softbus::core::models::RawBusMessage framed;
|
||
framed.deviceId = in.deviceId;
|
||
framed.endpointHash = in.endpointHash;
|
||
framed.protocol = softbus::core::models::ProtocolType::MODBUS_RTU;
|
||
framed.logicalAddress = in.logicalAddress;
|
||
framed.routingKey = in.routingKey;
|
||
framed.header = in.header;
|
||
framed.timestampMs = in.timestampMs;
|
||
framed.traceId = in.traceId;
|
||
framed.direction = in.direction;
|
||
framed.payload.block = std::move(blk);
|
||
framed.payload.offset = 0;
|
||
framed.payload.length = *pred;
|
||
if (*pred >= 2 && framed.payload.block && framed.payload.block->data) {
|
||
framed.header.modbus.slaveId = framed.payload.block->data[0];
|
||
framed.header.modbus.functionCode = framed.payload.block->data[1];
|
||
framed.logicalAddress = framed.header.modbus.slaveId;
|
||
}
|
||
out.push_back(std::move(framed));
|
||
|
||
const std::size_t rest = m_len - *pred;
|
||
if (rest > 0) {
|
||
std::memmove(m_buf.data(), m_buf.data() + *pred, rest);
|
||
}
|
||
m_len = rest;
|
||
}
|
||
|
||
in.payload = {};
|
||
}
|
||
|
||
void reset() override { m_len = 0; }
|
||
void shutdown() override { m_len = 0; }
|
||
|
||
private:
|
||
std::shared_ptr<softbus::core::memory::MemoryPool> m_pool;
|
||
ModbusRtuFramerPluginConfig m_cfg;
|
||
std::uint32_t m_endpointHash{0};
|
||
std::vector<std::uint8_t> m_buf;
|
||
std::size_t m_len{0};
|
||
std::chrono::steady_clock::time_point m_lastRx{std::chrono::steady_clock::now()};
|
||
std::chrono::steady_clock::time_point m_lastActivity{std::chrono::steady_clock::now()};
|
||
};
|
||
|
||
} // namespace
|
||
|
||
ModbusRtuFramerPlugin::ModbusRtuFramerPlugin(std::shared_ptr<softbus::core::memory::MemoryPool> pool,
|
||
ModbusRtuFramerPluginConfig cfg)
|
||
: m_pool(std::move(pool))
|
||
, m_cfg(cfg)
|
||
{
|
||
}
|
||
|
||
QString ModbusRtuFramerPlugin::pluginId() const
|
||
{
|
||
return QStringLiteral("modbus_rtu_framer");
|
||
}
|
||
|
||
softbus::core::models::ProtocolType ModbusRtuFramerPlugin::protocolType() const
|
||
{
|
||
return softbus::core::models::ProtocolType::MODBUS_RTU;
|
||
}
|
||
|
||
void ModbusRtuFramerPlugin::bindMemoryPool(std::shared_ptr<softbus::core::memory::MemoryPool> pool)
|
||
{
|
||
m_pool = std::move(pool);
|
||
}
|
||
|
||
std::unique_ptr<softbus::core::plugin_system::IProtocolFramerSession>
|
||
ModbusRtuFramerPlugin::createFramerSession(std::uint32_t endpointHash, const QJsonObject& params)
|
||
{
|
||
if (!m_pool) {
|
||
return {};
|
||
}
|
||
ModbusRtuFramerPluginConfig cfg = m_cfg;
|
||
if (params.contains(QStringLiteral("modbusRtuMaxFrameBytes"))) {
|
||
cfg.maxAdu = static_cast<std::size_t>(
|
||
std::max(8, params.value(QStringLiteral("modbusRtuMaxFrameBytes")).toInt(static_cast<int>(cfg.maxAdu))));
|
||
}
|
||
if (params.contains(QStringLiteral("modbusRtuInterFrameTimeoutMs"))) {
|
||
cfg.interFrameTimeoutMs = params.value(QStringLiteral("modbusRtuInterFrameTimeoutMs")).toInt(cfg.interFrameTimeoutMs);
|
||
}
|
||
return std::make_unique<ModbusRtuFramerSession>(m_pool, cfg, endpointHash);
|
||
}
|
||
|
||
std::shared_ptr<softbus::core::plugin_system::IProtocolFramerPlugin> makeModbusRtuFramerPlugin(
|
||
std::shared_ptr<softbus::core::memory::MemoryPool> pool, ModbusRtuFramerPluginConfig cfg)
|
||
{
|
||
return std::make_shared<ModbusRtuFramerPlugin>(std::move(pool), cfg);
|
||
}
|
||
|
||
softbus::core::plugin_system::IProtocolFramerPlugin* createModbusRtuFramerPluginRaw()
|
||
{
|
||
return new ModbusRtuFramerPlugin(nullptr, {});
|
||
}
|
||
|
||
} // namespace softbus::message_bus::pipeline::protocol::modbusrtu
|