module fix_msg_decoder (
    input  wire       clk,
    input  wire       rst,
    input  wire [7:0] data_in,
    output reg        valid,
    output reg [7:0]  msg_type,
    output reg [63:0] sender_id,
    output reg [31:0] msg_seq_num
);
    localparam [7:0] SOH = 8'h01;
    localparam [7:0] EQUALS = 8'h3D;

    reg        in_tag;
    reg [15:0] current_tag;
    reg [7:0]  msg_type_accum;
    reg [63:0] sender_id_accum;
    reg [31:0] msg_seq_num_accum;
    reg [3:0]  sender_count;
    reg [3:0]  value_index;

    always @(posedge clk) begin
        if (rst) begin
            valid <= 1'b0;
            msg_type <= 8'b0;
            sender_id <= 64'b0;
            msg_seq_num <= 32'b0;

            in_tag <= 1'b1;
            current_tag <= 16'b0;
            msg_type_accum <= 8'b0;
            sender_id_accum <= 64'b0;
            msg_seq_num_accum <= 32'b0;
            sender_count <= 4'b0;
            value_index <= 4'b0;
        end else begin
            valid <= 1'b0;

            if (data_in == SOH) begin
                if (!in_tag && (current_tag == 16'd10)) begin
                    msg_type <= msg_type_accum;
                    sender_id <= sender_id_accum;
                    msg_seq_num <= msg_seq_num_accum;
                    valid <= 1'b1;

                    in_tag <= 1'b1;
                    current_tag <= 16'b0;
                    msg_type_accum <= 8'b0;
                    sender_id_accum <= 64'b0;
                    msg_seq_num_accum <= 32'b0;
                    sender_count <= 4'b0;
                    value_index <= 4'b0;
                end else begin
                    in_tag <= 1'b1;
                    current_tag <= 16'b0;
                    sender_count <= 4'b0;
                    value_index <= 4'b0;
                end
            end else begin
                if (in_tag) begin
                    if (data_in == EQUALS) begin
                        in_tag <= 1'b0;
                        value_index <= 4'b0;

                        if (current_tag == 16'd49) begin
                            sender_id_accum <= 64'b0;
                            sender_count <= 4'b0;
                        end else if (current_tag == 16'd34) begin
                            msg_seq_num_accum <= 32'b0;
                        end
                    end else begin
                        current_tag <= (current_tag * 16'd10) + (data_in - 8'h30);
                    end
                end else begin
                    case (current_tag)
                        16'd35: begin
                            if (value_index == 4'd0)
                                msg_type_accum <= data_in;
                        end

                        16'd49: begin
                            if (sender_count < 4'd8) begin
                                case (sender_count)
                                    4'd0: sender_id_accum[63:56] <= data_in;
                                    4'd1: sender_id_accum[55:48] <= data_in;
                                    4'd2: sender_id_accum[47:40] <= data_in;
                                    4'd3: sender_id_accum[39:32] <= data_in;
                                    4'd4: sender_id_accum[31:24] <= data_in;
                                    4'd5: sender_id_accum[23:16] <= data_in;
                                    4'd6: sender_id_accum[15:8] <= data_in;
                                    4'd7: sender_id_accum[7:0] <= data_in;
                                endcase
                                sender_count <= sender_count + 4'd1;
                            end
                        end

                        16'd34: begin
                            if ((data_in >= 8'h30) && (data_in <= 8'h39))
                                msg_seq_num_accum <= (msg_seq_num_accum * 32'd10) + (data_in - 8'h30);
                        end
                    endcase

                    value_index <= value_index + 4'd1;
                end
            end
        end
    end
endmodule
