`timescale 1ns / 1ps

module radar_receiver_final (
    input wire clk,           // 100MHz    
	 input wire reset_n,
    
	// ADC Physical Interface (LVDS Inputs)
    input wire [7:0] adc_d_p,        // ADC Data P (LVDS)
    input wire [7:0] adc_d_n,        // ADC Data N (LVDS)
    input wire adc_dco_p,            // Data Clock Output P (400MHz LVDS)
    input wire adc_dco_n,            // Data Clock Output N (400MHz LVDS)
	 output wire adc_pwdn,
    
    output reg [31:0] doppler_output,
    output reg doppler_valid,
    output reg [4:0] doppler_bin,
    output reg [5:0] range_bin
);

// ========== INTERNAL SIGNALS ==========
wire use_long_chirp;
wire [5:0] chirp_counter;
wire chirp_start;
wire azimuth_change;
wire elevation_change;

wire [1:0] segment_request;
wire mem_request;
wire [15:0] ref_i, ref_q;
wire mem_ready;

wire [15:0] adc_i_scaled, adc_q_scaled;
wire adc_valid_sync;

// Reference signals for the processing chain
wire [15:0] long_chirp_real, long_chirp_imag;
wire [15:0] short_chirp_real, short_chirp_imag;

// ========== DOPPLER PROCESSING SIGNALS ==========
wire [31:0] range_data_32bit;
wire range_data_valid;
wire new_chirp_frame;

// Doppler processor outputs
wire [31:0] doppler_spectrum;
wire doppler_spectrum_valid;
wire [4:0] doppler_bin_out;
wire [5:0] doppler_range_bin_out;
wire doppler_processing;
wire doppler_frame_done;

// ========== RANGE BIN DECIMATOR SIGNALS ==========
wire signed [15:0] decimated_range_i;
wire signed [15:0] decimated_range_q;
wire decimated_range_valid;
wire [5:0] decimated_range_bin;

// ========== MODULE INSTANTIATIONS ==========
reg clk_400m;

lvds_to_cmos_400m clk_400m_inst(
    // ADC Physical Interface (LVDS Inputs)
    .clk_400m_p(adc_dco_p),            // Data Clock Output P (400MHz LVDS, 2.5V)
    .clk_400m_n(adc_dco_n),            // Data Clock Output N (400MHz LVDS, 2.5V)
    .reset_n(reset_n),              // Active-low reset
    
    // CMOS Output Interface (400MHz Domain)
    .clk_400m_cmos(clk_400m)         // ADC data clock (CMOS, 3.3V)
);

// 1. ADC + CDC + AGC

// CMOS Output Interface (400MHz Domain)
wire [7:0] adc_data_cmos;  // 8-bit ADC data (CMOS)
wire adc_dco_cmos;         // ADC data clock (CMOS, 400MHz)
wire adc_valid;            // Data valid signal

wire [7:0] cdc_data_cmos;  // 8-bit ADC data (CMOS)
wire cdc_valid;            // Data valid signal


ad9484_lvds_to_cmos_400m adc (
	.adc_d_p(adc_d_p),
	.adc_d_n(adc_d_n),
	.adc_dco_p(adc_dco_p),
	.adc_dco_n(adc_dco_n),
	.reset_n(reset_n),
	.adc_data_cmos(adc_data_cmos),
	.adc_dco_cmos(adc_dco_cmos),
	.adc_valid(adc_valid),
	.adc_pwdn(adc_pwdn)
);

cdc_adc_to_processing #(
    .WIDTH(8),
    .STAGES(3)
)cdc(
    .src_clk(adc_dco_cmos),
    .dst_clk(clk_400m),
    .reset_n(reset_n),
    .src_data(adc_data_cmos),
    .src_valid(adc_valid),
    .dst_data(cdc_data_cmos),
    .dst_valid(cdc_valid)
);

// 2. DDC Input Interface
wire signed [17:0] ddc_out_i;
wire signed [17:0] ddc_out_q;

wire ddc_valid_i;
wire ddc_valid_q;

ddc_400m_enhanced ddc(
    .clk_400m(clk_400m),           // 400MHz clock from ADC DCO
    .clk_100m(clk),           // 100MHz system clock //used by the 2 FIR
    .reset_n(reset_n),
    .adc_data(cdc_data_cmos),     // ADC data at 400MHz (unsigned 0-255)
    .adc_data_valid_i(cdc_valid),     // Valid at 400MHz
    .adc_data_valid_q(cdc_valid),     // Valid at 400MHz
    .baseband_i(ddc_out_i), // I output at 100MHz
    .baseband_q(ddc_out_q), // Q output at 100MHz  
    .baseband_valid_i(ddc_valid_i),     // Valid at 100MHz
	 .baseband_valid_q(ddc_valid_q),
	 .mixers_enable(1'b1),
    .bypass_mode(1'b1)
);

ddc_input_interface ddc_if (
    .clk(clk),
    .reset_n(reset_n),
    .ddc_i(ddc_out_i),
    .ddc_q(ddc_out_q),
    .valid_i(ddc_valid_i),
    .valid_q(ddc_valid_q),
    .adc_i(adc_i_scaled),
    .adc_q(adc_q_scaled),
    .adc_valid(adc_valid_sync),
    .data_sync_error()
);

// 3. Dual Chirp Memory Loader

chirp_memory_loader_param chirp_mem (
    .clk(clk),
    .reset_n(reset_n),
    .segment_select(segment_request),
    .mem_request(mem_request),
    .use_long_chirp(use_long_chirp),
	 .sample_addr(sample_addr_from_chain),
    .ref_i(ref_i),
    .ref_q(ref_q),
    .mem_ready(mem_ready)
);

// Sample address generator
reg [9:0] sample_addr_reg;
always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        sample_addr_reg <= 0;
    end else if (mem_request) begin
        sample_addr_reg <= sample_addr_reg + 1;
        if (sample_addr_reg == 1023) sample_addr_reg <= 0;
    end
end
assign sample_addr_wire = sample_addr_reg;

// 4. CRITICAL: Reference Chirp Latency Buffer
// This aligns reference data with FFT output (2159 cycle delay)
wire [15:0] delayed_ref_i, delayed_ref_q;
wire mem_ready_delayed;

latency_buffer_2159 #(
    .DATA_WIDTH(32),  // 16-bit I + 16-bit Q
	.LATENCY(3187)
) ref_latency_buffer (
    .clk(clk),
    .reset_n(reset_n),
    .data_in({ref_i, ref_q}),
    .valid_in(mem_request),
    .data_out({delayed_ref_i, delayed_ref_q}),
    .valid_out(mem_ready_delayed)
);

// Assign delayed reference signals
assign long_chirp_real = delayed_ref_i;
assign long_chirp_imag = delayed_ref_q;
assign short_chirp_real = delayed_ref_i;
assign short_chirp_imag = delayed_ref_q;

// 5. Dual Chirp Matched Filter
wire [9:0] sample_addr_from_chain; 

wire signed [15:0] range_profile_i;
wire signed [15:0] range_profile_q;
wire range_valid;

matched_filter_multi_segment mf_dual (
    .clk(clk),
    .reset_n(reset_n),
    .ddc_i({{2{adc_i_scaled[15]}}, adc_i_scaled}),
    .ddc_q({{2{adc_q_scaled[15]}}, adc_q_scaled}),
    .ddc_valid(adc_valid_sync),
    .use_long_chirp(use_long_chirp),
    .chirp_counter(chirp_counter),
    .mc_new_chirp(mc_new_chirp),
    .mc_new_elevation(mc_new_elevation),
    .mc_new_azimuth(mc_new_azimuth),
	 .long_chirp_real(delayed_ref_i),      // From latency buffer
    .long_chirp_imag(delayed_ref_q),
    .short_chirp_real(delayed_ref_i),     // Same for short chirp
    .short_chirp_imag(delayed_ref_q),
    .segment_request(segment_request),
    .mem_request(mem_request),
	 .sample_addr_out(sample_addr_from_chain),
    .ref_i(16'd0),          // Direct ref to multi_seg
    .ref_q(16'd0),
    .mem_ready(mem_ready),
    .pc_i_w(range_profile_i),
    .pc_q_w(range_profile_q),
    .pc_valid_w(range_valid)
);

// ========== CRITICAL: RANGE BIN DECIMATOR ==========
// Convert 1024 range bins to 64 bins for Doppler
range_bin_decimator #(
    .INPUT_BINS(1024),
    .OUTPUT_BINS(64),
    .DECIMATION_FACTOR(16)
) range_decim (
    .clk(clk),
    .reset_n(reset_n),
    .range_i_in(range_profile_i),
    .range_q_in(range_profile_q),
    .range_valid_in(range_valid),
    .range_i_out(decimated_range_i),
    .range_q_out(decimated_range_q),
    .range_valid_out(decimated_range_valid),
    .range_bin_index(decimated_range_bin),
    .decimation_mode(2'b01),           // Peak detection mode
    .start_bin(10'd0)
);

// ========== FRAME SYNC USING chirp_counter ==========
reg [5:0] chirp_counter_prev;
reg new_frame_pulse;

always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        chirp_counter_prev <= 6'd0;
        new_frame_pulse <= 1'b0;
    end else begin
        // Default: no pulse
        new_frame_pulse <= 1'b0;
        
        // ===== CHOOSE ONE FRAME DETECTION METHOD =====
        
        // METHOD A: Detect frame start at chirp_counter = 0
        // (Assumes frames are 64 chirps: 0-63)
        //if (chirp_counter == 6'd0 && chirp_counter_prev != 6'd0) begin
        //    new_frame_pulse <= 1'b1;
        //end
        
        // METHOD B: Detect frame start at chirp_counter = 0 AND 32
        // (For 32-chirp frames in a 64-chirp sequence)
         if ((chirp_counter == 6'd0 || chirp_counter == 6'd32) && 
             (chirp_counter_prev != chirp_counter)) begin
             new_frame_pulse <= 1'b1;
         end
        
        // METHOD C: Programmable frame start
        // localparam FRAME_START_CHIRP = 6'd0;  // Set based on your sequence
        // if (chirp_counter == FRAME_START_CHIRP && 
        //     chirp_counter_prev != FRAME_START_CHIRP) begin
        //     new_frame_pulse <= 1'b1;
        // end
        
        // Store previous value
        chirp_counter_prev <= chirp_counter;
    end
end

assign new_chirp_frame = new_frame_pulse;

// ========== DATA PACKING FOR DOPPLER ==========
assign range_data_32bit = {decimated_range_q, decimated_range_i};
assign range_data_valid = decimated_range_valid;

// ========== DOPPLER PROCESSOR ==========
doppler_processor_optimized #(
    .DOPPLER_FFT_SIZE(32),
    .RANGE_BINS(64),
    .CHIRPS_PER_FRAME(32)  // MUST MATCH YOUR ACTUAL FRAME SIZE!
) doppler_proc (
    .clk(clk),
    .reset_n(reset_n),
    .range_data(range_data_32bit),
    .data_valid(range_data_valid),
    .new_chirp_frame(new_chirp_frame),
    
    // Outputs
    .doppler_output(doppler_output),
    .doppler_valid(doppler_valid),
    .doppler_bin(doppler_bin),
    .range_bin(doppler_range_bin_out),
    
    // Status
    .processing_active(doppler_processing),
    .frame_complete(doppler_frame_done),
    .status()
);

// ========== OUTPUT CONNECTIONS ==========
assign doppler_range_bin = doppler_range_bin_out;
assign doppler_processing_active = doppler_processing;
assign doppler_frame_complete = doppler_frame_done;

// ========== STATUS ==========

// ========== DEBUG AND VERIFICATION ==========
reg [31:0] frame_counter;
reg [5:0] chirps_in_current_frame;

always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        frame_counter <= 0;
        chirps_in_current_frame <= 0;
    end else begin
        // Count chirps in current frame
        if (range_data_valid && decimated_range_bin == 0) begin
            // First range bin of a chirp
            chirps_in_current_frame <= chirps_in_current_frame + 1;
        end
        
        // Detect frame completion
        if (new_chirp_frame) begin
            frame_counter <= frame_counter + 1;
            $display("[TOP] Frame %0d started. Previous frame had %0d chirps", 
                     frame_counter, chirps_in_current_frame);
            chirps_in_current_frame <= 0;
        end
        
        // Monitor chirp counter pattern
        if (chirp_counter != chirp_counter_prev) begin
            $display("[TOP] chirp_counter: %0d ? %0d", 
                     chirp_counter_prev, chirp_counter);
        end
    end
end



endmodule