【PCIE】基于PCIE4C的数据传输(一)——PC访问FPGA

这篇具有很好参考价值的文章主要介绍了【PCIE】基于PCIE4C的数据传输(一)——PC访问FPGA。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

FPGA设计

PCIE4C

  PCIE4C是Ultrascale+系列开始引入的硬核,它是PCIE4硬核的延续,在功能上增加了对PCIe4.0协议的支持,由于PCIe报文采用高速串行传输,到达FPGA后首先经过GT转换为低速并行数据,之后由PCIE4C进行进一步处理,得到便于用户使用的AXI-Stream形式的报文。
为了便于使用,Xilinx将GT与PCIE4C打包为一个IP核Ultrascale FPGAs Transceivers Wizard(产品手册),在将FPGA作为终端设备的基本配置下,IP核的主要接口如下:
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  各接口对应功能可从产品手册中看到,主要接口为cq、cc、rq、rc四个接口。其中cq、cc为主机(PC机)请求、从机(FPGA)响应接口,PC机将读/写地址报文通过cq接口通过握手方式发送到FPGA,FPGA将读地址对应的数据内容/写地址完成报文通过cc接口通过握手方式发送给PC机。rq、rc为从机(FPGA)请求、主机(PC机)响应接口,FPGA将读/写地址报文通过rq接口通过握手方式发送到PC机,PC机将读地址对应的数据内容/写地址完成报文通过cc接口通过握手方式发送给FPGA。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  对于PC主动传输过程,CPU将需要读地址/写地址及数据告知FPGA,由FPGA被动进行响应处理,主要用到cq、cc两个接口。

cq接口

  cq接口具有的信号及传输方向如图所示。需要注意的是,不同于标准PCIe报文格式,PCIE4C将部分PCIe报文头字段(描述符)放入tuser字段中。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  同时,PCIE4C将剩余的PCIe报文头字段留在第一个传输tdata的前几个字节中,对于内存、IO、原子操作类型的PCIe报文,tdata头个传输字段划分如下图所示。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  各字段解释可从产品手册找到。
  对于128bit位宽AXIS流接口、DWORD对齐模式,一次写内存请求操作对应波形类似下图。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  对于128bit位宽AXIS流接口,一次读内存请求操作对应波形类似下图。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog

cc接口

  cc通道的接口信号如下图,当每次cq写请求操作结束后,FPGA侧需要通过cc接口返回写成功或写失败响应。
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  响应的每第一次传输的tdata的前几字节都被视为PCIe头字段(描述符),如下图
pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog
  各字段解释可从产品手册找到。
  对于128bit位宽AXIS流接口、DWORD对齐模式,一次读内存响应操作对应波形类似下图。

pcie fpga,# PCIe,fpga开发,PCIE,PCIE4C,Xilinx,Verilog

代码

1. 读写请求处理模块

  这里列出negative_process.sv的状态机代码,这里PCIE4C例化了四个功能设备,每个功能设备具有独立的ram区域,这里的状态机代码负责对PC机传入的对应功能设备ram的读写操作进行处理。

    always @(*) begin
        case (cs)
        0: begin
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 4;
                end
                else begin
                    ns = 1;
                end
            end
            else begin
                ns = 0;
            end
        end
        1: begin // must have header
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 3;
                end
                else begin
                    ns = 2;
                end
            end        
            else begin
                ns = 1;
            end    
        end
        2: begin
            if (m_axis_cq_tvalid & m_axis_cq_tlast & m_axis_cq_tready) begin
                ns = 3;
            end        
            else begin
                ns = 2;
            end   
        end
        3: begin // last_packet's frame
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 4;
                end
                else begin
                    ns = 1;
                end
            end
            else begin
                ns = 0;
            end
            // ns = 0;
        end
        4: begin // require cpl finish
            ns = 5;
        end
        5: begin
            if (usr_first_be_used_rr & cpl_ready) begin
                ns = 0;
            end
            else begin
                ns = 5;
            end
        end
        default: begin
            ns = 0;
        end
        endcase
    end
2. 读写响应处理模块

  这里列出positive_process.sv的状态机代码,它通过监听negative_process.sv模块进行操作类型,如果出现读写操作则返回对应响应包。

    always @(*) begin
        case (cs)
        0: begin
            // if (dma_enable) begin
            ns = 1;
            // end
            // else begin
            //     ns = 0;
            // end
        end
        1: begin
            ns = 2;
        end
        2: begin
            if (dma_fetch) begin
                ns = 7;
            end
            else begin
                ns = 1;
            end
        end
        7: begin    // delay wait fetch data from ram
            if (s_axis_rq_tready[0]) begin
                ns = 8;
            end
            else begin
                ns = 7;
            end
        end
        8: begin    // delay
            if (s_axis_rq_tready[0]) begin
                ns = 3;
            end
            else begin
                ns = 8;
            end
        end
        3: begin
            if (s_axis_rq_tvalid && s_axis_rq_tready[0]) begin
                if (dma_trans_direction) begin
                    ns = 4;
                end
                else begin
                    ns = 5;
                end
            end
            else begin
                ns = 3;
            end
        end
        4: begin // wr
            if (s_axis_rq_tvalid && s_axis_rq_tready[0] & s_axis_rq_tlast) begin
                ns = 6;
            end
            else begin
                ns = 4;
            end
        end
        5: begin // rd cpl
            if (~cpl_start & cpl_done & last_trans_flag_r) begin
                ns = 6;
            end
            else begin
                ns = 5;
            end
        end
        6: begin // write finish flag
            if (irq_ready) begin
                ns = 0;
            end
            else begin
                ns = 6;
            end
        end
        default: begin
            ns = 0;
        end
        endcase
    end
3. ram模块

  由于每次读取和写入ram的过程可能会同时对ram相邻两个地址的数据进行操作,为了降低读取和写入ram数据的延时,这里使用了两个ram并联的方式,即偶数地址、奇数地址数据分别存在两块ram中。当遇到对ram相邻两个地址数据的操作时,能够从两块ram同时取数并截取得到返回结果。核心代码如下

`timescale 1ns / 1ps
//
// Company: 
// Engineer: wjh776a68
// 
// Create Date: 09/13/2023 02:45:50 PM
// Design Name: 
// Module Name: ram_ctrl
// Project Name: 
// Target Devices: xcvu37p
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ram_ctrl #(
    parameter RAM_DEPTH = 1024,
    parameter BYTEADDR_WIDTH = $clog2(RAM_DEPTH * 32 / 8),
    parameter ADDR_WIDTH = $clog2(RAM_DEPTH / 4)
) (
    input  wire clk,

    output reg [127:0]                 ram_douta,
    output reg [127:0]                 ram_doutb,
    input  wire [BYTEADDR_WIDTH - 1:0] ram_byteaddra,
    input  wire [BYTEADDR_WIDTH - 1:0] ram_byteaddrb,
    input  wire [127:0]                ram_dina,
    input  wire [127:0]                ram_dinb,
    input  wire [15:0]                 ram_wea,
    input  wire [15:0]                 ram_web,
    input  wire                        ram_ena,
    input  wire                        ram_enb
);

    wire [127:0]            ram_lo_douta, ram_hi_douta;
    wire [127:0]            ram_lo_doutb, ram_hi_doutb;
    reg  [ADDR_WIDTH - 1:0] ram_lo_addra, ram_hi_addra;
    reg  [ADDR_WIDTH - 1:0] ram_lo_addrb, ram_hi_addrb;
    reg  [127:0]            ram_lo_dina, ram_hi_dina;
    reg  [127:0]            ram_lo_dinb, ram_hi_dinb;
    reg  [15:0]             ram_lo_wea, ram_hi_wea;
    reg  [15:0]             ram_lo_web, ram_hi_web;

    reg [BYTEADDR_WIDTH - 1:0] ram_byteaddra_r, ram_byteaddra_rr;
    reg [BYTEADDR_WIDTH - 1:0] ram_byteaddrb_r, ram_byteaddrb_rr;

    always @(posedge clk) begin
        if (ram_ena) begin
            ram_byteaddra_r <= ram_byteaddra;
            ram_byteaddra_rr <= ram_byteaddra_r;
        end
    end

    always @(posedge clk) begin
        case (ram_byteaddra_rr[4 : 0]) 
        5'b00000: begin
            ram_douta <= ram_lo_douta; 
        end
        5'b10000: begin
            ram_douta <= ram_hi_douta; 
        end
        5'b00001: begin
            ram_douta <= {ram_hi_douta[0 +: 1 * 8], ram_lo_douta[1 * 8 +: 15 * 8]}; 
        end
        5'b00010: begin
            ram_douta <= {ram_hi_douta[0 +: 2 * 8], ram_lo_douta[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b01111: begin
            ram_douta <= {ram_hi_douta[0 +: 15 * 8], ram_lo_douta[15 * 8 +: 1 * 8]}; 
        end
        5'b10001: begin
            ram_douta <= {ram_lo_douta[0 +: 1 * 8], ram_hi_douta[1 * 8 +: 15 * 8]}; 
        end
        5'b10010: begin
            ram_douta <= {ram_lo_douta[0 +: 2 * 8], ram_hi_douta[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b11111: begin
            ram_douta <= {ram_lo_douta[0 +: 15 * 8], ram_hi_douta[15 * 8 +: 1 * 8]}; 
        end
        endcase
    end

    always @(posedge clk) begin
        if (ram_enb) begin
            ram_byteaddrb_r  <= ram_byteaddrb;
            ram_byteaddrb_rr <= ram_byteaddrb_r;
        end
    end

    always @(posedge clk) begin
        case (ram_byteaddrb_rr[4 : 0]) 
        5'b00000: begin
            ram_doutb <= ram_lo_doutb; 
        end
        5'b10000: begin
            ram_doutb <= ram_hi_doutb; 
        end
        5'b00001: begin
            ram_doutb <= {ram_hi_doutb[0 +: 1 * 8], ram_lo_doutb[1 * 8 +: 15 * 8]}; 
        end
        5'b00010: begin
            ram_doutb <= {ram_hi_doutb[0 +: 2 * 8], ram_lo_doutb[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b01111: begin
            ram_doutb <= {ram_hi_doutb[0 +: 15 * 8], ram_lo_doutb[15 * 8 +: 1 * 8]}; 
        end
        5'b10001: begin
            ram_doutb <= {ram_lo_doutb[0 +: 1 * 8], ram_hi_doutb[1 * 8 +: 15 * 8]}; 
        end
        5'b10010: begin
            ram_doutb <= {ram_lo_doutb[0 +: 2 * 8], ram_hi_doutb[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b11111: begin
            ram_doutb <= {ram_lo_doutb[0 +: 15 * 8], ram_hi_doutb[15 * 8 +: 1 * 8]}; 
        end
        endcase
    end

    always @(*) begin
        case (ram_byteaddra[4])
        1'b0: begin
            ram_lo_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
            ram_hi_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
        end
        1'b1: begin
            ram_lo_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5] + 1;
            ram_hi_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
        end
        endcase 
        

        case (ram_byteaddra[4 : 0]) 
        5'b00000: begin
            ram_lo_wea <= ram_wea;
            ram_hi_wea <= 0;
            ram_lo_dina <= ram_dina;
            ram_hi_dina <= 0;
        end
        5'b10000: begin
            ram_lo_wea <= 0;
            ram_hi_wea <= ram_wea;
            ram_lo_dina <= 0;
            ram_hi_dina <= ram_dina;
        end
        5'b00001: begin
            ram_lo_wea <= {ram_wea[0 +: 15], 1'b0};
            ram_hi_wea <= {15'b0, ram_wea[15 +: 1]};
            ram_lo_dina <= {ram_dina[0 +: 15 * 8], {1{8'bx}}};
            ram_hi_dina <= {{15{8'bx}}, ram_dina[15 * 8 +: 1 * 8]};
        end
        5'b00010: begin
            ram_lo_wea <= {ram_wea[0 +: 14], 2'b0};
            ram_hi_wea <= {14'b0, ram_wea[14 +: 2]};
            ram_lo_dina <= {ram_dina[0 +: 14 * 8], {2{8'bx}}};
            ram_hi_dina <= {{14{8'bx}}, ram_dina[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b01111: begin
            ram_lo_wea <= {ram_wea[0 +: 1], 15'b0};
            ram_hi_wea <= {1'b0, ram_wea[1 +: 15]};
            ram_lo_dina <= {ram_dina[0 +: 1 * 8], {15{8'bx}}};
            ram_hi_dina <= {{1{8'bx}}, ram_dina[1 * 8 +: 15 * 8]};
        end
        5'b10001: begin
            ram_hi_wea <= {ram_wea[0 +: 15], 1'b0};
            ram_lo_wea <= {15'b0, ram_wea[15 +: 1]};
            ram_hi_dina <= {ram_dina[0 +: 15 * 8], {1{8'bx}}};
            ram_lo_dina <= {{15{8'bx}}, ram_dina[15 * 8 +: 1 * 8]};
        end
        5'b10010: begin
            ram_hi_wea <= {ram_wea[0 +: 14], 2'b0};
            ram_lo_wea <= {14'b0, ram_wea[14 +: 2]};
            ram_hi_dina <= {ram_dina[0 +: 14 * 8], {2{8'bx}}};
            ram_lo_dina <= {{14{8'bx}}, ram_dina[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b11111: begin
            ram_hi_wea <= {ram_wea[0 +: 1], 15'b0};
            ram_lo_wea <= {1'b0, ram_wea[1 +: 15]};
            ram_hi_dina <= {ram_dina[0 +: 1 * 8], {15{8'bx}}};
            ram_lo_dina <= {{1{8'bx}}, ram_dina[1 * 8 +: 15 * 8]};
        end
        endcase
    end



    always @(*) begin
        case (ram_byteaddrb[4])
        1'b0: begin
            ram_lo_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
            ram_hi_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
        end
        1'b1: begin
            ram_lo_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5] + 1;
            ram_hi_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
        end
        endcase 
        

        case (ram_byteaddrb[4 : 0]) 
        5'b00000: begin
            ram_lo_web <= ram_web;
            ram_hi_web <= 0;
            ram_lo_dinb <= ram_dinb;
            ram_hi_dinb <= 0;
        end
        5'b10000: begin
            ram_lo_web <= 0;
            ram_hi_web <= ram_web;
            ram_lo_dinb <= 0;
            ram_hi_dinb <= ram_dinb;
        end
        5'b00001: begin
            ram_lo_web <= {ram_web[0 +: 15], 1'b0};
            ram_hi_web <= {15'b0, ram_web[15 +: 1]};
            ram_lo_dinb <= {ram_dinb[0 +: 15 * 8], {1{8'bx}}};
            ram_hi_dinb <= {{15{8'bx}}, ram_dinb[15 * 8 +: 1 * 8]};
        end
        5'b00010: begin
            ram_lo_web <= {ram_web[0 +: 14], 2'b0};
            ram_hi_web <= {14'b0, ram_web[14 +: 2]};
            ram_lo_dinb <= {ram_dinb[0 +: 14 * 8], {2{8'bx}}};
            ram_hi_dinb <= {{14{8'bx}}, ram_dinb[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b01111: begin
            ram_lo_web <= {ram_web[0 +: 1], 15'b0};
            ram_hi_web <= {1'b0, ram_web[1 +: 15]};
            ram_lo_dinb <= {ram_dinb[0 +: 1 * 8], {15{8'bx}}};
            ram_hi_dinb <= {{1{8'bx}}, ram_dinb[1 * 8 +: 15 * 8]};
        end
        5'b10001: begin
            ram_hi_web <= {ram_web[0 +: 15], 1'b0};
            ram_lo_web <= {15'b0, ram_web[15 +: 1]};
            ram_hi_dinb <= {ram_dinb[0 +: 15 * 8], {1{8'bx}}};
            ram_lo_dinb <= {{15{8'bx}}, ram_dinb[15 * 8 +: 1 * 8]};
        end
        5'b10010: begin
            ram_hi_web <= {ram_web[0 +: 14], 2'b0};
            ram_lo_web <= {14'b0, ram_web[14 +: 2]};
            ram_hi_dinb <= {ram_dinb[0 +: 14 * 8], {2{8'bx}}};
            ram_lo_dinb <= {{14{8'bx}}, ram_dinb[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b11111: begin
            ram_hi_web <= {ram_web[0 +: 1], 15'b0};
            ram_lo_web <= {1'b0, ram_web[1 +: 15]};
            ram_hi_dinb <= {ram_dinb[0 +: 1 * 8], {15{8'bx}}};
            ram_lo_dinb <= {{1{8'bx}}, ram_dinb[1 * 8 +: 15 * 8]};
        end
        endcase
    end



    ram #(
        .RAM_DEPTH(RAM_DEPTH)
    ) ram_lo_inst (
        .clk(clk),

        .ram_douta(ram_lo_douta),
        .ram_doutb(ram_lo_doutb),
        .ram_addra(ram_lo_addra),
        .ram_addrb(ram_lo_addrb),
        .ram_dina(ram_lo_dina),
        .ram_dinb(ram_lo_dinb),
        .ram_wea(ram_lo_wea),
        .ram_web(ram_lo_web),
        .ram_ena(ram_ena),
        .ram_enb(ram_enb)
    );

    ram #(
        .RAM_DEPTH(RAM_DEPTH)
    ) ram_hi_inst (
        .clk(clk),

        .ram_douta(ram_hi_douta),
        .ram_doutb(ram_hi_doutb),
        .ram_addra(ram_hi_addra),
        .ram_addrb(ram_hi_addrb),
        .ram_dina(ram_hi_dina),
        .ram_dinb(ram_hi_dinb),
        .ram_wea(ram_hi_wea),
        .ram_web(ram_hi_web),
        .ram_ena(ram_ena),
        .ram_enb(ram_enb)
    );
endmodule
仿真

  这里PCIe仿真利用Alex Forencich编写的cocotb pcie仿真库进行,核心代码如下。

    tb = TB(dut)

    await tb.init()

    mem = tb.rc.mem_pool.alloc_region(16*1024*1024)
    mem_base = mem.get_absolute_address(0)

    dev = tb.rc.find_device(tb.dev.functions[0].pcie_id)

    dev_pf0_bar0 = dev.bar_window[0]
    dev_pf0_bar2 = dev.bar_window[2]

    tb.log.info("Test memory write to BAR 2")

    test_data = b'\x11\x22\x33\x44'
    await dev_pf0_bar2.write(0, test_data)

    await Timer(100, 'ns')

    tb.log.info("Test memory read from BAR 2")

    val = await dev_pf0_bar2.read(0, len(test_data), timeout=1000)
    tb.log.info("Read data: %s", val)
    assert val == test_data

PC驱动设计

  由于系统为RHEL,因此驱动基于linux内核进行开发,对于主机而言,PCIe与PCI设备的驱动代码基本一致。kernel官网PCI设备开发教程
  进行读写测试的核心代码如下:

        if (bar32 != NULL) {
            printk("bar status: %d %d", bar_baseaddress, bar_length);
            printk("write %x to %p", bar32_rc, bar32);
            for (i = 0; i < 8; i+=4) {
                iowrite32(bar32_rc, (u32*)bar32 + i);
            }
            printk("try read from mmio");
            for (i = 0; i < 8; i++) {
                bar32_rc = ioread32((u32*)bar32 + i);
                printk("read %p value: %08x ", (u32*)bar32 + i, bar32_rc);
            }
            printk("\n");
            printk("test 32 wrrd pass, then test 64 wrrd\n");
        }
        else {
            printk("cannot map bar");
        }

工程文件

  完整工程于同名公众号回复PCIE4C_PC获取。文章来源地址https://www.toymoban.com/news/detail-844477.html

到了这里,关于【PCIE】基于PCIE4C的数据传输(一)——PC访问FPGA的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java基于物联网的医疗数据采集传输系统(ssm)

    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考 选题背景: 随着科技的不断进步,物联网(Internet of Things, IoT)技术已经渗透到医疗健康领域,成为推动现代医疗服务发展的重要力量。传统的医疗数据采集方式多依赖于手工记录和定期体检,这种方

    2024年03月15日
    浏览(43)
  • Debezium系列之:基于debezium将mysql数据库数据更改流式传输到 Elasticsearch和PostgreSQL数据库

    基于 Debezium 的端到端数据流用例,将数据流式传输到 Elasticsearch 服务器,以利用其出色的功能对我们的数据进行全文搜索。 同时把数据流式传输到 PostgreSQL 数据库,通过 SQL 查询语言来优化对数据的访问。 下面的图表显示了数据如何流经我们的分布式系统。首先,Debezium M

    2024年02月13日
    浏览(62)
  • 基于区块链/Hyperledger Fabric与IPFS的电子病历数据传输系统搭建流程

    购买专栏前请认真阅读:《Fabric项目学习笔记》专栏介绍 从0开始的搭建视频请看介绍内的QQ群获取 原项目链接:https://github.com/the-chain/airmedfoundation-terminal 本项目链接 https://gitee.com/real__cool/data_transfer 项目视频演示 https://www.bilibili.com/video/BV1f34y1v7hM 可以同时参考原项目的搭建

    2023年04月10日
    浏览(49)
  • python 基于http方式与基于redis方式传输摄像头图片数据的实现和对比

    0. 需求 在不同进程或者不同语言间传递摄像头图片数据,比如从java实现的代码中获取摄像头画面数据,将其传递给python实现的算法代码中进行处理。这里,提供基于http方式和基于redis方式这两种方式进行实现,并比较两者传输速度。 作为样例,代码均采用python实现,运行环

    2024年02月09日
    浏览(40)
  • 基于区块链/Hyperledger Fabric与IPFS的电子病历数据传输系统搭建流程与视频

    购买专栏前请认真阅读:《Fabric项目学习笔记》专栏介绍 从0开始的搭建视频请看介绍内的QQ群获取 原项目链接:https://github.com/the-chain/airmedfoundation-terminal 本项目链接 https://gitee.com/real__cool/data_transfer 项目视频演示 https://www.bilibili.com/video/BV1f34y1v7hM 可以同时参考原项目的搭建

    2023年04月20日
    浏览(41)
  • 基于Hyperledger Fabric1.4和IPFS的情报数据安全传输系统

    点击 “生成” 按钮即可产生新的身份(密钥对),数据传输必要条件。     保存密钥对,我们称其为UserA。 继续相同步骤,新建UserB。  点击 “选择文件” 即可上传文件,或将文件拖拽至上传区域。 选择文件加密后,界面变化。  填写发送者的私钥和接收者的公钥。 上传

    2024年02月15日
    浏览(42)
  • QT基于TCP协议实现数据传输以及波形绘制——安卓APP及Windows程序双版本

    文章代码有非常非常之详细的解析!!!诸位可放心食用 这个玩意我做了两个,一个是安卓app,一个是Windows程序。代码并非全部都是由我从无到有实现,只是实现了我想要的功能。多亏了巨人的肩膀,开源万岁!!! 我把程序放到GitHub上,需要的可自取。 安卓app:   mai

    2024年02月15日
    浏览(49)
  • ssm/php/node/python基于物联网的医疗数据采集传输系统

    本系统 (程序+源码) 带文档lw万字以上    文末可领取本课题的JAVA源码参考 选题背景: 随着物联网技术的飞速发展,其在医疗领域的应用也日益广泛。物联网技术通过将传感器、智能设备与网络连接起来,实现了数据的实时采集、传输和处理,极大地丰富了医疗服务的手

    2024年02月19日
    浏览(36)
  • 5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

    1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。 QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界

    2024年02月11日
    浏览(62)
  • 如何用JAVA实现一款高可用的TCP数据传输服务器——【基于netty4.x】

    震惊!这可能是我与底层最接近的一次编程体验 首先netty是一款高性能、封装性良好且灵活、基于NIO(真·非阻塞IO)的开源框架。可以用来手写web服务器、TCP服务器等,支持的协议丰富,如:常用的HTTP/HTTPS/WEBSOCKET,并且提供的大量的方法,十分灵活,可以根据自己的需求量身

    2024年01月19日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包