赞
踩
XMODEM协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异步文件运输协议。这种协议以128字节块的形式传输数据,并且每个块都使用一个校验和过程来进行错误检测。使用循环冗余校验的与XMODEM相应的一种协议称为XMODEM-CRC。还有一种是XMODEM-1K,它以1024字节一块来传输数据。YMODEM也是一种XMODEM的实现。它包括XMODEM-1K的所有特征,另外在一次单一会话期间为发送一组文件,增加了批处理文件传输模式。
本文利用C++实现XYModem-1K协议,并利用Qt串口类QSerialPort实现数据读写。
该模块实现XYModem协议发送文件。
流程图:
class QSerialPort;
class XYModemSendFile : public QObject, public YModem
{
Q_OBJECT
public:
explicit XYModemSendFile(QSerialPort *serial, QObject *parent = nullptr);
public slots:
void startYModem(QString const& fileName);
void startXModem(QString const& fileName);
void stop() { { doSignal(); }}
void cancel() { tx_cancle(); }
signals:
void gotFileSize(quint64 filesize);
void progressInfo(quint32 blockNumber, quint64 bytesOfSend);
void error(QString const& e);
void finished();
protected:
uint32_t write(uint8_t const *data, uint32_t size) override;
uint32_t read(uint8_t *data, uint32_t size) override;
uint8_t get_code(bool isWait = true) override;
private:
bool singled() { return signal_; }
void doSignal() { signal_ = true; };
void doError(QString const& text);
private:
QSerialPort* serial_;
volatile bool signal_;
};
公共接口:
信号:
重载接口:
void XYModemSendFile::startYModem(QString const& fileName)
{
QFileInfo fileInfo(fileName);
uint64_t fileSize = fileInfo.size();
std::string filename = fileInfo.fileName().toStdString();
std::string filesize = QString::number(fileSize).toStdString();
if(filename.size() + filesize.size() + 2 > SIZE1)
{
doError("Filename too long!");
return;
}
//Get Start flag
if(get_code() != C)
{
doError("Can not get C!");
return;
}
//SOH first block
emit gotFileSize(fileSize);
if(!tx_start(filename, filesize))
{
doError("Can not get ACK and C!");
return;
}
//Send data of file
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))
{
doError(QString("%1 cannot be opened!").arg(fileName));
return;
}
uint8_t data[SIZE2];
quint64 bytesOfSend = 0;
quint32 block = 0;
bool is_end = false;
while(!singled())
{
quint64 size = file.read((char *)data, sizeof(data));
if(size == 0)
{
is_end = true;
break;
}
if(tx_send(data, size))
{
block++;
bytesOfSend += size;
emit progressInfo(block, bytesOfSend);
}
else
{
emit error("send is error");
break;
}
}
//Send end
if(is_end)
{
if(tx_eot())
{
if(tx_end())
{
//std::cout << "end is ok" << std::endl;
}
}
}
emit finished();
serial_->moveToThread(QApplication::instance()->thread());
}
函数流程:
void XYModemSendFile::startXModem(QString const& fileName)
{
QFileInfo fileInfo(fileName);
uint64_t fileSize = fileInfo.size();
//Get Start flag
if(get_code() != C)
{
doError("Can not get C!");
return;
}
//SOH first block
emit gotFileSize(fileSize);
//Send data of file
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))
{
doError(QString("%1 cannot be opened!").arg(fileName));
return;
}
uint8_t data[SIZE2];
quint64 bytesOfSend = 0;
quint32 block = 0;
bool is_end = false;
next_id();
while(!singled())
{
quint64 size = file.read((char *)data, sizeof(data));
if(size == 0)
{
is_end = true;
break;
}
if(tx_send(data, size))
{
block++;
bytesOfSend += size;
emit progressInfo(block, bytesOfSend);
}
else
{
emit error("send is error");
break;
}
}
//Send end
if(is_end)
{
if(tx_eot())
{
//std::cout << "end is ok" << std::endl;
}
}
emit finished();
serial_->moveToThread(QApplication::instance()->thread());
}
函数流程:
uint32_t XYModemSendFile::write(uint8_t const *data, uint32_t size)
{
return serial_->write((const char *)data, size);
}
uint32_t XYModemSendFile::read(uint8_t *data, uint32_t size)
{
return serial_->read((char *)data, size);
}
函数说明:
uint8_t XYModemSendFile::get_code(bool isWait)
{
while(!singled())
{
if(serial_->waitForReadyRead(10))
{
uint8_t data[1] = { 0 };
read(data, sizeof(data));
return data[0];
}
if(!isWait)
break;
}
return MAX;
}
函数流程:
void XYModemSendFile::doError(QString const& text)
{
emit error(text);
serial_->moveToThread(QApplication::instance()->thread());
emit finished();
}
函数流程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。