This commit is contained in:
flower_linux
2026-03-12 14:56:53 +08:00
parent 22ee28f33b
commit 9a2224f185
62 changed files with 1597 additions and 505 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

164
.gitignore vendored
View File

@@ -1,82 +1,82 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
*.qbs.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
# Directories with generated files
.moc/
.obj/
.pch/
.rcc/
.uic/
/build*/
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
*.qbs.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
# Directories with generated files
.moc/
.obj/
.pch/
.rcc/
.uic/
/build*/

View File

@@ -1,85 +1,116 @@
cmake_minimum_required(VERSION 3.19)
project(soft_bus_daemon
LANGUAGES CXX
VERSION 1.0.0
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
# Output layout
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/plugins)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/plugins)
# 启用AddressSanitizer仅在非Windows平台上
if(NOT WIN32)
set(SANITIZE_FLAGS "-fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
else()
message(STATUS "AddressSanitizer disabled on Windows because the runtime is unavailable in the MinGW kit.")
endif()
# 设置C++标准
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
# 查找Qt6守护进程只需要 Core/DBus/Network/SerialPort/Sql
find_package(Qt6 6.5 REQUIRED COMPONENTS Core SerialPort Network Sql DBus)
# 检测编译平台
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
set(PlatformDir "x86")
else()
set(PlatformDir "x64")
endif()
qt_standard_project_setup()
# 添加软总线模板库
# 1. 日志库
qt_add_library(softbus_template
src/utils/logs/logging.h
src/utils/logs/LogStream.h
)
qt_add_executable(softbus_daemon
main.cpp
src/core/CoreService.cpp
# api 接口
src/api/ipc_dbus/IpcDBus.h
src/api/ipc_dbus/IpcDBus.cpp
)
target_include_directories(softbus_daemon
PRIVATE
${CMAKE_SOURCE_DIR}
)
target_link_libraries(softbus_daemon
PRIVATE
Qt::Core
Qt6::DBus
Qt6::SerialPort
Qt6::Network
)
add_subdirectory(plugins)
install(TARGETS softbus_daemon
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
cmake_minimum_required(VERSION 3.19)
project(soft_bus_daemon
LANGUAGES CXX
VERSION 1.0.0
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
# Output layout
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/plugins)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/plugins)
# 启用AddressSanitizer仅在非Windows平台上
if(NOT WIN32)
set(SANITIZE_FLAGS "-fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
else()
message(STATUS "AddressSanitizer disabled on Windows because the runtime is unavailable in the MinGW kit.")
endif()
# 设置C++标准
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
# 查找Qt6守护进程只需要 Core/DBus/Network/SerialPort/Sql
find_package(Qt6 6.5 REQUIRED COMPONENTS Core SerialPort Network Sql DBus)
# 检测编译平台
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
set(PlatformDir "x86")
else()
set(PlatformDir "x64")
endif()
qt_standard_project_setup()
# 添加软总线模板库
# 1. 日志库
qt_add_library(softbus_template
src/utils/logs/logging.h
src/utils/logs/LogStream.h
)
qt_add_executable(softbus_daemon
main.cpp
src/core/CoreService.cpp
# core device types
src/core/device/DeviceTypes.h
src/core/device/DeviceTypes.cpp
# api 接口
src/api/ipc_dbus/IpcDBus.h
src/api/ipc_dbus/IpcDBus.cpp
# hardware interfaces (Level 2)
src/hardware/interfaces/IStreamDriver.h
src/hardware/interfaces/IFrameDriver.h
src/hardware/interfaces/IDeviceWatcher.h
# hardware drivers (Level 2)
src/hardware/drivers/serial/SerialQtDriver.h
src/hardware/drivers/serial/SerialQtDriver.cpp
src/hardware/drivers/serial/SerialCapabilities.h
# device bus: tree & capabilities
src/device_bus/tree/DeviceTreeModel.h
src/device_bus/tree/DeviceTreeModel.cpp
src/device_bus/capabilities/DriverCapabilityProvider.h
src/device_bus/capabilities/DriverCapabilityProvider.cpp
# device bus: facade & manager
src/device_bus/DeviceBus.h
src/device_bus/DeviceBus.cpp
src/device_bus/manager/DeviceBusManager.h
src/device_bus/manager/DeviceBusManager.cpp
# device bus: registry skeleton
src/device_bus/registry/IDeviceRegistry.h
# devices: base skeleton
src/devices/base/IDevice.h
)
target_include_directories(softbus_daemon
PRIVATE
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(softbus_daemon
PRIVATE
Qt::Core
Qt6::DBus
Qt6::SerialPort
Qt6::Network
)
add_subdirectory(plugins)
install(TARGETS softbus_daemon
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

Binary file not shown.

View File

@@ -1,5 +1,23 @@
{
"plugin_dir": "bin/plugins",
"device_tree": [],
"routes": []
}
{
"plugin_dir": "bin/plugins",
"device_tree": [
{
"id": "serial_1",
"name": "Serial Device 1",
"type": "serial",
"endpoint": "/dev/ttyS1",
"driver": "hardware/drivers/serial/SerialQtDriver",
"capabilitiesRef": "src/hardware/drivers/serial/parameters.json",
"params": {
"baudRate": 115200,
"dataBits": 8,
"parity": "none",
"stopBits": 1,
"flowControl": "none"
},
"children": [],
"enabled": true
}
],
"routes": []
}

View File

@@ -2,4 +2,4 @@
"modbus_rtu": {
"register_map": []
}
}
}

272
main.cpp
View File

@@ -1,136 +1,136 @@
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDBusConnection>
#include <QDBusError>
#include <signal.h>
#include "src/utils/logs/logging.h"
#include "src/core/CoreService.h"
#include "src/api/ipc_dbus/IpcDBus.h"
void signalHandler(int signal)
{
LOG_INFO() << "Received signal:" << signal;
QCoreApplication::quit();
}
int main(int argc, char *argv[])
{
// ==================================
// 创建并配置 Qt 应用程序对象
// ==================================
QCoreApplication app(argc, argv);
app.setApplicationName("soft_bus_daemon");
app.setApplicationVersion("1.0.0");
app.setOrganizationName("soft_bus");
// ==================================
// 设置 Qt 应用程序信息
// ==================================
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Soft Bus Daemon"));
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption roleOption(QStringLiteral("role"),
QStringLiteral("Daemon role (CoreRouter, CollectorSerial, CollectorCan, Collector, SqlServer)"),
QStringLiteral("role"),
QStringLiteral("CoreRouter"));
parser.addOption(roleOption);
QCommandLineOption dbusBusOption(QStringLiteral("dbus-bus"),
QStringLiteral("DBus bus to use: system|session|auto (default: auto)"),
QStringLiteral("bus"),
QStringLiteral("auto"));
parser.addOption(dbusBusOption);
parser.process(app);
const QString roleString = parser.value(roleOption).trimmed();
const QString dbusBus = parser.value(dbusBusOption).trimmed();
CoreService::Role role = CoreService::Role::CoreRouter; // 默认角色
if (roleString == QStringLiteral("CoreRouter")) {
role = CoreService::Role::CoreRouter;
} else if (roleString == QStringLiteral("CollectorSerial")) {
role = CoreService::Role::CollectorSerial;
} else if (roleString == QStringLiteral("CollectorCan")) {
role = CoreService::Role::CollectorCan;
} else if (roleString == QStringLiteral("Collector")) {
role = CoreService::Role::Collector;
} else if (roleString == QStringLiteral("SqlServer")) {
role = CoreService::Role::SqlServer;
} else {
LOG_ERROR() << "Invalid role:" << roleString
<< "valid roles are: CoreRouter, CollectorSerial, CollectorCan, Collector, SqlServer";
return 1;
}
CoreService* coreService = CoreService::instance();
if (!coreService->initialize()) {
LOG_ERROR() << "CoreService initialize failed";
return 1;
}
QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
// ========================================================================
// 创建并注册 D-Bus 服务(仅在 CoreRouter 角色中启用)
// ========================================================================
if (role == CoreService::Role::CoreRouter) {
const QString serviceName = QStringLiteral("com.softbus.Daemon");
const QString objectPath = QStringLiteral("/com/softbus/Daemon");
IpcDBus* ipc = new IpcDBus(coreService, roleString, &app);
auto pickConnection = [&]() -> QDBusConnection {
if (dbusBus == QStringLiteral("system")) {
return QDBusConnection::systemBus();
}
if (dbusBus == QStringLiteral("session")) {
return QDBusConnection::sessionBus();
}
// auto: 优先 system更符合 daemon失败则退回 session方便本地开发
QDBusConnection conn = QDBusConnection::systemBus();
if (conn.isConnected()) {
return conn;
}
return QDBusConnection::sessionBus();
};
QDBusConnection connection = pickConnection();
if (!connection.isConnected()) {
LOG_ERROR() << "Cannot connect to D-Bus. system error="
<< QDBusConnection::systemBus().lastError().message()
<< " session error=" << QDBusConnection::sessionBus().lastError().message();
return 1;
}
if (!connection.registerService(serviceName)) {
LOG_ERROR() << "Failed to register D-Bus service:" << serviceName
<< "error=" << connection.lastError().message();
return 1;
}
if (!connection.registerObject(objectPath,
ipc,
QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) {
LOG_ERROR() << "Failed to register D-Bus object:" << objectPath
<< "error=" << connection.lastError().message();
return 1;
}
LOG_INFO() << "D-Bus ready. bus="
<< (connection.name() == QDBusConnection::systemBus().name() ? "system" : "session")
<< " service=" << serviceName
<< " object=" << objectPath;
}
// ==================================
// 处理系统信号,确保在接收到 SIGINT 或 SIGTERM 时能够优雅地退出
// ==================================
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
int ret = app.exec();
return ret;
}
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDBusConnection>
#include <QDBusError>
#include <signal.h>
#include "src/utils/logs/logging.h"
#include "src/core/CoreService.h"
#include "src/api/ipc_dbus/IpcDBus.h"
void signalHandler(int signal)
{
LOG_INFO() << "Received signal:" << signal;
QCoreApplication::quit();
}
int main(int argc, char *argv[])
{
// ==================================
// 创建并配置 Qt 应用程序对象
// ==================================
QCoreApplication app(argc, argv);
app.setApplicationName("soft_bus_daemon");
app.setApplicationVersion("1.0.0");
app.setOrganizationName("soft_bus");
// ==================================
// 设置 Qt 应用程序信息
// ==================================
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Soft Bus Daemon"));
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption roleOption(QStringLiteral("role"),
QStringLiteral("Daemon role (CoreRouter, CollectorSerial, CollectorCan, Collector, SqlServer)"),
QStringLiteral("role"),
QStringLiteral("CoreRouter"));
parser.addOption(roleOption);
QCommandLineOption dbusBusOption(QStringLiteral("dbus-bus"),
QStringLiteral("DBus bus to use: system|session|auto (default: auto)"),
QStringLiteral("bus"),
QStringLiteral("auto"));
parser.addOption(dbusBusOption);
parser.process(app);
const QString roleString = parser.value(roleOption).trimmed();
const QString dbusBus = parser.value(dbusBusOption).trimmed();
CoreService::Role role = CoreService::Role::CoreRouter; // 默认角色
if (roleString == QStringLiteral("CoreRouter")) {
role = CoreService::Role::CoreRouter;
} else if (roleString == QStringLiteral("CollectorSerial")) {
role = CoreService::Role::CollectorSerial;
} else if (roleString == QStringLiteral("CollectorCan")) {
role = CoreService::Role::CollectorCan;
} else if (roleString == QStringLiteral("Collector")) {
role = CoreService::Role::Collector;
} else if (roleString == QStringLiteral("SqlServer")) {
role = CoreService::Role::SqlServer;
} else {
LOG_ERROR() << "Invalid role:" << roleString
<< "valid roles are: CoreRouter, CollectorSerial, CollectorCan, Collector, SqlServer";
return 1;
}
CoreService* coreService = CoreService::instance();
if (!coreService->initialize()) {
LOG_ERROR() << "CoreService initialize failed";
return 1;
}
QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
// ========================================================================
// 创建并注册 D-Bus 服务(仅在 CoreRouter 角色中启用)
// ========================================================================
if (role == CoreService::Role::CoreRouter) {
const QString serviceName = QStringLiteral("com.softbus.Daemon");
const QString objectPath = QStringLiteral("/com/softbus/Daemon");
IpcDBus* ipc = new IpcDBus(coreService, roleString, &app);
auto pickConnection = [&]() -> QDBusConnection {
if (dbusBus == QStringLiteral("system")) {
return QDBusConnection::systemBus();
}
if (dbusBus == QStringLiteral("session")) {
return QDBusConnection::sessionBus();
}
// auto: 优先 system更符合 daemon失败则退回 session方便本地开发
QDBusConnection conn = QDBusConnection::systemBus();
if (conn.isConnected()) {
return conn;
}
return QDBusConnection::sessionBus();
};
QDBusConnection connection = pickConnection();
if (!connection.isConnected()) {
LOG_ERROR() << "Cannot connect to D-Bus. system error="
<< QDBusConnection::systemBus().lastError().message()
<< " session error=" << QDBusConnection::sessionBus().lastError().message();
return 1;
}
if (!connection.registerService(serviceName)) {
LOG_ERROR() << "Failed to register D-Bus service:" << serviceName
<< "error=" << connection.lastError().message();
return 1;
}
if (!connection.registerObject(objectPath,
ipc,
QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) {
LOG_ERROR() << "Failed to register D-Bus object:" << objectPath
<< "error=" << connection.lastError().message();
return 1;
}
LOG_INFO() << "D-Bus ready. bus="
<< (connection.name() == QDBusConnection::systemBus().name() ? "system" : "session")
<< " service=" << serviceName
<< " object=" << objectPath;
}
// ==================================
// 处理系统信号,确保在接收到 SIGINT 或 SIGTERM 时能够优雅地退出
// ==================================
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
int ret = app.exec();
return ret;
}

View File

@@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.19)
add_subdirectory(protocols/modbus_rtu)
add_subdirectory(protocols/can_raw)
add_subdirectory(protocols/custom_proto)
add_subdirectory(filters)
add_subdirectory(filters)

View File

@@ -1 +1 @@
# Placeholder for filter plugins
# Placeholder for filter plugins

View File

@@ -1,3 +1,3 @@
# Placeholder for can_raw plugin
add_library(can_raw SHARED)
set_target_properties(can_raw PROPERTIES OUTPUT_NAME "can_raw")
set_target_properties(can_raw PROPERTIES OUTPUT_NAME "can_raw")

View File

@@ -1,3 +1,3 @@
# Placeholder for custom_proto plugin
add_library(custom_proto SHARED)
set_target_properties(custom_proto PROPERTIES OUTPUT_NAME "custom_proto")
set_target_properties(custom_proto PROPERTIES OUTPUT_NAME "custom_proto")

View File

@@ -1,3 +1,3 @@
# Placeholder for modbus_rtu plugin
add_library(modbus_rtu SHARED)
set_target_properties(modbus_rtu PROPERTIES OUTPUT_NAME "modbus_rtu")
set_target_properties(modbus_rtu PROPERTIES OUTPUT_NAME "modbus_rtu")

View File

@@ -1,75 +1,75 @@
#include "IpcDBus.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include "src/core/CoreService.h"
IpcDBus::IpcDBus(CoreService* coreService, const QString& role, QObject* parent)
: QObject(parent),
m_coreService(coreService),
m_role(role)
{
}
IpcDBus::~IpcDBus() = default;
bool IpcDBus::isRunning() const
{
if (!m_coreService) {
return false;
}
return m_coreService->isInitialized();
}
QString IpcDBus::ping() const
{
return QStringLiteral("pong");
}
QString IpcDBus::getVersion() const
{
return QCoreApplication::applicationVersion();
}
QString IpcDBus::getStatus() const
{
QJsonObject obj;
obj.insert(QStringLiteral("service"), QStringLiteral("com.softbus.Daemon"));
obj.insert(QStringLiteral("objectPath"), QStringLiteral("/com/softbus/Daemon"));
obj.insert(QStringLiteral("interface"), QStringLiteral("com.softbus.Daemon"));
obj.insert(QStringLiteral("pid"), static_cast<qint64>(QCoreApplication::applicationPid()));
obj.insert(QStringLiteral("role"), m_role);
obj.insert(QStringLiteral("running"), isRunning());
obj.insert(QStringLiteral("timestampMs"), static_cast<qint64>(QDateTime::currentMSecsSinceEpoch()));
const QJsonDocument doc(obj);
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
qint64 IpcDBus::getPid() const
{
return static_cast<qint64>(QCoreApplication::applicationPid());
}
void IpcDBus::shutdown()
{
if (m_coreService) {
m_coreService->shutdown();
}
QCoreApplication::quit();
}
bool IpcDBus::reloadConfig()
{
// 占位:后续移植配置系统时在这里触发 reload
return false;
}
void IpcDBus::updateLoadInfo()
{
// 预留:后续可在此周期性采样 CPU/内存/队列长度等指标,并通过 getStatus() 输出
}
#include "IpcDBus.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include "src/core/CoreService.h"
IpcDBus::IpcDBus(CoreService* coreService, const QString& role, QObject* parent)
: QObject(parent),
m_coreService(coreService),
m_role(role)
{
}
IpcDBus::~IpcDBus() = default;
bool IpcDBus::isRunning() const
{
if (!m_coreService) {
return false;
}
return m_coreService->isInitialized();
}
QString IpcDBus::ping() const
{
return QStringLiteral("pong");
}
QString IpcDBus::getVersion() const
{
return QCoreApplication::applicationVersion();
}
QString IpcDBus::getStatus() const
{
QJsonObject obj;
obj.insert(QStringLiteral("service"), QStringLiteral("com.softbus.Daemon"));
obj.insert(QStringLiteral("objectPath"), QStringLiteral("/com/softbus/Daemon"));
obj.insert(QStringLiteral("interface"), QStringLiteral("com.softbus.Daemon"));
obj.insert(QStringLiteral("pid"), static_cast<qint64>(QCoreApplication::applicationPid()));
obj.insert(QStringLiteral("role"), m_role);
obj.insert(QStringLiteral("running"), isRunning());
obj.insert(QStringLiteral("timestampMs"), static_cast<qint64>(QDateTime::currentMSecsSinceEpoch()));
const QJsonDocument doc(obj);
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
qint64 IpcDBus::getPid() const
{
return static_cast<qint64>(QCoreApplication::applicationPid());
}
void IpcDBus::shutdown()
{
if (m_coreService) {
m_coreService->shutdown();
}
QCoreApplication::quit();
}
bool IpcDBus::reloadConfig()
{
// 占位:后续移植配置系统时在这里触发 reload
return false;
}
void IpcDBus::updateLoadInfo()
{
// 预留:后续可在此周期性采样 CPU/内存/队列长度等指标,并通过 getStatus() 输出
}

View File

@@ -1,70 +1,70 @@
/**
* @file Ipc_dbus.h
* @brief D-Bus 服务接口 - 提供核心服务状态和负载查询
*/
#ifndef IPC_DBUS_H
#define IPC_DBUS_H
#include <QObject>
#include <QString>
// 前向声明
class CoreService;
/**
* @brief D-Bus 服务适配器 - 暴露核心服务接口
*/
class IpcDBus : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.softbus.Daemon")
public:
explicit IpcDBus(CoreService* coreService, const QString& role, QObject* parent = nullptr);
~IpcDBus();
public slots:
/**
* @brief 检查核心服务是否运行
* @return true 如果核心服务正在运行
*/
bool isRunning() const;
QString ping() const;
QString getVersion() const;
/**
* @brief 获取核心服务状态信息
* @return JSON 格式的状态信息
*/
QString getStatus() const;
/**
* @brief 获取守护进程的进程ID
* @return 进程ID如果无法获取则返回0
*/
qint64 getPid() const;
/**
* @brief 关闭守护进程
*/
void shutdown();
bool reloadConfig();
private slots:
void updateLoadInfo();
private:
CoreService* m_coreService{nullptr}; // non-owning
QString m_role;
};
#endif // IPC_DBUS_H
/**
* @file Ipc_dbus.h
* @brief D-Bus 服务接口 - 提供核心服务状态和负载查询
*/
#ifndef IPC_DBUS_H
#define IPC_DBUS_H
#include <QObject>
#include <QString>
// 前向声明
class CoreService;
/**
* @brief D-Bus 服务适配器 - 暴露核心服务接口
*/
class IpcDBus : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.softbus.Daemon")
public:
explicit IpcDBus(CoreService* coreService, const QString& role, QObject* parent = nullptr);
~IpcDBus();
public slots:
/**
* @brief 检查核心服务是否运行
* @return true 如果核心服务正在运行
*/
bool isRunning() const;
QString ping() const;
QString getVersion() const;
/**
* @brief 获取核心服务状态信息
* @return JSON 格式的状态信息
*/
QString getStatus() const;
/**
* @brief 获取守护进程的进程ID
* @return 进程ID如果无法获取则返回0
*/
qint64 getPid() const;
/**
* @brief 关闭守护进程
*/
void shutdown();
bool reloadConfig();
private slots:
void updateLoadInfo();
private:
CoreService* m_coreService{nullptr}; // non-owning
QString m_role;
};
#endif // IPC_DBUS_H

View File

@@ -1,5 +1,14 @@
#include "CoreService.h"
#include "../utils/logs/logging.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDir>
#include <QFileInfo>
#include "utils/logs/logging.h"
#include "device_bus/DeviceBus.h"
CoreService* CoreService::instance()
{
@@ -26,6 +35,34 @@ bool CoreService::initialize()
}
LOG_INFO() << "CoreService initializing";
// 1. 解析配置路径(放在用户 home 下的相对固定目录:~/softbus/config
const QString configPath =
QDir::homePath() + QStringLiteral("/softbus/config/daemon_config.json");
QFile f(configPath);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_ERROR() << "CoreService: failed to open" << configPath;
return false;
}
const QByteArray data = f.readAll();
f.close();
QJsonParseError pe;
const QJsonDocument doc = QJsonDocument::fromJson(data, &pe);
if (pe.error != QJsonParseError::NoError || !doc.isObject()) {
LOG_ERROR() << "CoreService: invalid JSON in" << configPath << ":" << pe.errorString();
return false;
}
const QJsonObject root = doc.object();
// 2. 初始化 device_bus交给 DeviceBus facade 处理具体设备)
if (!softbus::device_bus::DeviceBus::instance().initialize(root)) {
return false;
}
m_initialized = true;
return true;
}
@@ -38,6 +75,7 @@ void CoreService::shutdown()
}
LOG_INFO() << "CoreService shutting down";
softbus::device_bus::DeviceBus::instance().shutdown();
m_initialized = false;
}

View File

@@ -2,6 +2,7 @@
#include <QObject>
class CoreService : public QObject {
Q_OBJECT

View File

@@ -0,0 +1,39 @@
#include "core/device/DeviceTypes.h"
namespace softbus::core::device
{
DeviceKind kindFromType(const QString& typeStr)
{
const QString t = typeStr.trimmed().toLower();
if (t == QStringLiteral("serial")) return DeviceKind::Serial;
if (t == QStringLiteral("can")) return DeviceKind::Can;
if (t == QStringLiteral("ethernet") || t == QStringLiteral("network")) return DeviceKind::Network;
if (t == QStringLiteral("virtual")) return DeviceKind::Virtual;
if (t == QStringLiteral("distributed")) return DeviceKind::Distributed;
return DeviceKind::Unknown;
}
DeviceKind inferDeviceKindFromEndpoint(const QString& endpoint)
{
const QString ep = endpoint.trimmed();
if (ep.startsWith(QStringLiteral("/dev/tty"))) return DeviceKind::Serial;
if (ep.startsWith(QStringLiteral("can"))) return DeviceKind::Can;
if (ep.startsWith(QStringLiteral("tcp://")) || ep.startsWith(QStringLiteral("udp://"))) return DeviceKind::Network;
return DeviceKind::Unknown;
}
QString driverKeyFor(DeviceKind kind)
{
switch (kind) {
case DeviceKind::Serial: return QStringLiteral("serial_qt");
case DeviceKind::Can: return QStringLiteral("can_socketcan");
case DeviceKind::Network: return QStringLiteral("tcp_qt");
case DeviceKind::Virtual: return QStringLiteral("virtual_device");
case DeviceKind::Distributed: return QStringLiteral("distributed_node");
default: return QStringLiteral("unknown");
}
}
} // namespace softbus::core::device

View File

@@ -0,0 +1,69 @@
#pragma once
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#include <QString>
namespace softbus::core::device
{
enum class DeviceKind {
Serial,
Can,
Network,
Virtual,
Distributed,
Unknown,
};
struct DeviceInfo
{
int id{0};
QString endpoint;
QString name;
QString type; // "serial" / "can" / "network" / ...
int address{0};
QString protocol;
QString protocolDetail;
QJsonObject properties;
QString status{QStringLiteral("online")};
bool isActive{true};
QDateTime lastSeen;
QString toJson() const
{
QJsonObject obj;
obj[QStringLiteral("id")] = id;
obj[QStringLiteral("endpoint")] = endpoint;
obj[QStringLiteral("name")] = name;
obj[QStringLiteral("type")] = type;
obj[QStringLiteral("address")] = address;
obj[QStringLiteral("protocol")] = protocol;
obj[QStringLiteral("protocol_detail")] = protocolDetail;
obj[QStringLiteral("properties")] = properties;
obj[QStringLiteral("status")] = status;
obj[QStringLiteral("isActive")] = isActive;
if (lastSeen.isValid()) {
obj[QStringLiteral("lastSeen")] = lastSeen.toString(Qt::ISODate);
}
const QJsonDocument doc(obj);
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
};
struct BusMessage
{
QString id;
QString source;
QString destination;
QJsonObject payload;
qint64 timestamp{0};
};
DeviceKind kindFromType(const QString& typeStr);
DeviceKind inferDeviceKindFromEndpoint(const QString& endpoint);
QString driverKeyFor(DeviceKind kind);
} // namespace softbus::core::device

View File

@@ -4,4 +4,4 @@
class LockFreeQueue {
public:
LockFreeQueue() = default;
};
};

View File

@@ -4,4 +4,4 @@
class MemoryPool {
public:
MemoryPool() = default;
};
};

View File

@@ -2,4 +2,4 @@
// Placeholder for data trace model.
struct DataTrace {
};
};

View File

@@ -2,4 +2,4 @@
// Placeholder for metadata model.
struct Metadata {
};
};

View File

@@ -4,4 +4,4 @@
class IProtocolPlugin {
public:
virtual ~IProtocolPlugin() = default;
};
};

View File

@@ -4,4 +4,4 @@
class PluginManager {
public:
PluginManager() = default;
};
};

View File

@@ -0,0 +1,30 @@
#include "device_bus/DeviceBus.h"
#include "device_bus/manager/DeviceBusManager.h"
namespace softbus::device_bus {
class DeviceBus::Impl {
public:
DeviceBusManager manager;
};
DeviceBus &DeviceBus::instance() {
static DeviceBus inst;
return inst;
}
DeviceBus::DeviceBus() : d(new Impl()) {}
DeviceBus::~DeviceBus() {
delete d;
d = nullptr;
}
bool DeviceBus::initialize(const QJsonObject &rootConfig) {
return d->manager.initialize(rootConfig);
}
void DeviceBus::shutdown() { d->manager.shutdown(); }
} // namespace softbus::device_bus

View File

@@ -0,0 +1,24 @@
#pragma once
#include <QJsonObject>
namespace softbus::device_bus {
class DeviceBus {
public:
static DeviceBus &instance();
bool initialize(const QJsonObject &rootConfig);
void shutdown();
private:
DeviceBus();
~DeviceBus();
DeviceBus(const DeviceBus &) = delete;
DeviceBus &operator=(const DeviceBus &) = delete;
class Impl;
Impl *d;
};
} // namespace softbus::device_bus

View File

@@ -0,0 +1,77 @@
#include "device_bus/capabilities/DriverCapabilityProvider.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include "utils/logs/logging.h"
bool DriverCapabilityProvider::loadFromFile(const QString& jsonPath, QString* errorMessage)
{
m_defaults = QJsonObject();
m_enums = QJsonObject();
QFile f(jsonPath);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (errorMessage) {
*errorMessage = QStringLiteral("Failed to open capability file: %1").arg(jsonPath);
}
return false;
}
const QByteArray data = f.readAll();
f.close();
QJsonParseError pe;
const QJsonDocument doc = QJsonDocument::fromJson(data, &pe);
if (pe.error != QJsonParseError::NoError || !doc.isObject()) {
if (errorMessage) {
*errorMessage = QStringLiteral("Invalid JSON in capability file %1: %2")
.arg(jsonPath, pe.errorString());
}
return false;
}
const QJsonObject root = doc.object();
m_defaults = root.value(QStringLiteral("defaults")).toObject();
m_enums = root.value(QStringLiteral("enums")).toObject();
LOG_INFO() << "DriverCapabilityProvider loaded from" << jsonPath;
return true;
}
QJsonObject DriverCapabilityProvider::mergeAndValidateParams(const QJsonObject& nodeParams) const
{
// 1. 从 defaults 拷贝一份出来
QJsonObject result = m_defaults;
// 2. 覆盖节点里的显式参数
for (auto it = nodeParams.constBegin(); it != nodeParams.constEnd(); ++it) {
const QString key = it.key();
const QJsonValue value = it.value();
// 如果存在枚举限制,则先校验
const QJsonValue enumVal = m_enums.value(key);
if (enumVal.isArray()) {
const QJsonArray arr = enumVal.toArray();
bool ok = false;
for (const QJsonValue& candidate : arr) {
if (candidate == value) {
ok = true;
break;
}
}
if (!ok) {
LOG_WARNING() << "DriverCapabilityProvider: param" << key
<< "value" << value.toVariant()
<< "not in allowed enum, keep default";
continue; // 不覆盖默认值
}
}
result.insert(key, value);
}
return result;
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <QJsonObject>
#include <QString>
// 负责加载 drivers 下的 parameters.json并对节点 params 做默认值合并与简单枚举校验
class DriverCapabilityProvider
{
public:
// 从给定路径加载能力描述(如 "src/hardware/drivers/serial/parameters.json"
bool loadFromFile(const QString& jsonPath, QString* errorMessage = nullptr);
// 将节点 params 与 defaults 合并,并按 enums 做简单校验
QJsonObject mergeAndValidateParams(const QJsonObject& nodeParams) const;
private:
QJsonObject m_defaults;
QJsonObject m_enums;
};

View File

@@ -0,0 +1,124 @@
#include "device_bus/manager/DeviceBusManager.h"
#include <QJsonDocument>
#include <algorithm>
#include "hardware/drivers/serial/SerialCapabilities.h"
#include "core/device/DeviceTypes.h"
#include "utils/logs/logging.h"
using softbus::hardware::drivers::serial::SerialQtDriver;
namespace serial_cap = softbus::hardware::drivers::serial::capabilities;
bool DeviceBusManager::initialize(const QJsonObject& rootConfig)
{
// 加载设备树
QString treeError;
if (!m_treeModel.loadFromDaemonConfig(rootConfig, &treeError)) {
LOG_ERROR() << "DeviceBusManager: failed to load device_tree:" << treeError;
return false;
}
const auto nodes = m_treeModel.nodes();
for (const auto& n : nodes) {
if (!n.enabled) continue;
auto kind = softbus::core::device::kindFromType(n.type);
if (kind == softbus::core::device::DeviceKind::Unknown) {
kind = softbus::core::device::inferDeviceKindFromEndpoint(n.endpoint);
}
if (kind == softbus::core::device::DeviceKind::Serial) {
initializeSerialDriver(n.endpoint, n.params);
m_deviceEndpointsMap.insert(n.endpoint, QStringLiteral("serial"));
} else {
LOG_WARNING() << "DeviceBusManager: skip unsupported kind for endpoint=" << n.endpoint
<< "type=" << n.type;
}
}
return true;
}
void DeviceBusManager::shutdown()
{
// 关闭并销毁所有串口驱动
const auto keys = m_serialDriversMap.keys();
for (const auto& endpoint : keys) {
shutdownSerialDriver(endpoint);
}
}
void DeviceBusManager::initializeSerialDriver(const QString& endpoint,const QJsonObject& params)
{
if (m_serialDriversMap.contains(endpoint)) {
LOG_WARNING() << "DeviceBusManager: serial driver 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 = new SerialQtDriver(nullptr);
driver->SetBaudRate(static_cast<QSerialPort::BaudRate>(baud));
driver->SetDataBits(static_cast<QSerialPort::DataBits>(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);
// 按你当前策略:初始化时就打开串口
driver->Open(endpoint.toStdString());
m_serialDriversMap.insert(endpoint, driver);
m_serialDriversList.push_back(driver);
}
void DeviceBusManager::shutdownSerialDriver(const QString& endpoint)
{
auto driver = m_serialDriversMap.take(endpoint);
if (driver) {
driver->Close();
delete driver;
m_serialDriversList.removeAll(driver);
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <QByteArray>
#include <QJsonObject>
#include <QMap>
#include <QList>
#include <functional>
#include "device_bus/tree/DeviceTreeModel.h"
#include "hardware/drivers/serial/SerialQtDriver.h"
class DeviceBusManager
{
public:
bool initialize(const QJsonObject& rootConfig);
void shutdown();
private:
void initializeSerialDriver(const QString& endpoint, const QJsonObject& params);
void shutdownSerialDriver(const QString& endpoint);
// void initializeCanDriver();
// void shutdownCanDriver();
// void initializeTcpDriver();
// void shutdownTcpDriver();
// void initializeUdpDriver();
// void shutdownUdpDriver();
private:
DeviceTreeModel m_treeModel;
// 添加map来记住所有设备的endpoint和type的映射
QMap<QString, QString> m_deviceEndpointsMap;
QMap<QString, softbus::hardware::drivers::serial::SerialQtDriver*> m_serialDriversMap;
QList<softbus::hardware::drivers::serial::SerialQtDriver*> m_serialDriversList;
// std::vector<softbus::hardware::drivers::can::CanQtDriver*> m_canDrivers;
// std::vector<softbus::hardware::drivers::tcp::TcpQtDriver*> m_tcpDrivers;
// std::vector<softbus::hardware::drivers::udp::UdpQtDriver*> m_udpDrivers;
};

View File

@@ -0,0 +1,24 @@
#pragma once
#include <optional>
#include <vector>
#include "core/device/DeviceTypes.h"
namespace softbus::device_bus::registry
{
class IDeviceRegistry
{
public:
virtual ~IDeviceRegistry() = default;
virtual void registerDevice(const softbus::core::device::DeviceInfo& info) = 0;
virtual void unregisterDevice(int id) = 0;
virtual std::optional<softbus::core::device::DeviceInfo> findById(int id) const = 0;
virtual std::vector<softbus::core::device::DeviceInfo> listDevices() const = 0;
};
} // namespace softbus::device_bus::registry

View File

@@ -0,0 +1,84 @@
#include "device_bus/tree/DeviceTreeModel.h"
#include <QJsonArray>
#include "utils/logs/logging.h"
bool DeviceTreeModel::loadFromDaemonConfig(const QJsonObject& root, QString* errorMessage)
{
m_nodes.clear();
m_indexById.clear();
if (!root.contains(QStringLiteral("device_tree"))) {
if (errorMessage) {
*errorMessage = QStringLiteral("daemon_config.json missing 'device_tree' field");
}
return false;
}
const QJsonValue treeVal = root.value(QStringLiteral("device_tree"));
if (!treeVal.isArray()) {
if (errorMessage) {
*errorMessage = QStringLiteral("'device_tree' must be an array");
}
return false;
}
const QJsonArray arr = treeVal.toArray();
m_nodes.reserve(arr.size());
for (const QJsonValue& v : arr) {
if (!v.isObject()) {
LOG_WARNING() << "DeviceTreeModel: skip non-object node in device_tree";
continue;
}
const QJsonObject obj = v.toObject();
DeviceTreeNode node;
node.id = obj.value(QStringLiteral("id")).toString();
node.name = obj.value(QStringLiteral("name")).toString();
node.type = obj.value(QStringLiteral("type")).toString();
node.endpoint = obj.value(QStringLiteral("endpoint")).toString();
node.driver = obj.value(QStringLiteral("driver")).toString();
node.capabilitiesRef = obj.value(QStringLiteral("capabilitiesRef")).toString();
node.params = obj.value(QStringLiteral("params")).toObject();
node.enabled = obj.value(QStringLiteral("enabled")).toBool(true);
// children: array of ids
const QJsonValue childrenVal = obj.value(QStringLiteral("children"));
if (childrenVal.isArray()) {
const QJsonArray childrenArr = childrenVal.toArray();
for (const QJsonValue& c : childrenArr) {
if (c.isString()) {
node.childrenIds.push_back(c.toString());
}
}
}
if (node.id.isEmpty()) {
LOG_WARNING() << "DeviceTreeModel: node without id, skipping";
continue;
}
const int index = m_nodes.size();
m_nodes.push_back(node);
m_indexById.insert(node.id, index);
}
LOG_INFO() << "DeviceTreeModel loaded" << m_nodes.size() << "nodes from daemon_config";
return true;
}
const DeviceTreeNode* DeviceTreeModel::findById(const QString& id) const
{
const auto it = m_indexById.constFind(id);
if (it == m_indexById.constEnd()) {
return nullptr;
}
const int index = it.value();
if (index < 0 || index >= m_nodes.size()) {
return nullptr;
}
return &m_nodes.at(index);
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <QJsonObject>
#include <QVector>
#include <QString>
#include <QHash>
// 轻量级设备树模型:从 daemon_config.json 的 device_tree 字段加载
struct DeviceTreeNode
{
QString id;
QString name;
QString type;
QString endpoint;
QString driver;
QString capabilitiesRef;
QJsonObject params;
QVector<QString> childrenIds;
bool enabled{true};
};
class DeviceTreeModel
{
public:
// 从给定的 JSON 根对象(包含 device_tree 字段)加载
bool loadFromDaemonConfig(const QJsonObject& root, QString* errorMessage = nullptr);
const QVector<DeviceTreeNode>& nodes() const { return m_nodes; }
const DeviceTreeNode* findById(const QString& id) const;
private:
QVector<DeviceTreeNode> m_nodes;
QHash<QString, int> m_indexById;
};

View File

@@ -0,0 +1,17 @@
#pragma once
#include "core/device/DeviceTypes.h"
namespace softbus::devices
{
class IDevice
{
public:
virtual ~IDevice() = default;
virtual softbus::core::device::DeviceInfo deviceInfo() const = 0;
};
} // namespace softbus::devices

14
src/devices/devicesType.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <QString>
namespace softbus::devices::physical
{
enum class Type
{
Serial,
Can,
Tcp,
Udp,
};
}

View File

@@ -0,0 +1,67 @@
#pragma once
#include <array>
#include <QString>
namespace softbus::hardware::drivers::serial::capabilities
{
struct SerialDefaults
{
int baudRate = 115200;
int dataBits = 8;
const char* parity = "none";
int stopBits = 1;
const char* flowControl = "none";
};
inline constexpr SerialDefaults kDefaults{};
inline constexpr std::array<int, 5> kBaudRates{9600, 19200, 38400, 57600, 115200};
inline constexpr std::array<int, 4> kDataBits{5, 6, 7, 8};
inline constexpr std::array<const char*, 3> kParity{"none", "even", "odd"};
inline constexpr std::array<int, 2> kStopBits{1, 2};
inline constexpr std::array<const char*, 3> kFlowControl{"none", "hardware", "software"};
inline bool isValidBaud(int v)
{
for (int b : kBaudRates) {
if (b == v) return true;
}
return false;
}
inline bool isValidDataBits(int v)
{
for (int b : kDataBits) {
if (b == v) return true;
}
return false;
}
inline bool isValidParity(const QString& s)
{
for (const char* p : kParity) {
if (s == QLatin1String(p)) return true;
}
return false;
}
inline bool isValidStopBits(int v)
{
for (int b : kStopBits) {
if (b == v) return true;
}
return false;
}
inline bool isValidFlowControl(const QString& s)
{
for (const char* f : kFlowControl) {
if (s == QLatin1String(f)) return true;
}
return false;
}
} // namespace softbus::hardware::drivers::serial::capabilities

View File

@@ -0,0 +1,138 @@
#include "hardware/drivers/serial/SerialQtDriver.h"
#include <QByteArray>
#include "utils/logs/logging.h"
namespace softbus::hardware::drivers::serial
{
SerialQtDriver::SerialQtDriver(QObject* parent)
: QObject(parent),
m_port(this)
{
connect(&m_port, &QSerialPort::readyRead, this, &SerialQtDriver::handleReadyRead);
connect(&m_port, &QSerialPort::errorOccurred, this, &SerialQtDriver::handleError);
}
SerialQtDriver::~SerialQtDriver()
{
Close();
}
bool SerialQtDriver::Open(const std::string& endpoint)
{
if (m_port.isOpen()) {
return true;
}
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;
}
void SerialQtDriver::Close()
{
if (m_port.isOpen()) {
const QString name = m_port.portName();
m_port.close();
LOG_DEBUG() << "SerialQtDriver: closed port" << name;
}
}
bool SerialQtDriver::Write(const std::vector<std::uint8_t>& data)
{
if (!m_port.isOpen()) {
return false;
}
const QByteArray bytes(reinterpret_cast<const char*>(data.data()), static_cast<int>(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;
}
return true;
}
void SerialQtDriver::SetReadCallback(ReadCallback cb)
{
m_readCallback = std::move(cb);
}
void SerialQtDriver::SetErrorCallback(ErrorCallback cb)
{
m_errorCallback = std::move(cb);
}
void SerialQtDriver::SetBaudRate(QSerialPort::BaudRate baud)
{
m_port.setBaudRate(baud);
}
void SerialQtDriver::SetDataBits(QSerialPort::DataBits bits)
{
m_port.setDataBits(bits);
}
void SerialQtDriver::SetParity(QSerialPort::Parity parity)
{
m_port.setParity(parity);
}
void SerialQtDriver::SetStopBits(QSerialPort::StopBits stopBits)
{
m_port.setStopBits(stopBits);
}
void SerialQtDriver::SetFlowControl(QSerialPort::FlowControl flow)
{
m_port.setFlowControl(flow);
}
void SerialQtDriver::handleReadyRead()
{
if (!m_readCallback) {
const QByteArray data = m_port.readAll();
LOG_DEBUG() << "SerialQtDriver: dropped" << data.size() << "bytes on" << m_port.portName()
<< "because no read callback is set";
return;
}
const QByteArray data = m_port.readAll();
if (data.isEmpty()) {
return;
}
std::vector<std::uint8_t> buffer(reinterpret_cast<const std::uint8_t*>(data.constData()),
reinterpret_cast<const std::uint8_t*>(data.constData()) + data.size());
m_readCallback(buffer);
}
void SerialQtDriver::handleError(QSerialPort::SerialPortError error)
{
if (error == QSerialPort::NoError) {
return;
}
const QString msg =
QStringLiteral("SerialQtDriver error on %1: %2").arg(m_port.portName(), m_port.errorString());
LOG_WARNING() << msg;
if (m_errorCallback) {
m_errorCallback(msg.toStdString());
}
}
} // namespace softbus::hardware::drivers::serial

View File

@@ -0,0 +1,85 @@
#pragma once
#include <QObject>
#include <QSerialPort>
#include <QString>
#include "hardware/interfaces/IStreamDriver.h"
// 这里的串口的唯一标识是串口的端口名,如 /dev/ttyUSB0, can0, tcp://...
// 串口的endpoint是串口的端口名如 /dev/ttyUSB0, can0, tcp://...
// 使用说明:
// 1. 创建一个SerialQtDriver对象
// 2. 调用Open方法打开串口
// 3. 调用Write方法写数据
// 4. 调用SetReadCallback方法设置读回调
// 5. 调用SetErrorCallback方法设置错误回调
// 6. 调用Close方法关闭串口
// 7. 调用SetBaudRate方法设置波特率
// 8. 调用SetDataBits方法设置数据位
// 9. 调用SetParity方法设置校验位
// 10. 调用SetStopBits方法设置停止位
// 11. 调用SetFlowControl方法设置流控制
// eg:
// SerialQtDriver driver;
// driver.Open("/dev/ttyUSB0");
// driver.Write({0x01, 0x02, 0x03});
// driver.SetReadCallback([](const std::vector<std::uint8_t>& data) {
// std::cout << "read data: " << data << std::endl;
// });
// driver.SetErrorCallback([](const std::string& error) {
// std::cout << "error: " << error << std::endl;
// });
// driver.Close();
// 12. 调用SetBaudRate方法设置波特率
// 13. 调用SetDataBits方法设置数据位
// 14. 调用SetParity方法设置校验位
// 15. 调用SetStopBits方法设置停止位
// 16. 调用SetFlowControl方法设置流控制
// eg:
// driver.SetBaudRate(QSerialPort::Baud115200);
// driver.SetDataBits(QSerialPort::Data8);
// driver.SetParity(QSerialPort::NoParity);
// driver.SetStopBits(QSerialPort::OneStop);
// driver.SetFlowControl(QSerialPort::NoFlowControl);
// driver.Close();
namespace softbus::hardware::drivers::serial
{
// 基于 Qt 的串口驱动实现:只负责串口 open/read/write不包含设备注册、数据库或协议逻辑
class SerialQtDriver : public QObject, public softbus::hardware::interfaces::IStreamDriver
{
Q_OBJECT
public:
explicit SerialQtDriver(QObject* parent = nullptr);
~SerialQtDriver() override;
bool Open(const std::string& endpoint) override;
void Close() override;
bool Write(const std::vector<std::uint8_t>& data) override;
void SetReadCallback(ReadCallback cb) override;
void SetErrorCallback(ErrorCallback cb) override;
// 允许上层配置串口参数(最小集合)
void SetBaudRate(QSerialPort::BaudRate baud);
void SetDataBits(QSerialPort::DataBits bits);
void SetParity(QSerialPort::Parity parity);
void SetStopBits(QSerialPort::StopBits stopBits);
void SetFlowControl(QSerialPort::FlowControl flow);
private slots:
void handleReadyRead();
void handleError(QSerialPort::SerialPortError error);
private:
QSerialPort m_port;
ReadCallback m_readCallback;
ErrorCallback m_errorCallback;
};
} // namespace softbus::hardware::drivers::serial

View File

@@ -0,0 +1,37 @@
#pragma once
#ifdef __cplusplus
#include <functional>
#include <string>
namespace softbus::hardware::interfaces
{
struct DiscoveredDevice
{
std::string id; // 稳定 ID如序列号、路径
std::string endpoint; // 打开所需的 endpoint如 /dev/ttyUSB0, can0, tcp://...
std::string type; // 设备类型serial / can / ethernet / usb 等
};
// 设备发现 / 监控接口:负责发现插拔事件,不负责创建设备或驱动实例
class IDeviceWatcher
{
public:
using DeviceAttachedCallback = std::function<void(const DiscoveredDevice&)>;
using DeviceDetachedCallback = std::function<void(const DiscoveredDevice&)>;
virtual ~IDeviceWatcher() = default;
virtual bool Start() = 0;
virtual void Stop() = 0;
virtual void SetDeviceAttachedCallback(DeviceAttachedCallback cb) = 0;
virtual void SetDeviceDetachedCallback(DeviceDetachedCallback cb) = 0;
};
} // namespace softbus::hardware::interfaces
#endif // __cplusplus

View File

@@ -0,0 +1,41 @@
#pragma once
#ifdef __cplusplus
#include <cstdint>
#include <functional>
#include <string>
#include <vector>
namespace softbus::hardware::interfaces
{
struct Frame
{
std::vector<std::uint8_t> payload;
std::uint32_t id{0}; // 如 CAN ID
std::uint64_t timestamp{0};
};
// 面向帧设备(如 CAN 总线)的统一驱动接口
class IFrameDriver
{
public:
using FrameCallback = std::function<void(const Frame&)>;
using ErrorCallback = std::function<void(const std::string& message)>;
virtual ~IFrameDriver() = default;
virtual bool Open(const std::string& endpoint) = 0;
virtual void Close() = 0;
virtual bool WriteFrame(const Frame& frame) = 0;
virtual void SetFrameCallback(FrameCallback cb) = 0;
virtual void SetErrorCallback(ErrorCallback cb) = 0;
};
} // namespace softbus::hardware::interfaces
#endif // __cplusplus

View File

@@ -0,0 +1,34 @@
#pragma once
#ifdef __cplusplus
#include <cstdint>
#include <functional>
#include <string>
#include <vector>
namespace softbus::hardware::interfaces
{
// 面向字节流设备的统一驱动接口:串口 / TCP / UDP 等
class IStreamDriver
{
public:
using ReadCallback = std::function<void(const std::vector<std::uint8_t>&)>;
using ErrorCallback = std::function<void(const std::string& message)>;
virtual ~IStreamDriver() = default;
virtual bool Open(const std::string& endpoint) = 0;
virtual void Close() = 0;
virtual bool Write(const std::vector<std::uint8_t>& data) = 0;
virtual void SetReadCallback(ReadCallback cb) = 0;
virtual void SetErrorCallback(ErrorCallback cb) = 0;
};
} // namespace softbus::hardware::interfaces
#endif // __cplusplus

View File

@@ -4,4 +4,4 @@
class PipelineContext {
public:
PipelineContext() = default;
};
};

View File

@@ -4,4 +4,4 @@
class PipelineEngine {
public:
PipelineEngine() = default;
};
};

View File

@@ -4,4 +4,4 @@
class LogStream {
public:
LogStream() = default;
};
};

View File

@@ -1,36 +1,36 @@
#ifndef LOGGING_H
#define LOGGING_H
#include <QDebug>
#include <QLoggingCategory>
#include <QString>
#include <cstring>
/**
* @file logging.h
* @brief 日志宏定义,提供带文件名和函数名的日志输出,并异步存储到数据库
*/
// 获取文件名(不含路径)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
// 构建来源字符串的辅助宏
// #define __LOG_SOURCE__ (QString(__FILENAME__) + "." + QString(__FUNCTION__))
// 日志宏,格式:[文件名.函数名] 消息
#define LOG_DEBUG() \
qDebug() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_ERROR() \
qCritical() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_INFO() \
qInfo() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_WARNING() \
qWarning() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#endif // LOGGING_H
#ifndef LOGGING_H
#define LOGGING_H
#include <QDebug>
#include <QLoggingCategory>
#include <QString>
#include <cstring>
/**
* @file logging.h
* @brief 日志宏定义,提供带文件名和函数名的日志输出,并异步存储到数据库
*/
// 获取文件名(不含路径)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
// 构建来源字符串的辅助宏
// #define __LOG_SOURCE__ (QString(__FILENAME__) + "." + QString(__FUNCTION__))
// 日志宏,格式:[文件名.函数名] 消息
#define LOG_DEBUG() \
qDebug() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_ERROR() \
qCritical() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_INFO() \
qInfo() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#define LOG_WARNING() \
qWarning() << "[" << __FILENAME__ << "/" << __FUNCTION__ << "]"
#endif // LOGGING_H