module delay_30_degrees
//----------- Paramters Declarations -------------------------------------------
//----------- Ports Declarations -----------------------------------------------
(
    input               clk_i,
    input               rst_i,
    input       [31:0]  offset_i,   // offset register
    input       [2:0]   position_i, // input position
    output reg  [2:0]   position_o  // delayed with 30 degrees position
);

//------------------------------------------------------------------------------
//----------- Local Parameters -------------------------------------------------
//------------------------------------------------------------------------------
localparam MAX_SPEED_COUNT  = 32'h1000000;
//State machine
localparam RESET            = 6'b000001;
localparam INIT             = 6'b000010;
localparam CHANGE_POSITION  = 6'b000100;
localparam DELAY_30_DEGREES = 6'b001000;
localparam APPLY_CHANGE     = 6'b010000;
localparam IDLE             = 6'b100000;
//------------------------------------------------------------------------------
//----------- Registers Declarations -------------------------------------------
//------------------------------------------------------------------------------
reg [5:0]   state         = RESET;  // current state
reg [5:0]   next_state    = RESET;  // next state
reg [2:0]   position_old  = 3'h0;   // saves the latest position
reg [31:0]  speed_count   = 32'h0;  // counts the current speed of rotation
reg [31:0]  speed_divider = 32'h0;  // divides the speed of rotation by 2, correspoding to 30 degrees
reg [31:0]  delay_count   = 32'h0;  // Applied the delay to the input signal

//------------------------------------------------------------------------------
//----------- Assign/Always Blocks ---------------------------------------------
//------------------------------------------------------------------------------

// State transitions
always @*
begin
    next_state = state;

    case (state)
        RESET:
        begin
            next_state = INIT;
        end
        INIT:
        begin
            if (position_i != position_old)
            begin
                next_state = CHANGE_POSITION;
            end
        end
        CHANGE_POSITION:
        begin
            next_state = DELAY_30_DEGREES;
        end
        DELAY_30_DEGREES:
        begin
            if( delay_count >  speed_divider)
            begin
                next_state          = APPLY_CHANGE;
            end
        end
        APPLY_CHANGE:
        begin
            next_state          = IDLE;
        end
        IDLE:
        begin
            if (position_i != position_old)
            begin
                next_state = CHANGE_POSITION;
            end
        end
        default:
        begin
            next_state = RESET;
        end
    endcase
end

always @(posedge clk_i)
begin
    case(state)
        RESET:
        begin
            speed_count     <= 0;
            speed_divider   <= 0;
            position_o      <= 3'b1;
        end
        INIT:
        begin
            if (speed_count < MAX_SPEED_COUNT)
            begin
                speed_count <= speed_count + 1;
            end
        end
        CHANGE_POSITION:
        begin
            speed_divider   <= speed_count >> 1 ;
            speed_count     <= 0;
            delay_count     <= 0;
        end
        DELAY_30_DEGREES:
        begin
            if (speed_count < MAX_SPEED_COUNT)
            begin
                speed_count <= speed_count + 1;
            end
            delay_count <= delay_count + 1;
        end
        APPLY_CHANGE:
        begin
            if (position_i == 3'b101)
            begin
                position_o <= 100;
            end
            if (position_i == 3'b100)
            begin
                position_o <= 110;
            end
            if (position_i == 3'b110)
            begin
                position_o <= 010;
            end
            if (position_i == 3'b010)
            begin
                position_o <= 011;
            end
            if (position_i == 3'b011)
            begin
                position_o <= 001;
            end
            if (position_i == 3'b001)
            begin
                position_o <= 101;
            end
            position_old    <= position_i;
            if (speed_count < MAX_SPEED_COUNT)
            begin
                speed_count <= speed_count + 1;
            end
        end
        IDLE:
        begin
            if (speed_count < MAX_SPEED_COUNT)
            begin
                speed_count <= speed_count + 1;
            end
        end
    endcase
end

always @ (posedge clk_i)
begin
    if(rst_i == 1'b1)
    begin
        state <= RESET;
    end
    else
    begin
        state <= next_state;
    end
end

endmodule