3 实现
3.3 KermitRecvFile
该模块实现了Kermit接收文件功能。
序列图如下:
3.3.1 KermitRecvFile定义
class QSerialPort;
class KermitRecvFile : public QObject, public Kermit
{
Q_OBJECT
public:
explicit KermitRecvFile(QSerialPort *serial, QObject *parent = nullptr);
public slots:
void start(QString const& fileName);
void stop();
void cancel();
signals:
void gotFileSize(quint64 filesize);
void progressInfo(quint32 blockNumber, quint64 bytesOfSend);
void error(QString const& e);
void finished();
protected:
int write(char const *data, int size) override;
int read(char *data, int size) override;
char getc() override;
void on_init(int seq, const char* data, int size) override;
void on_data(int seq, const char* data, int size) override;
void on_break(int seq, const char* data, int size) override;
private:
void saveData(const char* data, int size);
bool singled() { return signal_; }
void doSignal() { signal_ = true; };
private:
QSerialPort* serial_;
volatile bool signal_;
State state_ = SSNUL;
QFile file_;
int timeMs = 0;
quint32 blockNumber = 0;
quint64 bytesOfRecv_ = 0;
};
公共接口:
- start 开始接收文件
- stop 停止传输文件
- cancel 中断传输文件
信号:
- gotFileSize 文件大小信号
- progressInfo 传输进度信号
- error 出错信号
- finished 传输结束信号
重载接口:
- on_init 处理开始包
- on_data 处理数据包
- on_break 处理中断包
- write 向串口写数据
- read 从串口读数据
- getc 从串口读取一个字符
其它接口:
- saveData 解码数据并保存
3.3.2 KermitRecvFile实现
3.3.2.1 start/stop/cancel
void KermitRecvFile::start(QString const& fileName)
{
file_.setFileName(fileName);
while(!singled() && state_ != SSBRK)
recv_packet();
emit finished();
serial_->moveToThread(QApplication::instance()->thread());
}
void KermitRecvFile::stop() { doSignal(); }
void KermitRecvFile::cancel() { state_ = SSBRK; }
函数说明:
- start
- 循环接收数据包,直到收到停止或终止信号
- 发送结束信号
- stop 发送停止信号
- cancel 设置终止信号
3.3.2.2 on_init/on_data/on_break
void KermitRecvFile::on_init(int seq, const char* data, int size)
{
Kermit::on_init(seq, data, size);
state_ = SSINT;
}
void KermitRecvFile::on_data(int seq, const char* data, int size)
{
Q_UNUSED(seq)
if(state_ == SSINT)
{
file_.open(QIODevice::WriteOnly);
state_ = SSDAT;
}
if(file_.isOpen())
{
saveData(data, size);
send_ack(seq);
}
}
void KermitRecvFile::on_break(int seq, const char* data, int size)
{
Q_UNUSED(seq)
Q_UNUSED(data)
Q_UNUSED(size)
state_ = SSBRK;
}
函数说明:
- on_init 处理开始包,设置状态为初始
- on_data
- 如果是初始状态,则打开文件,将状态设置为接收数据状态
- 保存数据
- on_break 设置状态为中断
3.2.2.3 write/read/getc/saveData
int KermitRecvFile::write(char const *data, int size) {
return serial_->write(data, size);
}
int KermitRecvFile::read(char *data, int size)
{
int read_size = 0;
while(!singled() && read_size < size)
{
if(serial_->waitForReadyRead(timeMs))
read_size += serial_->read(data + read_size, size - read_size);
}
return read_size;
}
char KermitRecvFile::getc()
{
char c = NUL;
while(!singled())
{
if(serial_->waitForReadyRead(timeMs))
{
serial_->getChar(&c);
break;
}
}
return c;
}
void KermitRecvFile::saveData(const char* data, int size)
{
char d[MaxLen];
char a;
int index = 0;
int recvSize = 0;
while(index < size)
{
index += decode(data + index, a);
d[recvSize++] = a;
}
file_.write(d, recvSize);
blockNumber++;
bytesOfRecv_ += recvSize;
emit progressInfo(blockNumber, bytesOfRecv_);
}
函数说明:
- write 向串口写数据
- read 从串口读取指定大小数据
- getc 从串口读取一个字符
- saveData
- 解码数据
- 保存数据
- 发送进度信号
Qt实现Kermit协议(三)
未完待续…