diff --git a/CMakeLists.txt b/CMakeLists.txt index fcb4781..fbb7dc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,8 @@ qt_add_executable(softbus_daemon src/device_bus/DeviceBus.cpp src/device_bus/manager/DeviceBusManager.h src/device_bus/manager/DeviceBusManager.cpp + src/device_bus/manager/SerialDeviceManager.h + src/device_bus/manager/SerialDeviceManager.cpp # device bus: registry skeleton src/device_bus/registry/IDeviceRegistry.h @@ -110,6 +112,32 @@ qt_add_executable(softbus_daemon # devices: physical src/devices/physical/SerialDevice.h src/devices/physical/SerialDevice.cpp + + # core memory/plugin + src/core/memory/MemoryPool.h + src/core/memory/LockFreeQueue.h + src/core/plugin_system/IProtocolPlugin.h + src/core/plugin_system/PluginManager.h + src/core/plugin_system/PluginManager.cpp + + # message bus pipeline + src/message_bus/pipeline/PayloadRef.h + src/message_bus/pipeline/PipelineContext.h + src/message_bus/pipeline/PipelineEngine.h + src/message_bus/pipeline/PipelineEngine.cpp + src/message_bus/pipeline/stages/1_framers/IFramer.h + src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp + src/message_bus/pipeline/stages/2_parsers/IParserStage.h + src/message_bus/pipeline/stages/3_filters/IFilterStage.h + src/message_bus/pipeline/stages/4_validators/IValidator.h + + # message bus ingress/egress + src/message_bus/ingress/IIngressPort.h + src/message_bus/ingress/DriverIngressAdapter.h + src/message_bus/ingress/DriverIngressAdapter.cpp + src/message_bus/egress/IEgressPort.h + src/message_bus/egress/EgressRouter.h + src/message_bus/egress/EgressRouter.cpp ) target_include_directories(softbus_daemon diff --git a/bin/softbus_daemon b/bin/softbus_daemon index 5ec808f..d1fe3e9 100755 Binary files a/bin/softbus_daemon and b/bin/softbus_daemon differ diff --git a/main.cpp b/main.cpp index 16375e6..3b8dea4 100644 --- a/main.cpp +++ b/main.cpp @@ -26,7 +26,7 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); app.setApplicationName("soft_bus_daemon"); - app.setApplicationVersion("1.0.0"); + app.setApplicationVersion("1.1.0"); app.setOrganizationName("soft_bus"); // ================================== diff --git a/plugins/protocols/can_raw/CMakeLists.txt b/plugins/protocols/can_raw/CMakeLists.txt index 818c93b..76ab7e0 100644 --- a/plugins/protocols/can_raw/CMakeLists.txt +++ b/plugins/protocols/can_raw/CMakeLists.txt @@ -1,3 +1,3 @@ -# Placeholder for can_raw plugin -add_library(can_raw SHARED) +# Placeholder for can_raw plugin +add_library(can_raw SHARED plugin_stub.cpp) set_target_properties(can_raw PROPERTIES OUTPUT_NAME "can_raw") diff --git a/plugins/protocols/can_raw/plugin_stub.cpp b/plugins/protocols/can_raw/plugin_stub.cpp new file mode 100644 index 0000000..578c698 --- /dev/null +++ b/plugins/protocols/can_raw/plugin_stub.cpp @@ -0,0 +1 @@ +extern "C" void softbus_can_raw_plugin_stub() {} diff --git a/plugins/protocols/custom_proto/CMakeLists.txt b/plugins/protocols/custom_proto/CMakeLists.txt index fe435e3..91fac0b 100644 --- a/plugins/protocols/custom_proto/CMakeLists.txt +++ b/plugins/protocols/custom_proto/CMakeLists.txt @@ -1,3 +1,3 @@ -# Placeholder for custom_proto plugin -add_library(custom_proto SHARED) +# Placeholder for custom_proto plugin +add_library(custom_proto SHARED plugin_stub.cpp) set_target_properties(custom_proto PROPERTIES OUTPUT_NAME "custom_proto") diff --git a/plugins/protocols/custom_proto/plugin_stub.cpp b/plugins/protocols/custom_proto/plugin_stub.cpp new file mode 100644 index 0000000..b017454 --- /dev/null +++ b/plugins/protocols/custom_proto/plugin_stub.cpp @@ -0,0 +1 @@ +extern "C" void softbus_custom_proto_plugin_stub() {} diff --git a/plugins/protocols/modbus_rtu/CMakeLists.txt b/plugins/protocols/modbus_rtu/CMakeLists.txt index fc61891..d7384e5 100644 --- a/plugins/protocols/modbus_rtu/CMakeLists.txt +++ b/plugins/protocols/modbus_rtu/CMakeLists.txt @@ -1,3 +1,3 @@ -# Placeholder for modbus_rtu plugin -add_library(modbus_rtu SHARED) +# Placeholder for modbus_rtu plugin +add_library(modbus_rtu SHARED plugin_stub.cpp) set_target_properties(modbus_rtu PROPERTIES OUTPUT_NAME "modbus_rtu") diff --git a/plugins/protocols/modbus_rtu/plugin_stub.cpp b/plugins/protocols/modbus_rtu/plugin_stub.cpp new file mode 100644 index 0000000..d1966ea --- /dev/null +++ b/plugins/protocols/modbus_rtu/plugin_stub.cpp @@ -0,0 +1 @@ +extern "C" void softbus_modbus_rtu_plugin_stub() {} diff --git a/src/core/CoreService.cpp b/src/core/CoreService.cpp index 034b3c5..1f63344 100644 --- a/src/core/CoreService.cpp +++ b/src/core/CoreService.cpp @@ -9,6 +9,8 @@ #include "utils/logs/logging.h" #include "device_bus/DeviceBus.h" +#include "message_bus/pipeline/PayloadRef.h" +#include "message_bus/pipeline/PipelineContext.h" CoreService* CoreService::instance() { @@ -35,6 +37,8 @@ bool CoreService::initialize() } LOG_INFO() << "CoreService initializing"; + qRegisterMetaType("softbus::message_bus::pipeline::PayloadRef"); + qRegisterMetaType("softbus::message_bus::pipeline::PipelineContext"); // 1. 解析配置路径(放在用户 home 下的相对固定目录:~/softbus/config) const QString configPath = diff --git a/src/core/memory/LockFreeQueue.h b/src/core/memory/LockFreeQueue.h index 633da49..ab6cf93 100644 --- a/src/core/memory/LockFreeQueue.h +++ b/src/core/memory/LockFreeQueue.h @@ -1,7 +1,78 @@ -#pragma once - -// Placeholder for a lock-free ring queue. -class LockFreeQueue { -public: - LockFreeQueue() = default; +#pragma once + +#include +#include +#include + +namespace softbus::core::memory +{ + +template +class LockFreeQueue +{ +public: + // SPSC ring queue. Producer and consumer must be single-threaded. + explicit LockFreeQueue(std::size_t capacity) + : m_capacity(capacity + 1), m_data(m_capacity) + { + } + + bool push(const T& value) + { + const auto head = m_head.load(std::memory_order_relaxed); + const auto next = increment(head); + if (next == m_tail.load(std::memory_order_acquire)) { + return false; // queue full + } + m_data[head] = value; + m_head.store(next, std::memory_order_release); + return true; + } + + bool push(T&& value) + { + const auto head = m_head.load(std::memory_order_relaxed); + const auto next = increment(head); + if (next == m_tail.load(std::memory_order_acquire)) { + return false; // queue full + } + m_data[head] = std::move(value); + m_head.store(next, std::memory_order_release); + return true; + } + + bool pop(T& out) + { + const auto tail = m_tail.load(std::memory_order_relaxed); + if (tail == m_head.load(std::memory_order_acquire)) { + return false; // queue empty + } + out = std::move(m_data[tail]); + m_tail.store(increment(tail), std::memory_order_release); + return true; + } + + bool empty() const + { + return m_head.load(std::memory_order_acquire) == m_tail.load(std::memory_order_acquire); + } + + std::size_t capacity() const + { + return m_capacity - 1; + } + +private: + std::size_t increment(std::size_t idx) const + { + return (idx + 1) % m_capacity; + } + +private: + const std::size_t m_capacity; + std::vector m_data; + alignas(64) std::atomic m_head{0}; + alignas(64) std::atomic m_tail{0}; }; + +} // namespace softbus::core::memory diff --git a/src/core/memory/MemoryPool.h b/src/core/memory/MemoryPool.h index 47f07cf..c651ef3 100644 --- a/src/core/memory/MemoryPool.h +++ b/src/core/memory/MemoryPool.h @@ -1,7 +1,98 @@ -#pragma once - -// Placeholder for a preallocated memory pool. -class MemoryPool { -public: - MemoryPool() = default; +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace softbus::core::memory +{ + +class MemoryPool +{ +public: + struct PoolBlock + { + std::uint8_t* data{nullptr}; + std::size_t capacity{0}; + std::size_t size{0}; + std::size_t slotIndex{0}; + }; + + using BlockPtr = std::shared_ptr; + + explicit MemoryPool(std::size_t blockSize = 4096, std::size_t blockCount = 1024) + : m_blockSize(blockSize), m_storage(blockSize * blockCount), m_inUse(blockCount, false) + { + for (std::size_t i = 0; i < blockCount; ++i) { + m_freeSlots.push(i); + } + } + + BlockPtr allocate(std::size_t requiredSize) + { + if (requiredSize > m_blockSize) { + return {}; + } + + std::size_t slot = 0; + { + std::lock_guard lk(m_mutex); + if (m_freeSlots.empty()) { + return {}; + } + slot = m_freeSlots.front(); + m_freeSlots.pop(); + m_inUse[slot] = true; + } + + auto* raw = new PoolBlock{ + m_storage.data() + slot * m_blockSize, + m_blockSize, + requiredSize, + slot, + }; + return BlockPtr(raw, [this](PoolBlock* b) { + if (!b) return; + this->release(*b); + delete b; + }); + } + + void release(const PoolBlock& block) + { + std::lock_guard lk(m_mutex); + if (block.slotIndex >= m_inUse.size()) { + return; + } + if (!m_inUse[block.slotIndex]) { + return; + } + m_inUse[block.slotIndex] = false; + m_freeSlots.push(block.slotIndex); + } + + std::size_t blockSize() const { return m_blockSize; } + std::size_t totalBlocks() const { return m_inUse.size(); } + + std::size_t inUseBlocks() const + { + std::lock_guard lk(m_mutex); + std::size_t used = 0; + for (const bool v : m_inUse) { + if (v) ++used; + } + return used; + } + +private: + std::size_t m_blockSize; + std::vector m_storage; + mutable std::mutex m_mutex; + std::queue m_freeSlots; + std::vector m_inUse; }; + +} // namespace softbus::core::memory diff --git a/src/core/plugin_system/IProtocolPlugin.h b/src/core/plugin_system/IProtocolPlugin.h index ab70877..23bff7e 100644 --- a/src/core/plugin_system/IProtocolPlugin.h +++ b/src/core/plugin_system/IProtocolPlugin.h @@ -1,7 +1,30 @@ -#pragma once - -// Placeholder protocol plugin interface. -class IProtocolPlugin { -public: - virtual ~IProtocolPlugin() = default; +#pragma once + +#include + +#include + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::core::plugin_system +{ + +class IProtocolSession +{ +public: + virtual ~IProtocolSession() = default; + virtual bool feed(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; + virtual void reset() = 0; }; + +class IProtocolPlugin +{ +public: + virtual ~IProtocolPlugin() = default; + + virtual QString pluginId() const = 0; + virtual bool supports(const QString& protocolHint) const = 0; + virtual std::unique_ptr createSession() = 0; +}; + +} // namespace softbus::core::plugin_system diff --git a/src/core/plugin_system/PluginManager.cpp b/src/core/plugin_system/PluginManager.cpp new file mode 100644 index 0000000..480bf17 --- /dev/null +++ b/src/core/plugin_system/PluginManager.cpp @@ -0,0 +1,24 @@ +#include "core/plugin_system/PluginManager.h" + +namespace softbus::core::plugin_system +{ + +void PluginManager::registerProtocolPlugin(std::shared_ptr plugin) +{ + if (!plugin) { + return; + } + m_protocolPlugins.insert(plugin->pluginId(), std::move(plugin)); +} + +std::shared_ptr PluginManager::selectProtocolPlugin(const QString& protocolHint) const +{ + for (auto it = m_protocolPlugins.constBegin(); it != m_protocolPlugins.constEnd(); ++it) { + if (it.value() && it.value()->supports(protocolHint)) { + return it.value(); + } + } + return {}; +} + +} // namespace softbus::core::plugin_system diff --git a/src/core/plugin_system/PluginManager.h b/src/core/plugin_system/PluginManager.h index 251dae4..ef450e7 100644 --- a/src/core/plugin_system/PluginManager.h +++ b/src/core/plugin_system/PluginManager.h @@ -1,7 +1,25 @@ -#pragma once - -// Placeholder for plugin manager. -class PluginManager { -public: - PluginManager() = default; +#pragma once + +#include + +#include +#include + +#include "core/plugin_system/IProtocolPlugin.h" + +namespace softbus::core::plugin_system +{ + +class PluginManager +{ +public: + PluginManager() = default; + + void registerProtocolPlugin(std::shared_ptr plugin); + std::shared_ptr selectProtocolPlugin(const QString& protocolHint) const; + +private: + QHash> m_protocolPlugins; }; + +} // namespace softbus::core::plugin_system diff --git a/src/device_bus/DeviceBus.cpp b/src/device_bus/DeviceBus.cpp index d1b319c..e92366b 100644 --- a/src/device_bus/DeviceBus.cpp +++ b/src/device_bus/DeviceBus.cpp @@ -51,6 +51,7 @@ bool DeviceBus::initialize(const QJsonObject &rootConfig) { } d->manager->setDeviceTreeModel(d->treeModel); d->manager->setRegistry(d->registry.get()); + d->manager->setDirtyCallback([this]() { this->markDeviceTreeDirty(); }); // 1) Load persisted config and initialize manager if (!d->manager->initialize(rootConfig)) { diff --git a/src/device_bus/manager/DeviceBusManager.cpp b/src/device_bus/manager/DeviceBusManager.cpp index 4a7d6b3..09a5e02 100644 --- a/src/device_bus/manager/DeviceBusManager.cpp +++ b/src/device_bus/manager/DeviceBusManager.cpp @@ -1,19 +1,23 @@ #include "device_bus/manager/DeviceBusManager.h" +#include #include -#include -#include #include // #include -#include "hardware/drivers/serial/SerialQtDriver.h" -#include "hardware/drivers/serial/SerialCapabilities.h" +#include "message_bus/egress/EgressRouter.h" +#include "message_bus/ingress/DriverIngressAdapter.h" +#include "message_bus/pipeline/PipelineEngine.h" +#include "core/plugin_system/PluginManager.h" +#include "device_bus/manager/SerialDeviceManager.h" #include "devices/DeviceTypes.h" #include "utils/logs/logging.h" -using softbus::hardware::drivers::serial::SerialQtDriver; -namespace serial_cap = softbus::hardware::drivers::serial::capabilities; +DeviceBusManager::~DeviceBusManager() +{ + shutdown(); +} void DeviceBusManager::setDeviceTreeModel(std::shared_ptr model) { @@ -25,8 +29,37 @@ void DeviceBusManager::setRegistry(softbus::device_bus::registry::IDeviceRegistr m_registry = registry; } +void DeviceBusManager::setDirtyCallback(std::function cb) +{ + m_dirtyCb = std::move(cb); +} + bool DeviceBusManager::initialize(const QJsonObject& rootConfig) { + if (!m_memoryPool) { + m_memoryPool = std::make_shared(4096, 4096); + } + if (!m_pipelineEngine) { + m_pipelineEngine = std::make_unique(4096); + } + if (!m_pluginManager) { + m_pluginManager = std::make_shared(); + } + if (m_pipelineEngine) { + m_pipelineEngine->setPluginManager(m_pluginManager); + m_pipelineEngine->start(); + } + if (!m_ingressAdapter) { + m_ingressAdapter = std::make_unique( + m_memoryPool, m_pipelineEngine.get()); + } + if (!m_egressRouter) { + m_egressRouter = std::make_unique(); + } + if (!m_egressRunning.exchange(true)) { + m_egressThread = std::thread([this]() { this->processEgressLoop(); }); + } + if (!m_treeModel) { m_treeModel = std::make_shared(); } @@ -78,7 +111,7 @@ bool DeviceBusManager::reconcileFromTreeModel() if (kind == softbus::devices::DeviceKind::Serial) { desiredSerialEndpoints.insert(n.endpoint); - if (!m_serialDevicesByEndpoint.contains(n.endpoint)) { + if (!m_serialDevicesByEndpointSharedPtr.contains(n.endpoint)) { initializeSerialDevice(n.endpoint, n.params); } m_deviceEndpointsMap.insert(n.endpoint, kind); @@ -86,7 +119,7 @@ bool DeviceBusManager::reconcileFromTreeModel() } // Remove runtime devices that are no longer desired/offline - const auto currentKeys = m_serialDevicesByEndpoint.keys(); + const auto currentKeys = m_serialDevicesByEndpointSharedPtr.keys(); for (const auto& endpoint : currentKeys) { if (!desiredSerialEndpoints.contains(endpoint)) { shutdownSerialDevice(endpoint); @@ -99,105 +132,39 @@ bool DeviceBusManager::reconcileFromTreeModel() void DeviceBusManager::shutdown() { + m_egressRunning.store(false); + if (m_egressThread.joinable()) { + m_egressThread.join(); + } + // 关闭并销毁所有串口设备 - const auto keys = m_serialDevicesByEndpoint.keys(); + const auto keys = m_serialDevicesByEndpointSharedPtr.keys(); for (const auto& endpoint : keys) { shutdownSerialDevice(endpoint); } + if (m_pipelineEngine) { + m_pipelineEngine->stop(); + m_pipelineEngine->drain(); + } } void DeviceBusManager::initializeSerialDevice(const QString& endpoint, const QJsonObject& params) { - if (m_serialDevicesByEndpoint.contains(endpoint)) { - LOG_WARNING() << "DeviceBusManager: serial device already exists for" << endpoint; - return; - } - - // 合并参数(defaults + enum 校验) - serial_cap::SerialDefaults def = serial_cap::kDefaults; - - int baud = params.value(QStringLiteral("baudRate")).toInt(def.baudRate); - if (!serial_cap::isValidBaud(baud)) baud = def.baudRate; - - int dataBits = params.value(QStringLiteral("dataBits")).toInt(def.dataBits); - if (!serial_cap::isValidDataBits(dataBits)) dataBits = def.dataBits; - - QString parityStr = params.value(QStringLiteral("parity")).toString(QLatin1String(def.parity)); - if (!serial_cap::isValidParity(parityStr)) parityStr = QLatin1String(def.parity); - - int stopBitsVal = params.value(QStringLiteral("stopBits")).toInt(def.stopBits); - if (!serial_cap::isValidStopBits(stopBitsVal)) stopBitsVal = def.stopBits; - - QString flowStr = params.value(QStringLiteral("flowControl")).toString(QLatin1String(def.flowControl)); - if (!serial_cap::isValidFlowControl(flowStr)) flowStr = QLatin1String(def.flowControl); - - QJsonObject merged; - merged.insert(QStringLiteral("baudRate"), baud); - merged.insert(QStringLiteral("dataBits"), dataBits); - merged.insert(QStringLiteral("parity"), parityStr); - merged.insert(QStringLiteral("stopBits"), stopBitsVal); - merged.insert(QStringLiteral("flowControl"), flowStr); - - LOG_INFO() << "DeviceBusManager: init serial endpoint=" << endpoint - << "params=" << QJsonDocument(merged).toJson(QJsonDocument::Compact); - - auto driver = std::make_unique(nullptr); - driver->SetBaudRate(static_cast(baud)); - driver->SetDataBits(static_cast(dataBits)); - - QSerialPort::Parity parity = QSerialPort::NoParity; - if (parityStr == QStringLiteral("even")) { - parity = QSerialPort::EvenParity; - } else if (parityStr == QStringLiteral("odd")) { - parity = QSerialPort::OddParity; - } - driver->SetParity(parity); - - QSerialPort::StopBits stopBits = (stopBitsVal == 2) ? QSerialPort::TwoStop : QSerialPort::OneStop; - driver->SetStopBits(stopBits); - - QSerialPort::FlowControl flow = QSerialPort::NoFlowControl; - if (flowStr == QStringLiteral("hardware")) { - flow = QSerialPort::HardwareControl; - } else if (flowStr == QStringLiteral("software")) { - flow = QSerialPort::SoftwareControl; - } - driver->SetFlowControl(flow); - - softbus::devices::DeviceInfo info; - info.id = -1; - info.endpoint = endpoint; - info.type = QStringLiteral("serial"); - info.kind = softbus::devices::DeviceKind::Serial; - - softbus::devices::physical::SerialDevice::Config cfg; - cfg.endpoint = endpoint; - cfg.baudRate = baud; - cfg.dataBits = dataBits; - cfg.parity = parityStr; - cfg.stopBits = stopBitsVal; - cfg.flowControl = flowStr; - - QSharedPointer device( - new softbus::devices::physical::SerialDevice(std::move(driver), cfg, info)); - - if (m_registry) { - m_registry->registerDevice(info); - } - - // 按当前策略:初始化时就打开串口 - if (!device->start()) { - LOG_ERROR() << "DeviceBusManager: failed to start serial device for" << endpoint; - return; - } - - m_serialDevicesByEndpoint.insert(endpoint, device); + softbus::device_bus::manager::SerialInitDeps deps; + deps.treeModel = m_treeModel.get(); + deps.dirtyCb = m_dirtyCb; + deps.registry = m_registry; + deps.ingressAdapter = m_ingressAdapter.get(); + deps.memoryPool = m_memoryPool; + deps.egressRouter = m_egressRouter.get(); + deps.serialDevicesByEndpoint = &m_serialDevicesByEndpointSharedPtr; + (void)softbus::device_bus::manager::initializeSerialDeviceWithDeps(endpoint, params, deps); } void DeviceBusManager::shutdownSerialDevice(const QString& endpoint) { - auto it = m_serialDevicesByEndpoint.find(endpoint); - if (it == m_serialDevicesByEndpoint.end()) { + auto it = m_serialDevicesByEndpointSharedPtr.find(endpoint); + if (it == m_serialDevicesByEndpointSharedPtr.end()) { return; } @@ -209,6 +176,29 @@ void DeviceBusManager::shutdownSerialDevice(const QString& endpoint) } device->stop(); } + if (m_egressRouter) { + m_egressRouter->unbindSerialDevice(endpoint); + } - m_serialDevicesByEndpoint.erase(it); + m_serialDevicesByEndpointSharedPtr.erase(it); +} + +void DeviceBusManager::processEgressLoop() +{ + while (m_egressRunning.load()) { + if (!m_pipelineEngine || !m_egressRouter) { + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + continue; + } + + softbus::message_bus::pipeline::PipelineContext out; + if (!m_pipelineEngine->tryPopEgress(out)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + const bool ok = m_egressRouter->send(out); + if (!ok) { + // LOG_WARNING() << "DeviceBusManager: egress send failed endpoint=" << out.endpoint; + } + } } diff --git a/src/device_bus/manager/DeviceBusManager.h b/src/device_bus/manager/DeviceBusManager.h index e2d084a..dbc1fa2 100644 --- a/src/device_bus/manager/DeviceBusManager.h +++ b/src/device_bus/manager/DeviceBusManager.h @@ -6,18 +6,29 @@ #include #include #include +#include #include +#include +#include +#include "core/memory/MemoryPool.h" +#include "core/plugin_system/PluginManager.h" #include "device_bus/tree/DeviceTreeModel.h" #include "device_bus/registry/IDeviceRegistry.h" #include "devices/DeviceTypes.h" #include "devices/physical/SerialDevice.h" +#include "message_bus/egress/EgressRouter.h" +#include "message_bus/ingress/DriverIngressAdapter.h" +#include "message_bus/pipeline/PipelineEngine.h" class DeviceBusManager { public: + ~DeviceBusManager(); + void setDeviceTreeModel(std::shared_ptr model); void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry); + void setDirtyCallback(std::function cb); bool initialize(const QJsonObject& rootConfig); bool reconcileFromTreeModel(); @@ -26,6 +37,7 @@ public: private: void initializeSerialDevice(const QString& endpoint, const QJsonObject& params); void shutdownSerialDevice(const QString& endpoint); + void processEgressLoop(); // void initializeCanDriver(); // void shutdownCanDriver(); // void initializeTcpDriver(); @@ -40,12 +52,18 @@ private: // 添加map来记住所有设备的endpoint和type的映射 QMap m_deviceEndpointsMap; - QHash> m_serialDevicesByEndpoint; + QHash> m_serialDevicesByEndpointSharedPtr; softbus::device_bus::registry::IDeviceRegistry* m_registry = nullptr; + std::shared_ptr m_memoryPool; + std::shared_ptr m_pluginManager; + std::unique_ptr m_pipelineEngine; + std::unique_ptr m_ingressAdapter; + std::unique_ptr m_egressRouter; + std::atomic m_egressRunning{false}; + std::thread m_egressThread; + std::function m_dirtyCb; + - // std::vector m_canDrivers; - // std::vector m_tcpDrivers; - // std::vector m_udpDrivers; }; diff --git a/src/device_bus/manager/SerialDeviceManager.cpp b/src/device_bus/manager/SerialDeviceManager.cpp new file mode 100644 index 0000000..6b32a7d --- /dev/null +++ b/src/device_bus/manager/SerialDeviceManager.cpp @@ -0,0 +1,167 @@ +#include "device_bus/manager/SerialDeviceManager.h" + +#include +#include + +#include "device_bus/tree/DeviceTreeModel.h" +#include "devices/DeviceTypes.h" +#include "hardware/drivers/serial/SerialCapabilities.h" +#include "hardware/drivers/serial/SerialQtDriver.h" +#include "message_bus/egress/EgressRouter.h" +#include "message_bus/ingress/DriverIngressAdapter.h" +#include "utils/logs/logging.h" + +using softbus::hardware::drivers::serial::SerialQtDriver; +namespace serial_cap = softbus::hardware::drivers::serial::capabilities; + +namespace softbus::device_bus::manager +{ + +static bool setIfChanged(QJsonObject& params, const QString& key, const QJsonValue& value) +{ + const auto it = params.find(key); + if (it == params.end() || it.value() != value) { + params.insert(key, value); + return true; + } + return false; +} + +static bool persistSerialParams(DeviceTreeModel* treeModel, + const QString& endpoint, + const QJsonObject& mergedParams, + const std::function& dirtyCb) +{ + if (!treeModel || endpoint.isEmpty() || mergedParams.isEmpty()) { + return false; + } + + const int idx = treeModel->findIndexByEndpoint(endpoint); + if (idx < 0) { + return false; + } + + auto& nodes = treeModel->nodesMutable(); + if (idx >= nodes.size()) { + return false; + } + + auto& node = nodes[idx]; + auto& p = node.params; + + bool changed = false; + changed = setIfChanged(p, QStringLiteral("baudRate"), mergedParams.value(QStringLiteral("baudRate"))) || changed; + changed = setIfChanged(p, QStringLiteral("dataBits"), mergedParams.value(QStringLiteral("dataBits"))) || changed; + changed = setIfChanged(p, QStringLiteral("parity"), mergedParams.value(QStringLiteral("parity"))) || changed; + changed = setIfChanged(p, QStringLiteral("stopBits"), mergedParams.value(QStringLiteral("stopBits"))) || changed; + changed = + setIfChanged(p, QStringLiteral("flowControl"), mergedParams.value(QStringLiteral("flowControl"))) || changed; + + if (changed && dirtyCb) { + dirtyCb(); + } + return changed; +} + +bool initializeSerialDeviceWithDeps(const QString& endpoint, const QJsonObject& params, const SerialInitDeps& deps) +{ + if (!deps.serialDevicesByEndpoint) { + return false; + } + + if (deps.serialDevicesByEndpoint->contains(endpoint)) { + LOG_WARNING() << "DeviceBusManager: serial device already exists for" << endpoint; + return false; + } + + serial_cap::SerialDefaults def = serial_cap::kDefaults; + + int baud = params.value(QStringLiteral("baudRate")).toInt(def.baudRate); + if (!serial_cap::isValidBaud(baud)) baud = def.baudRate; + + int dataBits = params.value(QStringLiteral("dataBits")).toInt(def.dataBits); + if (!serial_cap::isValidDataBits(dataBits)) dataBits = def.dataBits; + + QString parityStr = params.value(QStringLiteral("parity")).toString(QLatin1String(def.parity)); + if (!serial_cap::isValidParity(parityStr)) parityStr = QLatin1String(def.parity); + + int stopBitsVal = params.value(QStringLiteral("stopBits")).toInt(def.stopBits); + if (!serial_cap::isValidStopBits(stopBitsVal)) stopBitsVal = def.stopBits; + + QString flowStr = params.value(QStringLiteral("flowControl")).toString(QLatin1String(def.flowControl)); + if (!serial_cap::isValidFlowControl(flowStr)) flowStr = QLatin1String(def.flowControl); + + QJsonObject merged; + merged.insert(QStringLiteral("baudRate"), baud); + merged.insert(QStringLiteral("dataBits"), dataBits); + merged.insert(QStringLiteral("parity"), parityStr); + merged.insert(QStringLiteral("stopBits"), stopBitsVal); + merged.insert(QStringLiteral("flowControl"), flowStr); + + LOG_INFO() << "DeviceBusManager: init serial endpoint=" << endpoint + << "params=" << QJsonDocument(merged).toJson(QJsonDocument::Compact); + + persistSerialParams(deps.treeModel, endpoint, merged, deps.dirtyCb); + + auto driver = std::make_unique(nullptr); + driver->SetBaudRate(static_cast(baud)); + driver->SetDataBits(static_cast(dataBits)); + + QSerialPort::Parity parity = QSerialPort::NoParity; + if (parityStr == QStringLiteral("even")) { + parity = QSerialPort::EvenParity; + } else if (parityStr == QStringLiteral("odd")) { + parity = QSerialPort::OddParity; + } + driver->SetParity(parity); + + QSerialPort::StopBits stopBits = (stopBitsVal == 2) ? QSerialPort::TwoStop : QSerialPort::OneStop; + driver->SetStopBits(stopBits); + + QSerialPort::FlowControl flow = QSerialPort::NoFlowControl; + if (flowStr == QStringLiteral("hardware")) { + flow = QSerialPort::HardwareControl; + } else if (flowStr == QStringLiteral("software")) { + flow = QSerialPort::SoftwareControl; + } + driver->SetFlowControl(flow); + + softbus::devices::DeviceInfo info; + info.id = -1; + info.endpoint = endpoint; + info.type = QStringLiteral("serial"); + info.kind = softbus::devices::DeviceKind::Serial; + + softbus::devices::physical::SerialDevice::Config cfg; + cfg.endpoint = endpoint; + cfg.baudRate = baud; + cfg.dataBits = dataBits; + cfg.parity = parityStr; + cfg.stopBits = stopBitsVal; + cfg.flowControl = flowStr; + + QSharedPointer device( + new softbus::devices::physical::SerialDevice(std::move(driver), cfg, info)); + // 绑定 ingress 适配器和内存池 数据推送到 ingress 队列 + device->bindIngress(deps.ingressAdapter, deps.memoryPool); + + if (deps.registry) { + deps.registry->registerDevice(info); + } + + if (!device->start()) { + LOG_ERROR() << "DeviceBusManager: failed to start serial device for" << endpoint; + return false; + } + + deps.serialDevicesByEndpoint->insert(endpoint, device); + // 暂时不绑定 egress 路由器 因为还没有 egress 路由器 + // egress 路由器 是用来将数据从 ingress 队列中取出并发送给设备的 + // if (deps.egressRouter) { + // deps.egressRouter->bindSerialDevice(endpoint, device); + // } + + return true; +} + +} // namespace softbus::device_bus::manager diff --git a/src/device_bus/manager/SerialDeviceManager.h b/src/device_bus/manager/SerialDeviceManager.h new file mode 100644 index 0000000..7ab29e7 --- /dev/null +++ b/src/device_bus/manager/SerialDeviceManager.h @@ -0,0 +1,41 @@ +#pragma once +// 串口参数校验与默认值合并 +// 参数回写设备树(持久化前置) +// 创建设备与驱动 +// ingress / egress 绑定 +// registry 注册与设备启动 + +#include +#include + +#include +#include +#include +#include + +#include "core/memory/MemoryPool.h" +#include "device_bus/registry/IDeviceRegistry.h" +#include "devices/physical/SerialDevice.h" + +namespace softbus::message_bus::egress { class EgressRouter; } +namespace softbus::message_bus::ingress { class DriverIngressAdapter; } + +class DeviceTreeModel; + +namespace softbus::device_bus::manager +{ + +struct SerialInitDeps +{ + DeviceTreeModel* treeModel{nullptr}; + std::function dirtyCb; + softbus::device_bus::registry::IDeviceRegistry* registry{nullptr}; + softbus::message_bus::ingress::DriverIngressAdapter* ingressAdapter{nullptr}; + std::shared_ptr memoryPool; + softbus::message_bus::egress::EgressRouter* egressRouter{nullptr}; + QHash>* serialDevicesByEndpoint{nullptr}; +}; + +bool initializeSerialDeviceWithDeps(const QString& endpoint, const QJsonObject& params, const SerialInitDeps& deps); + +} // namespace softbus::device_bus::manager diff --git a/src/device_bus/tree/DeviceTreeModel.cpp b/src/device_bus/tree/DeviceTreeModel.cpp index 8ede967..bdcccc1 100644 --- a/src/device_bus/tree/DeviceTreeModel.cpp +++ b/src/device_bus/tree/DeviceTreeModel.cpp @@ -148,6 +148,20 @@ int DeviceTreeModel::findIndexByStableKey(const QString& stableKey) const return -1; } +int DeviceTreeModel::findIndexByEndpoint(const QString& endpoint) const +{ + if (endpoint.isEmpty()) { + return -1; + } + for (int i = 0; i < m_nodes.size(); ++i) { + const auto& n = m_nodes.at(i); + if (n.endpoint == endpoint) { + return i; + } + } + return -1; +} + QString DeviceTreeModel::upsertNodeByStableKey(const QString& stableKey, const QString& preferredId, const QString& type, diff --git a/src/device_bus/tree/DeviceTreeModel.h b/src/device_bus/tree/DeviceTreeModel.h index ab04948..3fa03c5 100644 --- a/src/device_bus/tree/DeviceTreeModel.h +++ b/src/device_bus/tree/DeviceTreeModel.h @@ -32,6 +32,7 @@ public: const DeviceTreeNode* findById(const QString& id) const; int findIndexById(const QString& id) const; + int findIndexByEndpoint(const QString& endpoint) const; int findIndexByStableKey(const QString& stableKey) const; // Monitor/register path: upsert or mark online/offline diff --git a/src/devices/physical/SerialDevice.cpp b/src/devices/physical/SerialDevice.cpp index a6f6c83..8f48695 100644 --- a/src/devices/physical/SerialDevice.cpp +++ b/src/devices/physical/SerialDevice.cpp @@ -1,8 +1,15 @@ #include "devices/physical/SerialDevice.h" +#include #include +#include +#include + +#include "core/memory/MemoryPool.h" #include "hardware/drivers/serial/SerialQtDriver.h" +#include "message_bus/ingress/IIngressPort.h" +#include "message_bus/pipeline/PipelineContext.h" #include "utils/logs/logging.h" using softbus::hardware::drivers::serial::SerialQtDriver; @@ -31,6 +38,9 @@ bool SerialDevice::start() return false; } + m_driver->SetReadCallback([this](const std::vector& data) { this->onRead(data); }); + m_driver->SetErrorCallback([this](const std::string& error) { this->onError(error); }); + LOG_INFO() << "SerialDevice: opening endpoint" << m_config.endpoint; return m_driver->Open(m_config.endpoint.toStdString()); } @@ -60,5 +70,71 @@ softbus::devices::DeviceKind SerialDevice::kind() const return softbus::devices::DeviceKind::Serial; } +void SerialDevice::bindIngress(softbus::message_bus::ingress::IIngressPort* ingress, + std::shared_ptr pool) +{ + m_ingress = ingress; + m_pool = std::move(pool); +} + +// 串口写入数据回调 不定长数据 +bool SerialDevice::writePayload(const std::vector& data) +{ + if (!m_driver) { + return false; + } + return m_driver->Write(data); +} +// 串口写入数据回调 定长数据 +bool SerialDevice::writePayload(const std::uint8_t* data, std::size_t size) +{ + if (!m_driver) { + return false; + } + return m_driver->Write(data, size); +} + +// 串口读取数据回调 + +void SerialDevice::onRead(const std::vector& data) +{ + if (!m_ingress || !m_pool || data.empty()) { + return; + } + + auto block = m_pool->allocate(data.size()); + if (!block || !block->data || block->capacity < data.size()) { + m_ingress->reportError(m_config.endpoint, QStringLiteral("memory pool exhausted")); + return; + } + + std::copy(data.begin(), data.end(), block->data); + block->size = data.size(); + // @test code + LOG_INFO() << "SerialDevice: onRead data size" << data.size() << "endpoint" << m_config.endpoint; + // 将数据推送到 ingress 队列 包含端口名、协议、数据、时间戳、traceId + softbus::message_bus::pipeline::PipelineContext ctx; + ctx.endpoint = m_config.endpoint; + ctx.protocolHint = m_info.protocol; + ctx.payload.block = std::move(block); + ctx.payload.length = data.size(); + ctx.payloadSize = data.size(); + ctx.traceId = QStringLiteral("serial:%1:%2") + .arg(m_config.endpoint) + .arg(QDateTime::currentMSecsSinceEpoch()); + + if (!m_ingress->push(std::move(ctx))) { + m_ingress->reportError(m_config.endpoint, QStringLiteral("ingress queue full")); + } +} + +void SerialDevice::onError(const std::string& error) +{ + if (!m_ingress) { + return; + } + m_ingress->reportError(m_config.endpoint, QString::fromStdString(error)); +} + } // namespace softbus::devices::physical diff --git a/src/devices/physical/SerialDevice.h b/src/devices/physical/SerialDevice.h index 8947088..52a1795 100644 --- a/src/devices/physical/SerialDevice.h +++ b/src/devices/physical/SerialDevice.h @@ -1,11 +1,15 @@ #pragma once #include +#include #include +#include #include "devices/DeviceTypes.h" #include "devices/base/IPhysicalDevice.h" namespace softbus::hardware::drivers::serial { class SerialQtDriver; } +namespace softbus::message_bus::ingress { class IIngressPort; } +namespace softbus::core::memory { class MemoryPool; } namespace softbus::devices::physical { @@ -36,11 +40,21 @@ public: QString endpoint() const; softbus::devices::DeviceKind kind() const; + void bindIngress(softbus::message_bus::ingress::IIngressPort* ingress, + std::shared_ptr pool); + bool writePayload(const std::vector& data); + bool writePayload(const std::uint8_t* data, std::size_t size); + +private: + void onRead(const std::vector& data); + void onError(const std::string& error); private: std::unique_ptr m_driver; Config m_config; softbus::devices::DeviceInfo m_info; + softbus::message_bus::ingress::IIngressPort* m_ingress{nullptr}; + std::shared_ptr m_pool; }; } // namespace softbus::devices::physical diff --git a/src/hardware/drivers/serial/SerialCapabilities.h b/src/hardware/drivers/serial/SerialCapabilities.h index 1058b0a..dd50eab 100644 --- a/src/hardware/drivers/serial/SerialCapabilities.h +++ b/src/hardware/drivers/serial/SerialCapabilities.h @@ -8,7 +8,7 @@ namespace softbus::hardware::drivers::serial::capabilities struct SerialDefaults { - int baudRate = 115200; + int baudRate = 9600; int dataBits = 8; const char* parity = "none"; int stopBits = 1; diff --git a/src/hardware/drivers/serial/SerialQtDriver.cpp b/src/hardware/drivers/serial/SerialQtDriver.cpp index a427535..58c6e0f 100644 --- a/src/hardware/drivers/serial/SerialQtDriver.cpp +++ b/src/hardware/drivers/serial/SerialQtDriver.cpp @@ -1,6 +1,8 @@ #include "hardware/drivers/serial/SerialQtDriver.h" #include +#include +#include #include "utils/logs/logging.h" @@ -22,46 +24,51 @@ SerialQtDriver::~SerialQtDriver() bool SerialQtDriver::Open(const std::string& endpoint) { - if (m_port.isOpen()) { - return true; + const QString ep = QString::fromStdString(endpoint); + if (QThread::currentThread() == this->thread()) { + return openOnOwnerThread(ep); } - m_port.setPortName(QString::fromStdString(endpoint)); - if (!m_port.open(QIODevice::ReadWrite)) { - if (m_errorCallback) { - m_errorCallback(m_port.errorString().toStdString()); - } - LOG_WARNING() << "SerialQtDriver: failed to open port" << m_port.portName() << ":" << m_port.errorString(); - return false; - } - - LOG_DEBUG() << "SerialQtDriver: opened port" << m_port.portName(); - return true; + bool ok = false; + QMetaObject::invokeMethod( + this, + [this, ep, &ok]() { ok = openOnOwnerThread(ep); }, + Qt::BlockingQueuedConnection); + return ok; } void SerialQtDriver::Close() { - if (m_port.isOpen()) { - const QString name = m_port.portName(); - m_port.close(); - LOG_DEBUG() << "SerialQtDriver: closed port" << name; + if (QThread::currentThread() == this->thread()) { + closeOnOwnerThread(); + return; } + QMetaObject::invokeMethod(this, [this]() { closeOnOwnerThread(); }, Qt::BlockingQueuedConnection); } bool SerialQtDriver::Write(const std::vector& data) { - if (!m_port.isOpen()) { - return false; + return Write(data.data(), data.size()); +} + +bool SerialQtDriver::Write(const std::uint8_t* data, std::size_t size) +{ + if (!data || size == 0) { + return true; } - const QByteArray bytes(reinterpret_cast(data.data()), static_cast(data.size())); - const qint64 written = m_port.write(bytes); - if (written != bytes.size()) { - LOG_WARNING() << "SerialQtDriver: partial write on" << m_port.portName() << "written" << written << "of" - << bytes.size(); - return false; + const QByteArray bytes(reinterpret_cast(data), static_cast(size)); + // QSerialPort 必须在其所属线程内访问;若从外部线程调用,切回 owner 线程执行。 + if (QThread::currentThread() == this->thread()) { + return writeOnOwnerThread(bytes); } - return true; + + bool ok = false; + QMetaObject::invokeMethod( + this, + [this, bytes, &ok]() { ok = writeOnOwnerThread(bytes); }, + Qt::BlockingQueuedConnection); + return ok; } void SerialQtDriver::SetReadCallback(ReadCallback cb) @@ -134,5 +141,47 @@ void SerialQtDriver::handleError(QSerialPort::SerialPortError error) } } +bool SerialQtDriver::writeOnOwnerThread(const QByteArray& bytes) +{ + if (!m_port.isOpen()) { + return false; + } + const qint64 written = m_port.write(bytes); + if (written != bytes.size()) { + LOG_WARNING() << "SerialQtDriver: partial write on" << m_port.portName() << "written" << written << "of" + << bytes.size(); + return false; + } + return true; +} + +bool SerialQtDriver::openOnOwnerThread(const QString& endpoint) +{ + if (m_port.isOpen()) { + return true; + } + + m_port.setPortName(endpoint); + if (!m_port.open(QIODevice::ReadWrite)) { + if (m_errorCallback) { + m_errorCallback(m_port.errorString().toStdString()); + } + LOG_WARNING() << "SerialQtDriver: failed to open port" << m_port.portName() << ":" << m_port.errorString(); + return false; + } + + LOG_DEBUG() << "SerialQtDriver: opened port" << m_port.portName(); + return true; +} + +void SerialQtDriver::closeOnOwnerThread() +{ + if (m_port.isOpen()) { + const QString name = m_port.portName(); + m_port.close(); + LOG_DEBUG() << "SerialQtDriver: closed port" << name; + } +} + } // namespace softbus::hardware::drivers::serial diff --git a/src/hardware/drivers/serial/SerialQtDriver.h b/src/hardware/drivers/serial/SerialQtDriver.h index 03fe2ec..8db4c07 100644 --- a/src/hardware/drivers/serial/SerialQtDriver.h +++ b/src/hardware/drivers/serial/SerialQtDriver.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "hardware/interfaces/IStreamDriver.h" @@ -60,6 +62,7 @@ public: void Close() override; bool Write(const std::vector& data) override; + bool Write(const std::uint8_t* data, std::size_t size) override; void SetReadCallback(ReadCallback cb) override; void SetErrorCallback(ErrorCallback cb) override; @@ -75,6 +78,11 @@ private slots: void handleReadyRead(); void handleError(QSerialPort::SerialPortError error); +private: + bool openOnOwnerThread(const QString& endpoint); + void closeOnOwnerThread(); + bool writeOnOwnerThread(const QByteArray& bytes); + private: QSerialPort m_port; ReadCallback m_readCallback; diff --git a/src/hardware/interfaces/IStreamDriver.h b/src/hardware/interfaces/IStreamDriver.h index 8874221..1363783 100644 --- a/src/hardware/interfaces/IStreamDriver.h +++ b/src/hardware/interfaces/IStreamDriver.h @@ -23,6 +23,7 @@ public: virtual void Close() = 0; virtual bool Write(const std::vector& data) = 0; + virtual bool Write(const std::uint8_t* data, std::size_t size) = 0; virtual void SetReadCallback(ReadCallback cb) = 0; virtual void SetErrorCallback(ErrorCallback cb) = 0; diff --git a/src/message_bus/egress/EgressRouter.cpp b/src/message_bus/egress/EgressRouter.cpp new file mode 100644 index 0000000..9e3c6fb --- /dev/null +++ b/src/message_bus/egress/EgressRouter.cpp @@ -0,0 +1,34 @@ +#include "message_bus/egress/EgressRouter.h" + +#include "devices/physical/SerialDevice.h" + +namespace softbus::message_bus::egress +{ + +void EgressRouter::bindSerialDevice( + const QString& endpoint, + const QSharedPointer& device) +{ + m_serialByEndpoint.insert(endpoint, device); +} + +void EgressRouter::unbindSerialDevice(const QString& endpoint) +{ + m_serialByEndpoint.remove(endpoint); +} + +bool EgressRouter::send(const softbus::message_bus::pipeline::PipelineContext& ctx) +{ + auto it = m_serialByEndpoint.constFind(ctx.endpoint); + if (it == m_serialByEndpoint.constEnd() || !it.value() || !ctx.payload.valid()) { + return false; + } + + const auto* p = ctx.payload.bytes(); + if (!p) { + return false; + } + return it.value()->writePayload(p, ctx.payload.length); +} + +} // namespace softbus::message_bus::egress diff --git a/src/message_bus/egress/EgressRouter.h b/src/message_bus/egress/EgressRouter.h new file mode 100644 index 0000000..4168eb5 --- /dev/null +++ b/src/message_bus/egress/EgressRouter.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include + +#include "message_bus/egress/IEgressPort.h" + +namespace softbus::devices::physical { class SerialDevice; } + +namespace softbus::message_bus::egress +{ + +class EgressRouter : public IEgressPort +{ +public: + EgressRouter() = default; + ~EgressRouter() override = default; + + void bindSerialDevice(const QString& endpoint, + const QSharedPointer& device); + void unbindSerialDevice(const QString& endpoint); + bool send(const softbus::message_bus::pipeline::PipelineContext& ctx) override; + +private: + QHash> m_serialByEndpoint; +}; + +} // namespace softbus::message_bus::egress diff --git a/src/message_bus/egress/IEgressPort.h b/src/message_bus/egress/IEgressPort.h new file mode 100644 index 0000000..cc1cb52 --- /dev/null +++ b/src/message_bus/egress/IEgressPort.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::egress +{ + +class IEgressPort +{ +public: + virtual ~IEgressPort() = default; + virtual bool send(const softbus::message_bus::pipeline::PipelineContext& ctx) = 0; +}; + +} // namespace softbus::message_bus::egress diff --git a/src/message_bus/ingress/DriverIngressAdapter.cpp b/src/message_bus/ingress/DriverIngressAdapter.cpp new file mode 100644 index 0000000..af5422e --- /dev/null +++ b/src/message_bus/ingress/DriverIngressAdapter.cpp @@ -0,0 +1,28 @@ +#include "message_bus/ingress/DriverIngressAdapter.h" + +#include "message_bus/pipeline/PipelineEngine.h" +#include "utils/logs/logging.h" + +namespace softbus::message_bus::ingress +{ + +DriverIngressAdapter::DriverIngressAdapter(std::shared_ptr pool, + softbus::message_bus::pipeline::PipelineEngine* engine) + : m_pool(std::move(pool)), m_engine(engine) +{ +} + +bool DriverIngressAdapter::push(softbus::message_bus::pipeline::PipelineContext ctx) +{ + if (!m_engine) { + return false; + } + return m_engine->enqueueIngress(std::move(ctx)); +} + +void DriverIngressAdapter::reportError(const QString& endpoint, const QString& error) +{ + LOG_WARNING() << "Ingress error endpoint=" << endpoint << "message=" << error; +} + +} // namespace softbus::message_bus::ingress diff --git a/src/message_bus/ingress/DriverIngressAdapter.h b/src/message_bus/ingress/DriverIngressAdapter.h new file mode 100644 index 0000000..65a5e25 --- /dev/null +++ b/src/message_bus/ingress/DriverIngressAdapter.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "core/memory/MemoryPool.h" +#include "message_bus/ingress/IIngressPort.h" + +namespace softbus::message_bus::pipeline { class PipelineEngine; } + +namespace softbus::message_bus::ingress +{ + +class DriverIngressAdapter : public IIngressPort +{ +public: + DriverIngressAdapter(std::shared_ptr pool, + softbus::message_bus::pipeline::PipelineEngine* engine); + + bool push(softbus::message_bus::pipeline::PipelineContext ctx) override; + void reportError(const QString& endpoint, const QString& error) override; + + softbus::core::memory::MemoryPool& pool() const { return *m_pool; } + +private: + std::shared_ptr m_pool; + softbus::message_bus::pipeline::PipelineEngine* m_engine{nullptr}; +}; + +} // namespace softbus::message_bus::ingress diff --git a/src/message_bus/ingress/IIngressPort.h b/src/message_bus/ingress/IIngressPort.h new file mode 100644 index 0000000..5eb5710 --- /dev/null +++ b/src/message_bus/ingress/IIngressPort.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::ingress +{ + +class IIngressPort +{ +public: + virtual ~IIngressPort() = default; + + virtual bool push(softbus::message_bus::pipeline::PipelineContext ctx) = 0; + virtual void reportError(const QString& endpoint, const QString& error) = 0; +}; + +} // namespace softbus::message_bus::ingress diff --git a/src/message_bus/pipeline/PayloadRef.h b/src/message_bus/pipeline/PayloadRef.h new file mode 100644 index 0000000..167305f --- /dev/null +++ b/src/message_bus/pipeline/PayloadRef.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include + +#include "core/memory/MemoryPool.h" + +namespace softbus::message_bus::pipeline +{ + +struct PayloadRef +{ + softbus::core::memory::MemoryPool::BlockPtr block; + std::size_t offset{0}; + std::size_t length{0}; + + const std::uint8_t* bytes() const + { + if (!block || !block->data || offset > block->capacity) { + return nullptr; + } + return block->data + offset; + } + + bool valid() const + { + return block && block->data && (offset + length <= block->capacity); + } +}; + +} // namespace softbus::message_bus::pipeline + +Q_DECLARE_METATYPE(softbus::message_bus::pipeline::PayloadRef) diff --git a/src/message_bus/pipeline/PipelineContext.h b/src/message_bus/pipeline/PipelineContext.h index c597f7a..63e299e 100644 --- a/src/message_bus/pipeline/PipelineContext.h +++ b/src/message_bus/pipeline/PipelineContext.h @@ -1,7 +1,30 @@ -#pragma once - -// Placeholder for pipeline context. -class PipelineContext { -public: - PipelineContext() = default; +#pragma once + +#include +#include + +#include +#include +#include + +#include "message_bus/pipeline/PayloadRef.h" + +namespace softbus::message_bus::pipeline +{ + +struct PipelineContext +{ + int deviceId{-1}; // 设备ID + QString stableKey; + QString endpoint; // 端点 + QDateTime timestamp{QDateTime::currentDateTimeUtc()}; // 时间戳 + QString protocolHint; // 协议提示 + QString traceId; // 跟踪ID + + PayloadRef payload; // 有效载荷 + std::size_t payloadSize{0}; // 有效载荷大小 }; + +} // namespace softbus::message_bus::pipeline + +Q_DECLARE_METATYPE(softbus::message_bus::pipeline::PipelineContext) diff --git a/src/message_bus/pipeline/PipelineEngine.cpp b/src/message_bus/pipeline/PipelineEngine.cpp new file mode 100644 index 0000000..d0cdbb1 --- /dev/null +++ b/src/message_bus/pipeline/PipelineEngine.cpp @@ -0,0 +1,142 @@ +#include "message_bus/pipeline/PipelineEngine.h" + +#include + +#include "utils/logs/logging.h" + +namespace softbus::message_bus::pipeline +{ + +PipelineEngine::PipelineEngine(std::size_t queueCapacity) + : m_ingressQ(queueCapacity), m_egressQ(queueCapacity) +{ +} + +PipelineEngine::~PipelineEngine() +{ + stop(); +} + +void PipelineEngine::start() +{ + if (m_running.exchange(true)) { + return; + } + m_worker = std::thread([this]() { run(); }); +} + +void PipelineEngine::stop() +{ + if (!m_running.exchange(false)) { + return; + } + if (m_worker.joinable()) { + m_worker.join(); + } +} + +void PipelineEngine::drain() +{ + PipelineContext tmp; + while (m_ingressQ.pop(tmp)) { + } +} + +bool PipelineEngine::enqueueIngress(PipelineContext ctx) +{ + if (!m_ingressQ.push(std::move(ctx))) { + ++m_counters.drop; + return false; + } + ++m_counters.in; + return true; +} + +bool PipelineEngine::enqueueEgress(PipelineContext ctx) +{ + return m_egressQ.push(std::move(ctx)); +} + +bool PipelineEngine::tryPopEgress(PipelineContext& out) +{ + return m_egressQ.pop(out); +} + +void PipelineEngine::setPluginManager(std::shared_ptr pluginManager) +{ + m_pluginManager = std::move(pluginManager); +} + +void PipelineEngine::run() +{ + while (m_running.load()) { + PipelineContext ctx; + if (!m_ingressQ.pop(ctx)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + const bool framed = stage1Framer(ctx); + const bool parsed = framed && stage2Parser(ctx); + const bool filtered = parsed && stage3Filter(ctx); + const bool valid = filtered && stage4Validator(ctx); + if (!valid) { + ++m_counters.error; + continue; + } + if (!m_egressQ.push(std::move(ctx))) { + ++m_counters.drop; + continue; + } + ++m_counters.out; + } +} + +bool PipelineEngine::stage1Framer(PipelineContext& ctx) +{ + if (!ctx.payload.valid()) { + return false; + } + if (ctx.payloadSize == 0) { + ctx.payloadSize = ctx.payload.length; + } + return true; +} + +bool PipelineEngine::stage4Validator(PipelineContext& ctx) +{ + if (!ctx.payload.valid()) { + return false; + } + if (ctx.endpoint.isEmpty()) { + return false; + } + if (!ctx.timestamp.isValid()) { + ctx.timestamp = QDateTime::currentDateTimeUtc(); + } + return true; +} + +bool PipelineEngine::stage2Parser(PipelineContext& ctx) +{ + if (!m_pluginManager) { + return true; + } + auto plugin = m_pluginManager->selectProtocolPlugin(ctx.protocolHint); + if (!plugin) { + return true; + } + auto session = plugin->createSession(); + if (!session) { + return false; + } + return session->feed(ctx); +} + +bool PipelineEngine::stage3Filter(PipelineContext& ctx) +{ + (void)ctx; + return true; +} + +} // namespace softbus::message_bus::pipeline diff --git a/src/message_bus/pipeline/PipelineEngine.h b/src/message_bus/pipeline/PipelineEngine.h index 2d51e69..c11ccb7 100644 --- a/src/message_bus/pipeline/PipelineEngine.h +++ b/src/message_bus/pipeline/PipelineEngine.h @@ -1,7 +1,56 @@ -#pragma once - -// Placeholder for pipeline engine. -class PipelineEngine { -public: - PipelineEngine() = default; +#pragma once + +#include +#include +#include + +#include "core/plugin_system/PluginManager.h" +#include "core/memory/LockFreeQueue.h" +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::pipeline +{ + +class PipelineEngine +{ +public: + struct Counters + { + std::atomic in{0}; + std::atomic out{0}; + std::atomic drop{0}; + std::atomic error{0}; + }; + + explicit PipelineEngine(std::size_t queueCapacity = 4096); + ~PipelineEngine(); + + void start(); + void stop(); + void drain(); + + bool enqueueIngress(PipelineContext ctx); + bool enqueueEgress(PipelineContext ctx); + + bool tryPopEgress(PipelineContext& out); + void setPluginManager(std::shared_ptr pluginManager); + + const Counters& counters() const { return m_counters; } + +private: + void run(); + bool stage1Framer(PipelineContext& ctx); + bool stage2Parser(PipelineContext& ctx); + bool stage3Filter(PipelineContext& ctx); + bool stage4Validator(PipelineContext& ctx); + +private: + softbus::core::memory::LockFreeQueue m_ingressQ; + softbus::core::memory::LockFreeQueue m_egressQ; + std::atomic m_running{false}; + std::thread m_worker; + Counters m_counters; + std::shared_ptr m_pluginManager; }; + +} // namespace softbus::message_bus::pipeline diff --git a/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp b/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp new file mode 100644 index 0000000..c69ba71 --- /dev/null +++ b/src/message_bus/pipeline/stages/1_framers/DefaultFramer.cpp @@ -0,0 +1,8 @@ +#include "message_bus/pipeline/stages/1_framers/IFramer.h" + +namespace softbus::message_bus::pipeline::stages::framers +{ + +// Placeholder TU for stage1 concrete framer implementations. + +} // namespace softbus::message_bus::pipeline::stages::framers diff --git a/src/message_bus/pipeline/stages/1_framers/IFramer.h b/src/message_bus/pipeline/stages/1_framers/IFramer.h new file mode 100644 index 0000000..628fe2b --- /dev/null +++ b/src/message_bus/pipeline/stages/1_framers/IFramer.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::pipeline::stages::framers +{ + +class IFramer +{ +public: + virtual ~IFramer() = default; + virtual bool frame(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; +}; + +} // namespace softbus::message_bus::pipeline::stages::framers diff --git a/src/message_bus/pipeline/stages/2_parsers/IParserStage.h b/src/message_bus/pipeline/stages/2_parsers/IParserStage.h new file mode 100644 index 0000000..0e64001 --- /dev/null +++ b/src/message_bus/pipeline/stages/2_parsers/IParserStage.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::pipeline::stages::parsers +{ + +class IParserStage +{ +public: + virtual ~IParserStage() = default; + virtual bool parse(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; +}; + +} // namespace softbus::message_bus::pipeline::stages::parsers diff --git a/src/message_bus/pipeline/stages/3_filters/IFilterStage.h b/src/message_bus/pipeline/stages/3_filters/IFilterStage.h new file mode 100644 index 0000000..81741d4 --- /dev/null +++ b/src/message_bus/pipeline/stages/3_filters/IFilterStage.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::pipeline::stages::filters +{ + +class IFilterStage +{ +public: + virtual ~IFilterStage() = default; + virtual bool apply(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; +}; + +} // namespace softbus::message_bus::pipeline::stages::filters diff --git a/src/message_bus/pipeline/stages/4_validators/IValidator.h b/src/message_bus/pipeline/stages/4_validators/IValidator.h new file mode 100644 index 0000000..19fea06 --- /dev/null +++ b/src/message_bus/pipeline/stages/4_validators/IValidator.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message_bus/pipeline/PipelineContext.h" + +namespace softbus::message_bus::pipeline::stages::validators +{ + +class IValidator +{ +public: + virtual ~IValidator() = default; + virtual bool validate(softbus::message_bus::pipeline::PipelineContext& ctx) = 0; +}; + +} // namespace softbus::message_bus::pipeline::stages::validators