-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSerialPortManager.cpp
More file actions
210 lines (172 loc) · 6.03 KB
/
Copy pathSerialPortManager.cpp
File metadata and controls
210 lines (172 loc) · 6.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "SerialPortManager.hpp"
#include <QMetaObject>
#include <QSerialPort>
#include <QThread>
class SerialPortWorker : public QObject {
Q_OBJECT
public:
explicit SerialPortWorker(QObject *parent = nullptr)
: QObject(parent), portPtr(nullptr) {}
public slots:
void init() {
if (portPtr) {
return;
}
portPtr = new QSerialPort(this);
connect(portPtr, &QSerialPort::readyRead, this, [this]() {
if (!portPtr || !portPtr->isOpen()) {
return;
}
QByteArray data = portPtr->readAll();
while (portPtr->waitForReadyRead(10)) {
data += portPtr->readAll();
}
if (!data.isEmpty()) {
emit dataReceived(data);
}
});
connect(portPtr, &QSerialPort::errorOccurred, this,
[this](QSerialPort::SerialPortError error) {
if (error == QSerialPort::NoError ||
error == QSerialPort::TimeoutError) {
return;
}
emit errorOccurred(portPtr ? portPtr->errorString()
: QString("Unknown serial error"));
});
}
void openPort(const QString &portName, qint32 baudRate,
const QString &dataBits, const QString &parity,
const QString &stopBits, const QString &flowControl) {
if (!portPtr) {
emit errorOccurred("SerialPortWorker is not initialized");
return;
}
if (portPtr->isOpen()) {
portPtr->close();
}
portPtr->setPortName(portName);
portPtr->setBaudRate(baudRate);
if (dataBits == "5") {
portPtr->setDataBits(QSerialPort::Data5);
} else if (dataBits == "6") {
portPtr->setDataBits(QSerialPort::Data6);
} else if (dataBits == "7") {
portPtr->setDataBits(QSerialPort::Data7);
} else {
portPtr->setDataBits(QSerialPort::Data8);
}
if (parity == "Even") {
portPtr->setParity(QSerialPort::EvenParity);
} else if (parity == "Odd") {
portPtr->setParity(QSerialPort::OddParity);
} else {
portPtr->setParity(QSerialPort::NoParity);
}
if (stopBits == "2") {
portPtr->setStopBits(QSerialPort::TwoStop);
} else {
portPtr->setStopBits(QSerialPort::OneStop);
}
if (flowControl == "Hardware") {
portPtr->setFlowControl(QSerialPort::HardwareControl);
} else if (flowControl == "Software") {
portPtr->setFlowControl(QSerialPort::SoftwareControl);
} else {
portPtr->setFlowControl(QSerialPort::NoFlowControl);
}
emit stateChanged(portPtr->open(QIODevice::ReadWrite));
}
void writeData(const QByteArray &data) {
if (!portPtr || !portPtr->isOpen()) {
emit errorOccurred("Serial port is not open");
return;
}
if (data.isEmpty()) {
return;
}
const qint64 written = portPtr->write(data);
if (written < 0) {
emit errorOccurred(portPtr->errorString());
return;
}
if (!portPtr->waitForBytesWritten(300)) {
emit errorOccurred(portPtr->errorString());
}
}
void closePort() {
if (portPtr && portPtr->isOpen()) {
portPtr->close();
}
emit stateChanged(false);
}
bool isPortOpen() const { return portPtr && portPtr->isOpen(); }
signals:
void dataReceived(const QByteArray &data);
void stateChanged(bool opened);
void errorOccurred(const QString &message);
private:
QSerialPort *portPtr;
};
SerialPortManager::SerialPortManager(QObject *parent)
: QObject(parent), ioThreadPtr(new QThread(this)),
workerPtr(new SerialPortWorker) {
workerPtr->moveToThread(ioThreadPtr);
connect(ioThreadPtr, &QThread::finished, workerPtr, &QObject::deleteLater);
connect(workerPtr, &SerialPortWorker::dataReceived, this,
&SerialPortManager::dataReceivedSlot);
connect(workerPtr, &SerialPortWorker::stateChanged, this,
&SerialPortManager::stateChangedSlot);
connect(workerPtr, &SerialPortWorker::errorOccurred, this,
&SerialPortManager::errorOccurredSlot);
ioThreadPtr->start();
// 确保在工作线程中初始化串口对象,避免主线程访问未初始化的对象
QMetaObject::invokeMethod(workerPtr, "init", Qt::BlockingQueuedConnection);
}
void SerialPortManager::open(const QString &portName, qint32 baudRate,
const QString &dataBits, const QString &parity,
const QString &stopBits,
const QString &flowControl) {
// [=]等效[this, portName, baudRate, dataBits, parity, stopBits, flowControl]
// 参数少用后者的写法更推荐,参数多用前者
// 现代 C++ 更推荐后者
auto function = [=]() {
workerPtr->openPort(portName, baudRate, dataBits, parity, stopBits,
flowControl);
};
QMetaObject::invokeMethod(workerPtr, function, Qt::BlockingQueuedConnection);
}
void SerialPortManager::write(const QByteArray &data) {
auto function = [=]() { workerPtr->writeData(data); };
QMetaObject::invokeMethod(workerPtr, function, Qt::QueuedConnection);
}
void SerialPortManager::close() {
QMetaObject::invokeMethod(workerPtr, "closePort",
Qt::BlockingQueuedConnection);
}
bool SerialPortManager::isOpen() const {
bool opened = false;
// [&]等效[this, &opened],适合修改外部变量场景
auto function = [&]() { opened = workerPtr->isPortOpen(); };
QMetaObject::invokeMethod(workerPtr, function, Qt::BlockingQueuedConnection);
return opened;
}
SerialPortManager::~SerialPortManager() {
close();
if (ioThreadPtr->isRunning()) {
ioThreadPtr->quit();
ioThreadPtr->wait();
}
}
void SerialPortManager::dataReceivedSlot(const QByteArray &data) {
emit dataReceivedSignal(data);
}
void SerialPortManager::stateChangedSlot(bool opened) {
emit stateChangedSignal(opened);
}
void SerialPortManager::errorOccurredSlot(const QString &message) {
emit errorOccurredSignal(message);
}
// 内部 Worker 类写在 .cpp,就需要这一行代码。
// 如果把内部 Worker 类挪到独立头文件并加入工程头文件列表,通常就不需要这行了。
#include "SerialPortManager.moc"