Qt实现Kermit协议(四)

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协议(三)
未完待续…

上一篇:Spark-Scala语言实战(7)


下一篇:Qt实现QDebug重定向输出到日志文件(支持多线程安全)