STM32f407 网络接收 fpga 的 bin 文件并更新到 fpga series7(2)

STM32f407 网络接收 fpga 的 bin 文件并更新到 fpga series7(2)

简介

实验 2:在单片机搭建好 tcp 服务器后,编写传送文件的上位机。

整体实现

- 利用qt的tcpsocket简单封装
- 每次发送512字节,这样小的tcp包就不会自动分包。保证每一个512tcp包都有帧头。
- 每次发送完,等待服务器返回一个包,用来判断是否正确写入fpga

代码

tcpclient.h

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QObject>
#include <QString>
#include <QTcpSocket>
#include <QHostAddress>


class TcpClient : public QObject {
    Q_OBJECT
public:
    explicit TcpClient(QObject *parent = nullptr);

    Q_INVOKABLE bool connect_server(QString ip, int port);
    Q_INVOKABLE void close_client();

    Q_INVOKABLE bool send_buffer(char *buf, size_t len);
    Q_INVOKABLE bool recv_buffer(char *pdata, uint32_t len);

private:
    QTcpSocket *socket_;
};

#endif  // TCPCLIENT_H

tcpclient.c


#include "tcpclient.h"

#include <QAbstractSocket>


TcpClient::TcpClient(QObject *parent) {
    socket_ = new QTcpSocket(this);
}

/// @brief 连接服务器
/// @param ip 
/// @param port 
/// @return 成功返回true,超时返回false
bool TcpClient::connect_server(QString ip, int port) {
    socket_->connectToHost(QHostAddress(ip), port);
    if (socket_->waitForConnected(3000)) {
        return true;
    } else {
        return false;
    }
}

void TcpClient::close_client() { socket_->close(); }


/// @brief 发送buffer
/// @param buf 
/// @param len 
/// @return 成功返回true,超时返回false
bool TcpClient::send_buffer(char *buf, size_t len) {
    socket_->write(buf, len);
    if (socket_->waitForBytesWritten(3000)) {
        return true;
    } else {
        return false;
    }
    socket_->flush();
}

/// @brief 接收buffer
/// @param pdata 
/// @param len 
/// @return 成功返回true,超时返回false
bool TcpClient::recv_buffer(char *pdata, uint32_t len) {
    if(!socket_->waitForReadyRead(10000)){
        return false;
    }
    socket_->read(pdata, len);
    return true;
}

main.c

// 文件: main.cpp
// 时间: 2024-08-21
// 来自: ccj
// 描述: 把fpga程序发送给STM32服务器
//          1. 自定义帧结构 512字节,其中24字节帧头。剩下都是数据
//          2. 发送一个512字节的帧,要接收一个24字节的帧,里面有判断是否写入fpga成功。
//          3. 整体流程
//              3.1 发送24字节的开始命令帧
//              3.2 发送512字节的数据帧
//              3.1 发送24字节的结束命令帧


#include <stdint.h>
#include <time.h>
#include <thread>

#include <QFile>
#include <QString>
#include <QFileInfo>

#include "tcpclient.h"

#define qdebug() qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"

// 帧信息
#define kbuffer_len  512
#define kheader_size 24
#define kdata_len    (kbuffer_len - kheader_size)
#define kmagic       0xaa5555aa
#define kmagic1      0x55aaaa55

// 发送帧头type字段定义
#define ksend_type_start 0xa
#define ksend_type_write 0xb
#define ksend_type_end   0xc

// 接收帧头offset定义
#define krecv_offset_success 0
#define krecv_offset_failed  1

/// @brief 帧头
struct tcp_package_header {
    uint32_t magic;
    uint32_t type;
    uint32_t data_offset;
    uint32_t data_len;
    uint32_t order;
    uint32_t magic1;
};

// 发送和接收缓冲区
char send_buffer[kbuffer_len];
char recv_buffer[kheader_size];

struct tcp_package_header *send_header = (struct tcp_package_header *)send_buffer;
struct tcp_package_header *recv_header = (struct tcp_package_header *)recv_buffer;

char *pdata = send_buffer + kheader_size;


// 接收校验
// 发送一个tcp包,就接收一个tcp包做校验
#define recv_verify()                                                                \
    do {                                                                             \
        ret = client.recv_buffer(recv_buffer, kheader_size);                         \
        if (!ret) {                                                                  \
            qdebug() << "recv buffer failed.";                                       \
            return 1;                                                                \
        }                                                                            \
        switch (recv_header->data_offset) {                                          \
            case krecv_offset_success: break;                                        \
            case krecv_offset_failed: qdebug() << "write to fpga failed."; return 1; \
            default: break;                                                          \
        }                                                                            \
    } while (0)


int main(int argc, char *argv[]) {
    // 0 读取命令行参数
    if (argc != 4) {
        qdebug() << "Usage: tcpclient {ip} {port} {file_full_path}";
        return 1;
    }
    QString server_ip = QString::fromLocal8Bit(argv[1]);
    int server_port = std::stoi(argv[2]);
    QString file_full_path = QString::fromLocal8Bit(argv[3]);
    // QString server_ip = "192.168.11.33";
    // int server_port = 7;
    // QString file_full_path = "qf_pciefmc_top.bin";


    // 1 判断参数是否有效
    // 1.1 判断是否可以连接服务器
    TcpClient client;
    bool ret = client.connect_server(server_ip, server_port);
    if (!ret) {
        qdebug() << "connect server failed.";
        return 1;
    }

    // 1.2 判断文件是否存在
    QFile file(file_full_path);
    if (!file.open(QIODevice::ReadOnly)) {
        qdebug() << "Cannot open file for reading:" << file.errorString();
        return 1;
    }


    clock_t start, end;
    start = clock();

    // 2 发送文件到服务器
    // 2.1 发送开始帧
    std::memset(send_header, 0, sizeof(struct tcp_package_header));
    send_header->magic = kmagic;
    send_header->data_offset = kheader_size;
    send_header->magic1 = kmagic1;
    send_header->type = ksend_type_start;
    ret = client.send_buffer(send_buffer, kheader_size);
    if (!ret) {
        qdebug() << "send buffer failed.";
        return 1;
    }
    recv_verify();


    // 2.2 循环文件发送每一个帧
    QFileInfo fileinfo(file_full_path);
    uint64_t total_file_size = fileinfo.size();
    uint64_t total_read_size = 0;
    uint64_t read_buf_size = 0;
    int order = 1;
    while (total_read_size < total_file_size) {
        // 2.2.1 读取一个帧
        read_buf_size = file.read(pdata, kdata_len);
        if (read_buf_size == -1) {
            qdebug() << "read file error." << file.errorString();
            return 1;
        }

        // 2.2.2 发送帧
        send_header->type = ksend_type_write;
        send_header->data_len = read_buf_size;
        send_header->order = order;
        ret = client.send_buffer(send_buffer, kbuffer_len);
        if (!ret) {
            qdebug() << "send buffer failed.";
            return 1;
        }
        recv_verify();

        // 2.2.3 继续循环
        total_read_size += read_buf_size;
        order++;

        // 打印发送进度
        if (order % 5 == 0)
            qdebug() << "total: " << total_file_size << ", send: " << total_read_size
                     << ", process: " << (double)total_read_size / total_file_size * 100 << "%";
    }


    // 2.3 发送结束帧
    send_header->type = ksend_type_end;
    ret = client.send_buffer(send_buffer, kheader_size);
    if (!ret) {
        qdebug() << "send buffer failed.";
        return 1;
    }
    recv_verify();

    end = clock();
    double cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
    qdebug() << "update success. cost time: " << cpu_time_used << "s.";
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值