module data_receive(
    clk         ,  //100M
    rst_n       ,

    ip_sour     ,  //上位机IP地址
    ip_self     ,  //自身IP地址
    mac_sour    ,  //上位机MAC地址
    mac_self    ,  //自身MAC地址
    data        ,

    ff_rx_valid ,
    ff_rx_data  ,
    ff_rx_sop   ,
    ff_rx_eop   ,
    ff_rx_err   ,
 
    cmd_arq     ,  //返回配置信息命令
    cmd_start   ,  //开始采集命令
    cmd_stop       //停止采集命令
    );

    //参数定义
    parameter               DATA_W   =         8;
    parameter                 IDLE   =         0;
    parameter             ETH_HEAD   =         1;
    parameter              IP_HEAD   =         2;
    parameter             UDP_HEAD   =         3;
    parameter             VLD_DATA   =         4;

    //输入信号定义
    input                           clk         ;
    input                           rst_n       ;
    input                           ff_rx_valid ;
    input                           ff_rx_sop   ;
    input                           ff_rx_eop   ;
    input [ 8-1:0]                  ff_rx_data  ;
    input [ 6-1:0]                  ff_rx_err   ;
    input [32-1:0]                  ip_self     ;
    input [48-1:0]                  mac_self    ;

    //输出信号定义
    output                          cmd_arq     ;
    output                          cmd_start   ;
    output                          cmd_stop    ;
    output[32-1:0]                  ip_sour     ;
    output[48-1:0]                  mac_sour    ;
    output[ 8-1:0]                  data        ;

    //输出信号reg定义
    reg                             cmd_arq     ;
    reg                             cmd_start   ;
    reg                             cmd_stop    ;
    reg   [48-1:0]                  mac_sour    ;
    reg   [32-1:0]                  ip_sour     ;

    //中间信号定义
    reg [ 4-1:0]                    state_c     ;
    reg [ 4-1:0]                    state_n     ;
    reg [ 8-1:0]                    cnt_data    ;
    reg [ 4-1:0]                    x           ;
    reg [48-1:0]                    mac_dest    ;
    reg [32-1:0]                    ip_dest     ;
    reg [ 8-1:0]                    data        ;
    //reg [16-1:0]                    udp_len     ;
    //reg [16-1:0]                    port_sour   ;
    //reg [16-1:0]                    port_dest   ;

    wire                            add_cnt_data  ;
    wire                            end_cnt_data  ;
    wire                            idle2eth_head ;
    wire                            eth_head2ip_head ;
    wire                            ip_head2udp_head ;
    wire                            udp_head2vld_data;
    wire                            vld_data2idle ;
    wire                            eth_err       ;
    wire                            ip_err        ;

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            data <= 0;
        end
        else if(ff_rx_valid) begin
            data <= ff_rx_data;
        end
        else begin
            data <= 0;
        end
    end

    /*always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= IDLE;
        end
        else begin
            state_c <= state_n;
        end
    end

    always@(*)begin
        case(state_c)
            IDLE:begin
                if(idle2eth_head)begin
                    state_n = ETH_HEAD;
                end
                else begin
                    state_n = state_c;
                end
            end
            ETH_HEAD:begin
                if(eth_head2ip_head)begin
                    state_n = IP_HEAD;
                end
                else if(eth_err)begin
                    state_n = IDLE;
                end
                else begin
                    state_n = state_c;
                end
            end
            IP_HEAD:begin
                if(ip_head2udp_head)begin
                    state_n = UDP_HEAD;
                end
                else if(ip_err)begin
                    state_n = IDLE;
                end
                else begin
                    state_n = state_c;
                end
            end
            UDP_HEAD:begin
                if(udp_head2vld_data)begin
                    state_n = VLD_DATA;
                end
                else begin
                    state_n = state_c;
                end
            end
            VLD_DATA:begin
                if(vld_data2idle)begin
                    state_n = IDLE;
                end
                else begin
                    state_n = state_c;
                end
            end
            default:begin
                state_n = IDLE;
            end
        endcase
    end
    //第三段：设计转移条件
    assign idle2eth_head = state_c==IDLE && (ff_rx_valid==1'b1) && (ff_rx_sop==1'b1);
    assign eth_head2ip_head = state_c==ETH_HEAD && (ff_rx_valid==1'b1) && end_cnt_data && (mac_dest==48'hff_ff_ff_ff_ff_ff || mac_dest==mac_self);
    assign ip_head2udp_head = state_c==IP_HEAD && (ff_rx_valid==1'b1) && end_cnt_data && (ip_dest==32'hff_ff_ff_ff || ip_dest== ip_self);
    assign udp_head2vld_data = state_c==UDP_HEAD && (ff_rx_valid==1'b1) && end_cnt_data;
    assign vld_data2idle = state_c==VLD_DATA && (ff_rx_valid==1'b1) && (ff_rx_eop==1'b1);
    
    assign eth_err = state_c==ETH_HEAD && cnt_data==1 && (mac_dest!=48'hff_ff_ff_ff_ff_ff && mac_dest!=mac_self);
    assign ip_err  = state_c==IP_HEAD && cnt_data==3 && (ip_dest!=32'hff_ff_ff_ff && ip_dest!= ip_self);

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_data <= 0;
        end
        else if(add_cnt_data)begin
            if(end_cnt_data)
                cnt_data <= 0;
            else
                cnt_data <= cnt_data + 1'b1;
        end
    end

    assign add_cnt_data = state_c==ETH_HEAD || state_c==IP_HEAD || state_c==UDP_HEAD;       
    assign end_cnt_data = add_cnt_data && (cnt_data== x - 1 || ff_rx_eop==1'b1);

    always  @(*)begin
        case(state_c)
            ETH_HEAD:begin
                x = 4;
            end
            IP_HEAD:begin
                x = 5;
            end
            UDP_HEAD:begin
                x = 2;
            end
            default:begin
                x = 0;
            end
        endcase
    end

    //解析目的MAC地址 与底层MAC地址比较 采用32bit对齐模式，帧头加了2字节数据
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            mac_dest <= 0;  //初始化
        end
        else if(state_c==ETH_HEAD && cnt_data==0)begin
            mac_dest[48-1:32] <= ff_rx_data;
        end
        else if(state_c==ETH_HEAD && cnt_data==1)begin
            mac_dest[32-1:0] <= ff_rx_data;
        end
    end

    //解析源MAC地址 供发送时使用
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            mac_sour <= 0;
        end
        else if(state_c==ETH_HEAD && cnt_data==2)begin
            mac_sour[48-1:16] <= ff_rx_data; 
        end
        else if(state_c==ETH_HEAD && cnt_data==3)begin
            mac_sour[16-1:0] <= ff_rx_data;
        end
    end

    //解析源IP地址 供发送时使用
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            ip_sour <= 0;
        end
        else if(state_c==IP_HEAD && cnt_data==3)begin
            ip_sour <= ff_rx_data;
        end
    end

    //解析目的IP地址 与底层IP比较
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            ip_dest <= 0;
        end
        else if(state_c==IP_HEAD && cnt_data==3)begin
            ip_dest <= ff_rx_data;
        end
    end*/

    //解析UDP首部
   /* always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            port_sour <= 0;
        end
        else if(state_c==UDP_HEAD && cnt_data==0)begin
            port_sour <= ff_rx_data[32-1:16];
        end
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            port_dest <= 0;
        end
        else if(state_c==UDP_HEAD && cnt_data==0)begin
            port_dest <= ff_rx_data[16-1:0];
        end
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            udp_len <= 0;
        end
        else if(state_c==UDP_HEAD && cnt_data==1)begin
            udp_len <= ff_rx_data[32-1:16];
        end
    end*/

    /*always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cmd_arq <= 1'b0;
        end
        else if(state_c==VLD_DATA && cnt_data==0 && ff_rx_data[32-1:16]==16'hf0_12)begin
            cmd_arq <= 1'b1;
        end
        else begin
            cmd_arq <= 1'b0;
        end
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cmd_start <= 1'b0;
        end
        else if(state_c==VLD_DATA && cnt_data==0 && ff_rx_data[32-1:16]==16'h80_8f)begin
            cmd_start <= 1'b1;
        end
        else begin
            cmd_start <= 1'b0;
        end
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cmd_stop <= 1'b0;
        end
        else if(state_c==VLD_DATA && cnt_data==0 && ff_rx_data[32-1:16]==16'h00_8f)begin
            cmd_stop <= 1'b1;
        end
        else begin
            cmd_stop <= 1'b0;
        end
    end*/

endmodule
