module top_uart_ultrasonic (
    input wire clk,
    input wire rst_p,
    input wire start,        // Démarrage de la mesure
    inout wire sig,          // Signal vers le capteur ultrason
    output wire uart_tx      // TX vers le PC
);
    wire [15:0] distance;
    wire [2:0] state;
    
    reg [7:0] tx_data_in;
    reg tx_data_valid;
    wire tx_data_ready;
    wire fifo_empty;
    wire fifo_full;

    wire uart_ready;
    reg uart_start;
    reg [7:0] uart_data;

    reg [1:0] send_state;
    localparam IDLE = 2'd0,
               SEND_HIGH = 2'd1,
               SEND_LOW = 2'd2,
               WAIT_UART = 2'd3;
    
    // Instanciation du module ultrason
    ultrasonic_fpga #(
        .CLK_FREQ(27_000_000)
    ) ultrasonic_inst (
        .clk(clk),
        .start(start),
        .sig(sig),
        .distance(distance),
        .state(state)
    );

    // Instanciation de la FIFO
    tx_fifo #(
        .WIDTH(8),
        .DEPTH(16)
    ) fifo_inst (
        .clk(clk),
        .rst_p(rst_p),
        .tx_data_in(tx_data_in),
        .tx_data_valid(tx_data_valid),
        .tx_data_ready(tx_data_ready),
        .fifo_empty(fifo_empty),
        .fifo_full(fifo_full)
    );

    // Instanciation de l'UART
    uart_tx uart_inst (
        .clk(clk),
        .rst(rst_p),
        .tx_start(uart_start),
        .tx_data(uart_data),
        .tx(uart_tx),
        .tx_ready(uart_ready)
    );

    reg [15:0] distance_reg;
    reg new_distance;

    // Détecte un nouveau résultat de distance
    always @(posedge clk or posedge rst_p) begin
        if (rst_p) begin
            distance_reg <= 16'd0;
            new_distance <= 1'b0;
        end else begin
            if (state == 3'd6 && distance != distance_reg) begin  // Quand l'ultrason est à DONE
                distance_reg <= distance;
                new_distance <= 1'b1;
            end else begin
                new_distance <= 1'b0;
            end
        end
    end

    // Envoi dans la FIFO (distance sur 2 octets : high byte + low byte)
    always @(posedge clk or posedge rst_p) begin
        if (rst_p) begin
            tx_data_in <= 8'd0;
            tx_data_valid <= 1'b0;
            send_state <= IDLE;
        end else begin
            case (send_state)
                IDLE: begin
                    tx_data_valid <= 1'b0;
                    if (new_distance && !fifo_full) begin
                        tx_data_in <= distance_reg[15:8];  // MSB en premier
                        tx_data_valid <= 1'b1;
                        send_state <= SEND_LOW;
                    end
                end

                SEND_LOW: begin
                    tx_data_valid <= 1'b0;
                    if (tx_data_ready && !fifo_full) begin
                        tx_data_in <= distance_reg[7:0];   // LSB ensuite
                        tx_data_valid <= 1'b1;
                        send_state <= WAIT_UART;
                    end
                end

                WAIT_UART: begin
                    tx_data_valid <= 1'b0;
                    send_state <= IDLE;
                end

                default: send_state <= IDLE;
            endcase
        end
    end

    // Gestion FIFO -> UART
    always @(posedge clk or posedge rst_p) begin
        if (rst_p) begin
            uart_start <= 1'b0;
            uart_data <= 8'd0;
        end else begin
            uart_start <= 1'b0; // Par défaut

            if (uart_ready && !fifo_empty) begin
                uart_data <= fifo_inst.fifo_mem[fifo_inst.rd_ptr]; // Lecture de la FIFO
                uart_start <= 1'b1;
                fifo_inst.rd_ptr <= fifo_inst.rd_ptr + 1;
                fifo_inst.fifo_count <= fifo_inst.fifo_count - 1;
            end
        end
    end

endmodule
