Skip to content

Commit fffa209

Browse files
committed
Async serial port reader
1 parent ca21e20 commit fffa209

File tree

6 files changed

+140
-67
lines changed

6 files changed

+140
-67
lines changed

qt/programmer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ int Programmer::serialPortConnect()
4141
{
4242
if (!serialPort.start(usbDevName.toLatin1(), SERIAL_PORT_SPEED))
4343
{
44+
std::string err = serialPort.errorString();
45+
QString errStr = QString(err.c_str());
4446
qCritical() << "Failed to open serial port " << usbDevName << ": " <<
45-
serialPort.errorString().c_str();
47+
errStr;
4648
return -1;
4749
}
4850

qt/qt.pro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ QMAKE_CXXFLAGS += -std=c++11 -Wextra -Werror
8282
mingw:QMAKE_CXXFLAGS += -mno-ms-bitfields
8383

8484
unix: {
85-
LIBS += -lboost_system
85+
LIBS += -lboost_system -lboost_thread
8686
}
8787

8888
win32: {
8989
INCLUDEPATH += C:/boost/include/boost-1_75
90-
LIBS += -LC:/boost/lib -lws2_32 -lboost_system-mgw8-mt-x64-1_75
90+
LIBS += -LC:/boost/lib -lws2_32 -lboost_system-mgw8-mt-x64-1_75 \
91+
-lboost_thread-mgw8-mt-x64-1_75
9192
}
9293

9394
DISTFILES += \

qt/reader.cpp

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <QTextCursor>
1212

1313
#define READ_TIMEOUT 10000
14-
#define BUF_SIZE 4096
1514
#define NOTIFY_LIMIT 131072 // 128KB
1615

1716
Q_DECLARE_METATYPE(QtMsgType)
@@ -31,6 +30,7 @@ void Reader::init(const QString &portName, qint32 baudRate, uint8_t *rbuf,
3130
readOffset = 0;
3231
bytesRead = 0;
3332
bytesReadNotified = 0;
33+
offset = 0;
3434
}
3535

3636
int Reader::write(const uint8_t *data, uint32_t len)
@@ -59,27 +59,6 @@ int Reader::readStart()
5959
return write(wbuf, wlen);
6060
}
6161

62-
int Reader::read(char *pbuf, uint32_t len)
63-
{
64-
qint64 ret;
65-
66-
//TODO: handle timeout
67-
// if (!serialPort->waitForReadyRead(READ_TIMEOUT))
68-
// {
69-
// logErr("Read data timeout");
70-
// return -1;
71-
// }
72-
73-
ret = serialPort->read(pbuf, len);
74-
if (ret < 0)
75-
{
76-
logErr("Failed to read data");
77-
return -1;
78-
}
79-
80-
return static_cast<int>(ret);
81-
}
82-
8362
int Reader::handleBadBlock(char *pbuf, uint32_t len, bool isSkipped)
8463
{
8564
RespBadBlock *badBlock = reinterpret_cast<RespBadBlock *>(pbuf);
@@ -164,7 +143,7 @@ int Reader::handleData(char *pbuf, uint32_t len)
164143
uint8_t dataSize = header->info;
165144
size_t headerSize = sizeof(RespHeader), packetSize = headerSize + dataSize;
166145

167-
if (!dataSize || packetSize > BUF_SIZE)
146+
if (!dataSize || packetSize > bufSize)
168147
{
169148
logErr(QString("Wrong data length in response header: %1")
170149
.arg(dataSize));
@@ -229,47 +208,82 @@ int Reader::handlePackets(char *pbuf, uint32_t len)
229208
return static_cast<int>(len - offset);
230209
}
231210

232-
int Reader::readData()
211+
void Reader::readCb(int size)
233212
{
234-
char pbuf[BUF_SIZE];
235-
int len, offset = 0;
236213

237-
do
214+
if (size < 0)
238215
{
239-
if ((len = read(pbuf + offset,
240-
BUF_SIZE - static_cast<uint32_t>(offset))) < 0)
241-
{
242-
return -1;
243-
}
244-
len += offset;
216+
std::string err = serialPort->errorString();
217+
QString errStr = QString(err.c_str());
218+
logErr("Failed to read data: " + errStr);
219+
emit result(-1);
220+
serialPortDestroy();
221+
return;
222+
}
245223

246-
if ((offset = handlePackets(pbuf, static_cast<uint32_t>(len))) < 0)
247-
return -1;
224+
size += offset;
248225

249-
if (bytesRead >= bytesReadNotified + NOTIFY_LIMIT)
226+
if ((offset = handlePackets(pbuf, static_cast<uint32_t>(size))) < 0)
227+
{
228+
emit result(-1);
229+
serialPortDestroy();
230+
return;
231+
}
232+
233+
if (bytesRead >= bytesReadNotified + NOTIFY_LIMIT)
234+
{
235+
emit progress(bytesRead);
236+
bytesReadNotified = bytesRead;
237+
}
238+
239+
if (!bytesRead || (rlen && rlen != bytesRead))
240+
{
241+
if (read(pbuf + offset, bufSize - offset) < 0)
250242
{
251-
emit progress(bytesRead);
252-
bytesReadNotified = bytesRead;
243+
emit result(-1);
244+
serialPortDestroy();
245+
return;
253246
}
254247
}
255-
while (!bytesRead || (rlen && rlen != bytesRead));
256-
257-
return 0;
248+
else
249+
{
250+
emit result(0);
251+
serialPortDestroy();
252+
}
258253
}
259254

260-
int Reader::serialPortCreate()
255+
int Reader::read(char *pbuf, uint32_t len)
261256
{
262-
serialPort = new SerialPort();
257+
std::function<void(int)> cb = std::bind(&Reader::readCb, this,
258+
std::placeholders::_1);
259+
260+
if (serialPort->asyncRead(pbuf, len, cb) < 0)
261+
{
262+
logErr("Failed to read data");
263+
return -1;
264+
}
265+
266+
return 0;
263267

264-
//TODO: error handling
265-
// if (!serialPort->open(QIODevice::ReadWrite))
268+
//TODO: handle timeout
269+
// if (!serialPort->waitForReadyRead(READ_TIMEOUT))
266270
// {
267-
// logErr(QString("Failed to open serial port: %1")
268-
// .arg(serialPort->errorString()));
271+
// logErr("Read data timeout");
269272
// return -1;
270273
// }
274+
}
275+
276+
int Reader::serialPortCreate()
277+
{
278+
serialPort = new SerialPort();
271279

272-
serialPort->start(portName.toLatin1(), baudRate);
280+
if (!serialPort->start(portName.toLatin1(), baudRate))
281+
{
282+
std::string err = serialPort->errorString();
283+
QString errStr = QString(err.c_str());
284+
logErr(QString("Failed to open serial port: %1").arg(errStr));
285+
return -1;
286+
}
273287

274288
return 0;
275289
}
@@ -280,26 +294,33 @@ void Reader::serialPortDestroy()
280294
delete serialPort;
281295
}
282296

283-
void Reader::run()
297+
void Reader::start()
284298
{
285-
int ret = -1;
286-
287299
/* Required for logger */
288300
qRegisterMetaType<QtMsgType>();
289301

290302
if (serialPortCreate())
291-
goto Exit;
303+
{
304+
emit result(-1);
305+
goto Error;
306+
}
307+
308+
if (read(pbuf, bufSize) < 0)
309+
{
310+
emit result(-1);
311+
goto Error;
312+
}
292313

293314
if (readStart())
294-
goto Exit;
315+
{
316+
emit result(-1);
317+
goto Error;
318+
}
295319

296-
if (readData())
297-
goto Exit;
320+
return;
298321

299-
ret = 0;
300-
Exit:
322+
Error:
301323
serialPortDestroy();
302-
emit result(ret);
303324
}
304325

305326
void Reader::logErr(const QString& msg)

qt/reader.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
#ifndef READER_H
77
#define READER_H
88

9-
#include <QThread>
9+
#include <QObject>
1010
#include "serial_port.h"
1111

12-
class Reader : public QThread
12+
class Reader : public QObject
1313
{
1414
Q_OBJECT
1515

16+
static const uint32_t bufSize = 4096;
17+
1618
SerialPort *serialPort;
1719
QString portName;
1820
qint32 baudRate;
@@ -23,30 +25,31 @@ class Reader : public QThread
2325
uint32_t readOffset;
2426
uint32_t bytesRead;
2527
uint32_t bytesReadNotified;
28+
int offset;
2629
bool isSkipBB;
2730
bool isReadLess;
31+
char pbuf[bufSize];
2832

2933
int serialPortCreate();
3034
void serialPortDestroy();
3135
int write(const uint8_t *data, uint32_t len);
3236
int readStart();
3337
int read(char *pbuf, uint32_t len);
38+
void readCb(int size);
3439
int handleError(char *pbuf, uint32_t len);
3540
int handleProgress(char *pbuf, uint32_t len);
3641
int handleBadBlock(char *pbuf, uint32_t len, bool isSkipped);
3742
int handleStatus(char *pbuf, uint32_t len);
3843
int handleData(char *pbuf, uint32_t len);
3944
int handlePacket(char *pbuf, uint32_t len);
4045
int handlePackets(char *pbuf, uint32_t len);
41-
int readData();
42-
void run() override;
4346
void logErr(const QString& msg);
4447
void logInfo(const QString& msg);
45-
4648
public:
4749
void init(const QString &portName, qint32 baudRate, uint8_t *rbuf,
4850
uint32_t rlen, const uint8_t *wbuf, uint32_t wlen, bool isSkipBB,
4951
bool isReadLess);
52+
void start();
5053
signals:
5154
void result(int ret);
5255
void progress(unsigned int progress);

qt/serial_port.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include "serial_port.h"
7+
#include <boost/bind.hpp>
78

89
SerialPort::SerialPort()
910
{
@@ -43,6 +44,40 @@ int SerialPort::read(char *buf, int size)
4344
return ret;
4445
}
4546

47+
int SerialPort::asyncRead(char *buf, int size, std::function<void(int)> cb)
48+
{
49+
if (!port || !port.get() || !port->is_open())
50+
return -1;
51+
52+
readCb = cb;
53+
54+
port->async_read_some(boost::asio::buffer(buf, size),
55+
boost::bind(&SerialPort::onRead, this, boost::asio::placeholders::error,
56+
boost::asio::placeholders::bytes_transferred));
57+
58+
if (!isStarted)
59+
{
60+
boost::thread t(boost::bind(&boost::asio::io_service::run, &ioService));
61+
isStarted = true;
62+
}
63+
64+
return 0;
65+
}
66+
67+
void SerialPort::onRead(const boost::system::error_code &ec, size_t bytesRead)
68+
{
69+
boost::mutex::scoped_lock look(mutex);
70+
71+
if (ec)
72+
{
73+
readCb(-1);
74+
isStarted = false;
75+
return;
76+
}
77+
78+
readCb(bytesRead);
79+
}
80+
4681
std::string SerialPort::errorString()
4782
{
4883
return ec.message();
@@ -64,6 +99,7 @@ bool SerialPort::start(const char *portName, int baudRate)
6499
{
65100
std::cout << "error : port_->open() failed...com_port_name="
66101
<< portName << ", e=" << ec.message().c_str() << std::endl;
102+
port = nullptr;
67103
return false;
68104
}
69105

@@ -81,6 +117,8 @@ bool SerialPort::start(const char *portName, int baudRate)
81117

82118
void SerialPort::stop()
83119
{
120+
boost::mutex::scoped_lock look(mutex);
121+
84122
if (port)
85123
{
86124
port->cancel();
@@ -91,4 +129,5 @@ void SerialPort::stop()
91129

92130
ioService.stop();
93131
ioService.reset();
132+
isStarted = false;
94133
}

qt/serial_port.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,27 @@
1010
#include <boost/asio/serial_port.hpp>
1111
#include <boost/system/error_code.hpp>
1212
#include <boost/system/system_error.hpp>
13+
#include <boost/thread.hpp>
1314

1415
#include <iostream>
1516

16-
typedef boost::shared_ptr<boost::asio::serial_port> serial_port_ptr;
17+
typedef boost::shared_ptr<boost::asio::serial_port> serial_port_ptr;
1718

1819
class SerialPort
1920
{
2021
private:
2122
boost::asio::io_service ioService;
2223
serial_port_ptr port;
2324
boost::system::error_code ec;
25+
boost::mutex mutex;
26+
std::function<void(int)> readCb;
27+
bool isStarted = false;
2428

2529
SerialPort(const SerialPort &p);
2630
SerialPort &operator=(const SerialPort &p);
2731

32+
void onRead(const boost::system::error_code &ec, size_t bytesRead);
33+
2834
public:
2935
SerialPort();
3036
virtual ~SerialPort();
@@ -34,6 +40,7 @@ class SerialPort
3440

3541
int write(const char *buf, int size);
3642
int read(char *buf, int size);
43+
int asyncRead(char *buf, int size, std::function<void(int)> cb);
3744
std::string errorString();
3845
};
3946

0 commit comments

Comments
 (0)