module ultrasonic_fpga #(
    parameter integer CLK_FREQ = 27_000_000  // Fréquence d'horloge en Hz
)(
    input  wire clk,
    input  wire start,
    inout  wire sig,             // Broche bidirectionnelle vers le capteur
    output reg [15:0] distance,  // Distance mesurée en cm
    output reg [2:0] state
);
    reg [15:0] trig_counter = 0;
    reg [31:0] echo_counter = 0;
    reg [31:0] echo_div_counter = 0;
    reg [15:0] distance_counter = 0;

    reg sig_out;
    reg sig_dir;                  // 1: output, 0: input

    assign sig = sig_dir ? sig_out : 1'bz; // bz pour dire que le fpga laisse le fils libre et n'oblige pas de valeur

    reg sig_int, sig_ok;

    localparam IDLE         = 3'd0,
               TRIG_HIGH    = 3'd1,
               TRIG_LOW     = 3'd2,
               WAIT_ECHO    = 3'd3,
               MEASURE_ECHO = 3'd4,
               COMPUTE      = 3'd5,
               DONE         = 3'd6,
               WAIT_NEXT    = 3'd7;

    localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse
    localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm
    localparam integer MAX_CM = 350;
    localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000;
    
    localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms

    reg [31:0] wait_counter;

    always @(posedge clk) begin
        sig_int <= sig;
        sig_ok  <= sig_int;
    end

    always @(posedge clk) begin // FSM
        
        case (state)
            IDLE: begin
                sig_out <= 0;
                sig_dir <= 0;
                distance <= 0;
                if (start) begin
                    state <= TRIG_HIGH;
                    trig_counter <= 0;
                end
            end

            TRIG_HIGH: begin
                sig_out <= 1;
                sig_dir <= 1;
                if (trig_counter < TRIG_PULSE_CYCLES) begin
                    trig_counter <= trig_counter + 1;
                end else begin
                    trig_counter <= 0;
                    state <= TRIG_LOW;
                end
            end

            TRIG_LOW: begin
                sig_out <= 0;
                sig_dir <= 0; // Mettre en entrée

                if (sig_ok) begin
                    state <= TRIG_LOW;
                end else
                    state <= WAIT_ECHO;
            end

            WAIT_ECHO: begin
                if (sig_ok) begin
                    echo_counter <= 0;
                    state <= MEASURE_ECHO;
                end else if (echo_counter >= TIMEOUT_CYCLES) begin
                    distance <= 0; 
                    state <= DONE;
                end else begin
                    echo_counter <= echo_counter + 1;
                end
            end

            MEASURE_ECHO: begin
                if (sig_ok) begin
                    if (echo_counter < TIMEOUT_CYCLES) begin
                        echo_counter <= echo_counter + 1;
                    end else begin 
                        state <= DONE;
                    end

                end else begin 
                    state <= COMPUTE;
                end
            end

            COMPUTE: begin
                if (echo_counter >= DIST_DIVISOR) begin
                    echo_counter <= echo_counter - DIST_DIVISOR;
                    distance_counter <= distance_counter + 1;
                    state <= COMPUTE;
                end else begin
                    distance <= distance_counter;
                    state <= DONE;
                end
            end

            DONE: begin
                if (start) begin
                    wait_counter <= 0;
                    state <= WAIT_NEXT;
                end else begin
                    state <= IDLE;
                end
            
            end

            WAIT_NEXT: begin
                wait_counter <= wait_counter + 1;
                if (wait_counter >= WAIT_NEXT_CYCLES) begin
                    state <= TRIG_HIGH;
                    trig_counter <= 0;
                    distance_counter <= 0;
                    echo_counter <= 0;
                end
            end

            default: begin
                state <= IDLE; // Reset to IDLE state in case of an error
            end
        endcase
    
    end

endmodule