`timescale 1ns / 1ps

module TB();

    // ==========================================
    // Parameters & Signal Definitions
    // ==========================================
    parameter CLK_PERIOD = 20;     // 50MHz
    parameter BAUD       = 115200; 
    localparam BIT_TIME  = 1_000_000_000 / BAUD;

    reg  clk;
    reg  rst_n;
    reg  uart_rx; // DUT RX
    wire uart_tx; // DUT TX
    reg sig_in;

    // Clock Generation
    initial clk = 0;
    always #(CLK_PERIOD/2) clk = ~clk;
    // initial begin
    //     $fsdbDumpfile("wave.fsdb");
    //     $fsdbDumpvars();
    // end
    // ==========================================
    // DUT Instantiation
    // ==========================================
    digital_top u_digital_top(
        .clk     (clk),
        .rst_n   (rst_n),
        .uart_rx (uart_rx),
        .uart_tx (uart_tx),
        .sig_in (sig_in)
    );


    // // ==========================================
    // // TX Driver: Read from case.txt
    // // ==========================================
    // initial begin
    //     int file_h;
    //     int status;
    //     logic [63:0] val;
        
    //     // Initialize signals
    //     rst_n = 0;
    //     uart_rx = 1;
    //     #(CLK_PERIOD * 10);
    //     rst_n = 1;
    //     file_h = $fopen("case.txt", "r");
    //     if (!file_h) begin
    //         $display("[TX ERROR] Cannot open case.txt");
    //         $finish;
    //     end

    //     $display("[TX] Starting transmission...");

    //     while (!$feof(file_h)) begin
    //         // Read hex data per line
    //         status = $fscanf(file_h, "%h\n", val);
    //         if (status == 1) begin
    //             if (val > 64'hFFFF_FFFF) begin
    //                 $display("[%t] TX CMD: %h", $time, val);
    //                 send_data(val, 64);
    //             end else begin
    //                 $display("[%t] TX DATA: %h", $time, val[31:0]);
    //                 send_data(val[31:0], 32);
    //             end
    //             #(BIT_TIME * 5); // Frame gap
    //         }
    //     end
        
    //     $fclose(file_h);
    //     $display("[TX] All cases sent.");
        
    //     // Wait for RX return data
    //     #(BIT_TIME * 500);
    //     $display("[SIM] Simulation finished.");
    //     $finish;
    // end

   

    // ==========================================
    // RX Monitor: Save to rx_data.txt
    // ==========================================
    int rx_file_h;
    initial begin
    
        logic [7:0] rx_byte;
        
        rx_file_h = $fopen("rx_data.txt", "w");
        if (!rx_file_h) begin
            $display("[RX ERROR] Cannot create rx_data.txt");
            $finish;
        end

        forever begin
            logic [31:0] packet_word;  // 32-bit data packet
            logic [7:0] rx_byte;
            // Collect 4 bytes to form 32-bit data
            for (int byte_idx = 0; byte_idx < 4; byte_idx++) begin
                // 1. Wait for start bit (falling edge)
                @(negedge uart_tx);
                // 2. Skip start bit, sample at center point
                #(BIT_TIME / 2);
                #(BIT_TIME);
                // Read 8 data bits
                for (int i = 0; i < 8; i++) begin
                    rx_byte[i] = uart_tx;
                    #(BIT_TIME);
                end
                // Combine to 32-bit (little-endian)
                packet_word[24 - 8*byte_idx +: 8] = rx_byte;
              //  $display("[%t] Byte %0d: 0x%h", $time, byte_idx, rx_byte);
                // Wait for end of stop bit
                if (byte_idx < 3) begin
                    #(BIT_TIME / 2);
                end
            end
            
            // Write to file (one 32-bit data per line)
            $fdisplay(rx_file_h, "%08h", packet_word);
            $display("[%0t] Packet (32-bit): 0x%08h", $time, packet_word);
            // Wait for end of last stop bit
            #(BIT_TIME / 2);
        end
    end

    final begin
        if (rx_file_h) begin
            $fclose(rx_file_h);
            $display("[RX] File closed at %t",$time);
        end
    end

    // --- Pulse Generation Task ---
    // freq_khz: Target frequency (kHz)
    // duration_ms: Test duration (ms)
    task automatic gen_pulses(input int freq_khz, input int duration_ms);
        int half_period_ns;
        longint end_time_ns;
        begin
            if (freq_khz <= 0) begin
                sig_in = 0;
                #(duration_ms * 1000000);
            end else begin
                half_period_ns = 500000 / freq_khz;
                end_time_ns = $time + (longint'(duration_ms) * 1000000);
                
                $display("[%0t] Start generating signal: %0d kHz", $time, freq_khz);
                while ($time < end_time_ns) begin
                    sig_in = 1;
                    #(half_period_ns);
                    sig_in = 0;
                    #(half_period_ns);
                end
            end
        end
    endtask

    // ==========================================
    // Task: Send one byte (Serial TX)
    // ==========================================
    task automatic send_byte(input [7:0] data);
        begin
            uart_rx = 0; // Start bit
            #(BIT_TIME);
            for (int i = 0; i < 8; i++) begin
                uart_rx = data[i]; // LSB First
                #(BIT_TIME);
            end
            uart_rx = 1; // Stop bit
            #(BIT_TIME);
        end
    endtask

    // Task: Send 32/64 bit data
    task automatic send_data(input [63:0] data, input int len_bits);
        int bytes = len_bits / 8;
        for (int i = bytes - 1; i >= 0; i--) begin  // Send from highest byte
            send_byte(data[i*8 +: 8]); 
        end
    endtask

     initial begin
        // 1. Initialization
        rst_n = 0; uart_rx = 1; sig_in = 0;
        #(CLK_PERIOD * 20);
        rst_n = 1;
        #(CLK_PERIOD * 100);
        $display("------- Step 1: read Thermometer Regs -------");
        send_data(64'h80000004_00000004,64);  
        send_data(64'h80000008_00000004,64); //mode[25:24] + win  
        send_data(64'h8000000c_00000004,64); //calibration H / L
        send_data(64'h80000010_00000004,64); //rep[31] +rep_gap[23:0]
        send_data(64'h80000014_00000004,64); //result [23:0]


        $display("------- Step 2: Running Concurrent Tasks -------");
        fork
            // Process A: Generate input pulses (simulate temperature change)
            begin
                gen_pulses(200, 10); // 100kHz for 10ms
                gen_pulses(300, 20);
                gen_pulses(400, 30);
            end

            // Process B: Insert read command during reporting
            begin
                #(6ms); // Wait for first report packet
                send_data(64'h80000014_00000004,64); $display("[%0t] == Sending Read Request ==", $time);
                send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); $display("[%0t] == open report_en==",$time);
                send_data(64'h0000008_00000004,64);send_data(32'h0100_03e8,32); $display("[%0t] == mode = 1 ==",$time);
                #15ms;
                send_data(64'h00000010_00000004,64);send_data(32'h0000_06e8,32);$display("[%0t] == cloese report_en==",$time);

                //send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); $display("[%0t] == open report_en==",$time);
                //send_data(64'h00000010_00000004,64);send_data(32'h0000_06e8,32);$display("[%0t] == cloese report_en==",$time);
                #30000;
                send_data(64'h80000014_00000004,64);
            end
        join

        #(BIT_TIME * 500);
        $display("Test Done.");
        $finish;
    end

endmodule