#include "uart.h"
#include "unistd.h"
#include <QtSerialPort/QtSerialPort>
#include <QTimer>
#include <QByteArray>
#include <QThread>
#include <QDebug>
std::vector<QSerialPortInfo> Uart::serialPorts_;
Uart::Uart(const QString& uartName, uint baudRate, int ms_rcv/*=-1*/)
: uart_(nullptr)
, uartName_(uartName)
, baudRate_(baudRate)
, serialConnect_(false)
, thread_(nullptr)
, timer_(nullptr)
, enWork_(false)
{
uart_ = new QSerialPort;
Q_CHECK_PTR(uart_);
if (ms_rcv > 0)
{
qDebug("== Use a separate thread to receive serial:%s data. ==", uartName.toLatin1().constData());
thread_ = new QThread;
Q_CHECK_PTR(thread_);
timer_ = new QTimer(this);
Q_CHECK_PTR(timer_);
timer_->setInterval(ms_rcv/2);
connect(timer_, &QTimer::timeout, this, [=](){
timer_->stop();
if (buf_.length()>0)
{
recvData(buf_);
buf_.clear();
}
});
connect(uart_, &QSerialPort::readyRead, this, &Uart::onReadyRead);
this->moveToThread(thread_);
uart_->moveToThread(thread_);
connect(thread_, &QThread::started, this, [=](){
createUartIntance(uartName_, baudRate_);
if (!serialConnect_)
{
QTimer::singleShot(30*1000, this, SLOT(onReconnect()));
}
});
thread_->start();
}
else
{
qDebug("** Use GUI-thread to receive serial:%s data. **", uartName.toLatin1().constData());
createUartIntance(uartName_, baudRate_);
if (!serialConnect_)
{
QTimer::singleShot(30*1000, this, SLOT(onReconnect()));
}
}
}
Uart::~Uart()
{
if (timer_ != nullptr)
{
timer_->stop();
delete timer_;
timer_ = nullptr;
}
uart_->close();
delete uart_;
if (thread_ != nullptr)
{
if (thread_->isRunning())
{
thread_->quit();
thread_->wait(500);
}
}
}
void Uart::onReadyRead()
{
QByteArray by = uart_->readAll();
if (by.size() <= 0) return;
if (!enWork_)
{
if (!buf_.isEmpty())
{
buf_.clear();
}
return;
}
buf_.append(by);
if (buf_.size() >= 56)
{
timer_->start();
}
}
int Uart::InitAvaliablePorts()
{
qDebug("Avaliable SerialPorts: ");
serialPorts_.clear();
int i = 0;
foreach (const QSerialPortInfo & info, QSerialPortInfo::availablePorts())
{
qDebug("- [%d] %s, Desc:%s\t", i,
info.portName().toLatin1().data(),
info.description().toLatin1().data());
serialPorts_.push_back(info);
++i;
}
return serialPorts_.size();
}
bool Uart::GetSerialPortInfo(QSerialPortInfo& serialChosen, const QString& uartName)
{
int portIndex = -1;
for (size_t i=0; i<Uart::serialPorts_.size(); ++i)
{
if (serialPorts_[i].portName() == uartName)
{
portIndex = i;
break;
}
}
if (portIndex == -1) return false;
serialChosen = Uart::serialPorts_[portIndex];
return true;
}
void Uart::onReconnect()
{
serialConnect_ = (ConnectUart(serialChosen_, baudRate_)>=0);
if (!serialConnect_)
{
qWarning() << QString("### Err: !! Serial %1 Not Connect !! ###").arg(serialChosen_.portName()).toLatin1().constData();
QTimer::singleShot(30*1000, this, SLOT(onReconnect()));
}
}
void Uart::createUartIntance(const QString& uartName, uint baudRate)
{
int count = 0;
int portIndex = -1;
do {
for (size_t i=0; i<Uart::serialPorts_.size(); ++i)
{
if (Uart::serialPorts_[i].portName() == uartName)
{
portIndex = i;
break;
}
}
if (portIndex != -1) break;
usleep(500*1000);
count++;
} while (count<6);
if (portIndex == -1)
{
portIndex = 0;
return;
}
serialChosen_ = Uart::serialPorts_[portIndex];
serialConnect_ = (ConnectUart(serialChosen_, baudRate)>=0);
if (!serialConnect_)
{
qWarning() << "Err: !! Serial Not Connect !!";
qWarning() << "Err: !! Serial Not Connect !!";
qWarning() << "Err: !! Serial Not Connect !!";
}
}
int Uart::ConnectUart(const QSerialPortInfo& serialChosen, uint baudRate)
{
uart_->setPort( serialChosen );
if (!uart_->open(QIODevice::ReadWrite))
{
int retries = 10; //30
while (retries-- > 0 && uart_->error() == QSerialPort::PermissionError)
{
qDebug() << QString("Cannot open %1").arg(uart_->portName()).toLatin1().data();
usleep(500*1000);
if (uart_->open(QIODevice::ReadWrite))
{
uart_->clearError();
break;
}
}
if (uart_->error() != QSerialPort::NoError)
{
qWarning() << QString("Failed to open Serial Device: %1 (E%2)").arg(uart_->portName()).arg(uart_->error());
return -1;
}
}
uart_->setBaudRate(QSerialPort::BaudRate(38400));
uart_->setParity(QSerialPort::NoParity);
uart_->setDataBits(QSerialPort::Data8);
uart_->setStopBits(QSerialPort::OneStop);
uart_->setFlowControl(QSerialPort::NoFlowControl);
uart_->clearError();
uart_->clear();
if (timer_ == nullptr)
{
connect(uart_, &QSerialPort::readyRead, this, [=](){
QByteArray by = uart_->readAll();
if (by.size() <= 0) return;
if (!enWork_) {
return;
}
recvData( by );
});
}
qDebug() << QString("%1 is ready.").arg(uart_->portName()).toLatin1().data();
return 0;
}
void Uart::recvData(QByteArray by)
{
if (!_yReadHead)
{
if (!_recvData.isEmpty())
_recvData.clear();
}
_recvData.append(by);
checkData(_recvData, _yReadHead); //virtual
}
void Uart::checkData(QByteArray &by, bool &hasReadHead)
{
static int s_iErr = 0;
int firstHeaderIndex = 0;
while (1)
{
firstHeaderIndex = by.indexOf("!AIV");
if (firstHeaderIndex < 0)
{
// qDebug() << "!! Cannot find Head.";
hasReadHead = false;
break;
}
hasReadHead = true;
if (firstHeaderIndex > 0)
{
by.remove(0, firstHeaderIndex);
}
int index = by.indexOf("\r\n");
if (index == -1)
{
if (++s_iErr >= 3)
{
qDebug() << "!! MS Err, no end-char, delete.";
hasReadHead = false;
}
break;
}
s_iErr = 0;
if (index < 20)
{
qDebug() << "!! MS Err, delete.";
hasReadHead = false;
break;
}
int len = index + 2; //20220103
if (len >= 120)
{
qDebug() << "!! Ms Too long, delete.";
hasReadHead = false;
break;
}
QByteArray data = by.mid(0, len);
index = data.indexOf("\r\n");
resolverFrame(data.mid(0,index));
by.remove(0, len);
if (by.isEmpty())
{
hasReadHead = false;
break;
}
}
}
void Uart::resolverFrame(const QByteArray &by)
{
//数据解析
qDebug()<<by;
}
void Uart::onSendData(const unsigned char* ch, int count, int retry/*=3*/)
{
int ret = justSend(ch, count, retry);
if (ret == 0) //<0: not connect
{
qDebug("Err: Uart Send fail (%d).", ret);
}
}
int Uart::justSend(const uchar* ch, int count, int retry)
{
if (!serialConnect_) return -1;
int i = 0;
bool success = true;
while (1)
{
if (uart_->write((const char*)ch, count) != count)
{
if (++i >= retry)
{