当前架构中,soft_bus(主应用)和 soft_bus_daemon(守护进程)是两个独立的进程,各自有独立的 SerialManager 实例。
问题:
┌──────────────────────┐ ┌──────────────────────┐
│ soft_bus │ │ soft_bus_daemon │
│ (主应用) │ │ (守护进程) │
│ │ │ │
│ ┌────────────────┐ │ │ ┌────────────────┐ │
│ │ SoftBusAPI │ │ │ │ SoftBusAPI │ │
│ │ (不创建串口) │ │ │ │ (管理串口) │ │
│ └────────────────┘ │ │ └────────────────┘ │
│ │ │ │ │ │
│ │ │ │ ▼ │
│ │ │ │ ┌────────────────┐ │
│ │ │ │ │ SerialManager │ │
│ │ │ │ │ (打开串口) │ │
│ │ │ │ └────────────────┘ │
│ │ │ │ │ │
│ │ │ │ ▼ │
│ │ │ │ ┌────────────────┐ │
│ │ │ │ │ /dev/ttyUSB0 │ │
│ │ │ │ │ (串口设备) │ │
│ │ │ │ └────────────────┘ │
│ │ │ │ │
└─────────┼────────────┘ └─────────┼────────────┘
│ │
│ D-Bus 通信 │
│ ┌─────────────────────────────┐ │
└─►│ DaemonService │◄─────────┘
│ (串口操作接口) │
└─────────────────────────────┘
数据流向:
1. 主应用通过 D-Bus 请求打开/关闭串口
2. 守护进程管理串口,接收数据
3. 数据通过 D-Bus 信号或数据库传递给主应用
在 daemon_service.h 中添加串口管理接口:
// daemon_service.h
public slots:
// ... 现有接口 ...
/**
* @brief 打开串口
* @param portName 串口名称(如 "ttyUSB0")
* @param baudRate 波特率
* @return 成功返回 true
*/
bool openSerialPort(const QString& portName, int baudRate);
/**
* @brief 关闭串口
* @param portName 串口名称
*/
void closeSerialPort(const QString& portName);
/**
* @brief 获取已打开的串口列表
* @return 串口名称列表(JSON 格式)
*/
QString getOpenedSerialPorts() const;
/**
* @brief 发送数据到串口
* @param portName 串口名称
* @param data 数据(Base64 编码)
* @return 成功返回 true
*/
bool writeSerialData(const QString& portName, const QString& data);
signals:
// ... 现有信号 ...
/**
* @brief 串口数据接收时发出
* @param portName 串口名称
* @param data 数据(Base64 编码)
*/
void serialDataReceived(const QString& portName, const QString& data);
/**
* @brief 串口状态变化时发出
* @param portName 串口名称
* @param isOpen 是否打开
*/
void serialPortStatusChanged(const QString& portName, bool isOpen);
在 daemon_service.cpp 中实现:
// daemon_service.cpp
#include "api/SoftBusAPI.h"
bool DaemonService::openSerialPort(const QString& portName, int baudRate)
{
if (!m_coreService || !m_coreService->isInitialized()) {
return false;
}
SoftBusAPI* api = SoftBusAPI::instance();
if (!api) {
return false;
}
// 查找串口信息
QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo& info : ports) {
if (info.portName() == portName) {
// 设置串口配置
SerialManager::SerialConfig config;
config.baudRate = static_cast<QSerialPort::BaudRate>(baudRate);
api->setSerialConfig(config);
// 打开串口
return api->openSerialPort(info);
}
}
return false;
}
void DaemonService::closeSerialPort(const QString& portName)
{
SoftBusAPI* api = SoftBusAPI::instance();
if (api) {
api->closeSerialPort(portName);
}
}
QString DaemonService::getOpenedSerialPorts() const
{
QJsonArray ports;
SoftBusAPI* api = SoftBusAPI::instance();
if (api) {
QStringList portList = api->getOpenedSerialPorts();
for (const QString& port : portList) {
ports.append(port);
}
}
QJsonObject result;
result["ports"] = ports;
return QJsonDocument(result).toJson(QJsonDocument::Compact);
}
bool DaemonService::writeSerialData(const QString& portName, const QString& data)
{
SoftBusAPI* api = SoftBusAPI::instance();
if (!api) {
return false;
}
// Base64 解码
QByteArray byteData = QByteArray::fromBase64(data.toUtf8());
return api->writeSerialData(portName, byteData);
}
在 daemon_service.cpp 构造函数中连接信号:
DaemonService::DaemonService(CoreService* coreService, QObject* parent)
: QObject(parent)
, m_coreService(coreService)
// ... 其他初始化 ...
{
// ... 现有代码 ...
// 连接串口数据信号
SoftBusAPI* api = SoftBusAPI::instance();
if (api) {
connect(api, &SoftBusAPI::serialDataReceived,
this, [this](const QString& portName, const QByteArray& data) {
// Base64 编码后通过 D-Bus 发送
QString base64Data = QString::fromUtf8(data.toBase64());
emit serialDataReceived(portName, base64Data);
});
}
}
在 daemon_client.h 中添加串口操作接口:
// daemon_client.h
public:
// ... 现有接口 ...
/**
* @brief 打开串口(通过守护进程)
* @param portName 串口名称
* @param baudRate 波特率
* @return 成功返回 true
*/
bool openSerialPort(const QString& portName, int baudRate);
/**
* @brief 关闭串口(通过守护进程)
* @param portName 串口名称
*/
void closeSerialPort(const QString& portName);
/**
* @brief 获取已打开的串口列表
* @return 串口名称列表
*/
QStringList getOpenedSerialPorts() const;
/**
* @brief 发送数据到串口(通过守护进程)
* @param portName 串口名称
* @param data 数据
* @return 成功返回 true
*/
bool writeSerialData(const QString& portName, const QByteArray& data);
signals:
// ... 现有信号 ...
/**
* @brief 串口数据接收时发出
* @param portName 串口名称
* @param data 数据
*/
void serialDataReceived(const QString& portName, const QByteArray& data);
/**
* @brief 串口状态变化时发出
* @param portName 串口名称
* @param isOpen 是否打开
*/
void serialPortStatusChanged(const QString& portName, bool isOpen);
在 daemon_client.cpp 中实现:
// daemon_client.cpp
bool DaemonClient::openSerialPort(const QString& portName, int baudRate)
{
if (!m_interface || !m_interface->isValid()) {
return false;
}
QDBusReply<bool> reply = m_interface->call("openSerialPort", portName, baudRate);
return reply.isValid() && reply.value();
}
void DaemonClient::closeSerialPort(const QString& portName)
{
if (m_interface && m_interface->isValid()) {
m_interface->call("closeSerialPort", portName);
}
}
QStringList DaemonClient::getOpenedSerialPorts() const
{
if (!m_interface || !m_interface->isValid()) {
return QStringList();
}
QDBusReply<QString> reply = m_interface->call("getOpenedSerialPorts");
if (reply.isValid()) {
QJsonDocument doc = QJsonDocument::fromJson(reply.value().toUtf8());
QJsonObject obj = doc.object();
QJsonArray ports = obj["ports"].toArray();
QStringList result;
for (const QJsonValue& value : ports) {
result.append(value.toString());
}
return result;
}
return QStringList();
}
bool DaemonClient::writeSerialData(const QString& portName, const QByteArray& data)
{
if (!m_interface || !m_interface->isValid()) {
return false;
}
// Base64 编码
QString base64Data = QString::fromUtf8(data.toBase64());
QDBusReply<bool> reply = m_interface->call("writeSerialData", portName, base64Data);
return reply.isValid() && reply.value();
}
在 daemon_client.cpp 的 connectToDaemon() 中连接信号:
bool DaemonClient::connectToDaemon()
{
// ... 现有代码 ...
// 连接串口信号
connection.connect(
"com.softbus.Daemon",
"/com/softbus/Daemon",
"com.softbus.Daemon",
"serialDataReceived",
this,
SLOT(onSerialDataReceived(QString, QString))
);
connection.connect(
"com.softbus.Daemon",
"/com/softbus/Daemon",
"com.softbus.Daemon",
"serialPortStatusChanged",
this,
SLOT(onSerialPortStatusChanged(QString, bool))
);
// ... 其他代码 ...
}
void DaemonClient::onSerialDataReceived(const QString& portName, const QString& base64Data)
{
QByteArray data = QByteArray::fromBase64(base64Data.toUtf8());
emit serialDataReceived(portName, data);
}
void DaemonClient::onSerialPortStatusChanged(const QString& portName, bool isOpen)
{
emit serialPortStatusChanged(portName, isOpen);
}
在主应用中,不再直接使用 SoftBusAPI 的串口接口,而是通过 DaemonClient:
// 原来的方式(不再使用)
// SoftBusAPI* api = SoftBusAPI::instance();
// api->openSerialPort(portInfo);
// 新的方式(通过守护进程)
DaemonClient* client = DaemonClient::instance();
if (client->connectToDaemon()) {
client->openSerialPort("ttyUSB0", 9600);
// 连接数据接收信号
connect(client, &DaemonClient::serialDataReceived,
this, [this](const QString& portName, const QByteArray& data) {
// 处理接收到的数据
qDebug() << "Received data from" << portName << ":" << data.toHex();
});
}
在守护进程启动时,自动开始串口发现:
// daemon_main.cpp
int main(int argc, char *argv[])
{
// ... 现有代码 ...
// 初始化核心服务
CoreService* coreService = CoreService::instance();
if (!coreService->initialize()) {
qCritical() << "Failed to initialize CoreService";
return 1;
}
// 启动设备发现(包括串口)
SoftBusAPI* api = SoftBusAPI::instance();
if (api) {
api->startDeviceDiscovery(5000); // 每5秒扫描一次
}
// ... 其他代码 ...
}
DaemonService 添加串口接口DaemonClient 添加串口接口通过让守护进程统一管理串口资源,主应用通过 D-Bus 操作串口,可以: