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.

View File

@@ -51,18 +51,49 @@ qt_add_library(softbus_template
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
)

Binary file not shown.

View File

@@ -1,5 +1,23 @@
{
"plugin_dir": "bin/plugins",
"device_tree": [],
"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

@@ -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

@@ -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