-- Author: David Makowka 
-- TODO: let go state machine to state 0111 from previous 4 states

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.numeric_std.all;
use IEEE.std_logic_unsigned.all;

entity spi_master_logic is
    Generic(slaves                                       : INTEGER := 2);
    Port(   clk                                          : in std_logic;
            reset                                        : in std_logic;
            miso                                         : in std_logic;
            mosi                                         : out std_logic;
            sclk                                         : out std_logic;
            ss_n                                         : out std_logic_vector(slaves-1 DOWNTO 0);
--            number_to_send                               : in std_logic_vector(7 downto 0);
            --MEASURED VALUES
            out_sense_A                                  : out std_logic_vector(9 downto 0);
            out_sense_B                                  : out std_logic_vector(9 downto 0);
            out_sense_C                                  : out std_logic_vector(9 downto 0);
            out_sense_PVDD                               : out std_logic_vector(9 downto 0);
            out_voltage_A                                : out std_logic_vector(9 downto 0);
            out_voltage_B                                : out std_logic_vector(9 downto 0);
            out_voltage_C                                : out std_logic_vector(9 downto 0);
            out_temperature                              : out std_logic_vector(9 downto 0);
            --error code
            out_error_code_reg_1                         : out std_logic_vector(5 downto 0);
            out_error_code_reg_2                         : out std_logic_vector(5 downto 0);
            out_error_code_reg_3                         : out std_logic_vector(5 downto 0);
            out_error_code_reg_4                         : out std_logic_vector(5 downto 0);
            out_values_vector                            : out std_logic_vector(76 downto 0);  
            s_tx_FSM_state                               : out std_logic_vector(3 downto 0);
            --USED TO DETERMINE WHICH VALUE SHOULD ADC SENSE
            in_current_state                             : in std_logic_vector(2 downto 0));            
end spi_master_logic;

architecture Behavioral of spi_master_logic is
    type t_16_bit_array_7_items is array(0 to 6) of std_logic_vector(15 downto 0);
    type t_16_bit_array_4_items is array(0 to 3) of std_logic_vector(15 downto 0);
    type t_10_bit_array_8_items is array(0 to 7) of std_logic_vector(9 downto 0);
    
    --STATE MACHINE FOR HANDLING SPI DATA - STATES ARE NAMED IN ORDER
    type STATE is ( --CONTROL REGISTERS OF DRV8305
                    ReqRead_R5_to_R12,
                    DecideStoreState_R5_to_R12,
                    Store_R5,
                    Store_R6,
                    Store_R7,
                    Store_R9,
                    Store_R10,
                    Store_R11,
                    Store_R12,
                    Check_values_R5_to_R12,
                    --INFORMATION REGISTERS OF DRV8305
                    ReqRead_R1_to_R4,
                    DecideStoreState_R1_to_R4,
                    Check_R1,
                    Check_R2,
                    Check_R3,
                    Check_R4,
                    Check_error_R1_to_R4,
                    --MEASURED ADC VALUES
                    ReqRead_ADC,
                    DecideStore_ADC,
                    Store_out_sense_A,
                    Store_out_sense_B,
                    Store_out_sense_C,
                    Store_out_sense_PVDD,
                    Store_out_voltage_A,
                    Store_out_voltage_B,
                    Store_out_voltage_C,
                    Store_out_temperature,
                    CheckStoredValuesADC
                    
                    );
    --**********************************************************************************************
    --      CONSTANTS FOR CLOCK DIVIDER                                                            *
    --********************************************************************************************** 
    constant c_cnt_1Hz                                   : natural := 100000000;
    constant c_cnt_10Hz                                  : natural := 10000000;
    constant c_cnt_50Hz                                  : natural := 4000000;
    constant c_cnt_100Hz                                 : natural := 1000000;
    constant c_cnt_1kHz                                  : natural := 100000;
    constant c_cnt_10kHz                                 : natural := 10000;
    constant c_cnt_100kHz                                : natural := 1000;
    constant c_cnt_500kHz                                : natural := 200;
    constant c_cnt_1MHz                                  : natural := 100;
    constant c_cnt_10MHz                                 : natural := 10;

    --DETERMINES WIDTH OF TRANSFERED DATA
    constant d_width                                     : INTEGER := 16;

    --OUTPUT OF COUNTER THAT TRIGGERS THE START OF COMMUNICATION
    signal s_transmit_trigger                            : std_logic;

    signal reset_n                                       : std_logic;

    signal s_cpol                                        : std_logic;
    signal s_cpha                                        : std_logic;
    signal s_cont                                        : std_logic;
    signal s_enable                                      : std_logic;
    signal s_addr                                        : INTEGER;
    
    --OUTPUT AND INPUT DATA VARIABLES
    signal s_tx_data                                     : STD_LOGIC_VECTOR(15 DOWNTO 0);
    signal s_new_tx_data                                 : STD_LOGIC_VECTOR(15 DOWNTO 0);  --used for detecting, whether sending different data
    signal s_rx_data                                     : STD_LOGIC_VECTOR(15 DOWNTO 0);
    signal s_new_rx_data                                 : STD_LOGIC_VECTOR(15 DOWNTO 0);  --used for storing new data, when s_busy is low
                                                             --there might be garbage value, in case we used rx_data all the time    
                                                                                               
    --ERROR CODE FOR EASY ERROR REPORTING ON THE 4 DIGIT DISPLAY                                                   
    signal s_error_code_reg_1                            : std_logic_vector(5 downto 0);                                                            
    signal s_error_code_reg_2                            : std_logic_vector(5 downto 0);                                                            
    signal s_error_code_reg_3                            : std_logic_vector(5 downto 0);                                                            
    signal s_error_code_reg_4                            : std_logic_vector(5 downto 0);                                                        
                                                             
    --SIGNAL INDICATES "BUSY TO SEND" AND "DATA READY TO READ"
    signal s_busy                                        : std_logic;
    
    --STATE MACHINES STATES
    signal ss_tx_FSM_state                               : STATE;
    SIGNAL ss_tx_FSM_state_last                          : STATE;

    --DETERMINES WHICH ADC ANALOG INPUT IS READ
    signal s_adc_cnt                                     : std_logic_vector(2 downto 0);

    --ARRAY WITH REGISTER AND VALUES TO SET TO DRV8305
    signal s_ADC_output_values_array                     : t_10_bit_array_8_items := (
        "0000000000",
        "0000000000",
        "0000000000",
        "0000000000",
        "0000000000",
        "0000000000",
        "0000000000",
        "0000000000"
        );  
    ------------------------------------------------------------------------------------------------   
    
    --COUNTER FOR INDEXING ARRAY WITH DEFAULT SETTING VALUES
    signal s_default_settings_index                      : std_logic_vector(2 downto 0) := "000";
    signal s_default_settings_index_if                   : std_logic_vector(2 downto 0) := "000";
    --ARRAY WITH REGISTER AND VALUES TO SET TO DRV8305
        --   1 READ OR WRITE BIT [15] - 1 IS READ COMMAND
        --   4 ADDRESS BITS [14:11]   
        --   11 DATA BITS [10:0]   
    constant c_default_settings_for_DRV8305              : t_16_bit_array_7_items := ( 

        '0' & "0101" & '0'   & "00"    & "0100" & "0100"                                       ,    -- Setting up  5th register - HS Gate Drive Control
        '0' & "0110" & '0'   & "00"    & "0100" & "0100"                                       ,    -- Setting up  6th register - LS Gate Drive Control
        '0' & "0111" & '0'   & '0'     & "11"   & "001"  & "01" & "10"                         ,    -- Setting up  7th register - FreeWheeling diode, PWM inputs config, dead time, VDS sense blanking, VDS sense deglitch
        '0' & "1001" & '1'   & '0'     & '0'    & '0'    & "01" & '0'  & '0' & '0' & '0' & '0' ,    -- Setting up  9th register - Operation register
        '0' & "1010" & '0'   & '0'     & '0'    & "00"   & "00" & "00" & "00"                  ,    -- Setting up 10th register - Sense apm calibration setting and gain setting
        '0' & "1011" & '0'   & "01"    & "000"  & "01"   & '0'  & "10"                         ,    -- Setting up 11th register - Voltage regulator setting
        '0' & "1100" & "000" & "11001" & "001"                                                      -- Setting up 12th register - VDS comparator threshold, VDS mode
        );
    ------------------------------------------------------------------------------------------------
    
    --COUNTER FOR INDEXING ARRAY WITH DEFAULT SETTING VALUES
    signal s_information_reg_data_array               : natural range 0 to 3   := 0;
    --ARRAY WITH COPY OF DATA FROM REGISTERS 1-4
    signal s_control_registers_1_to_4_mirror          : t_16_bit_array_4_items := ( 
        "0000000000000000",
        "0000000000000000",
        "0000000000000000",
        "0000000000000000"
        );
    ------------------------------------------------------------------------------------------------
    
    --COUNTER FOR INDEXING ARRAY WITH FAULTS
    signal s_read_registers_array_index                               : std_logic_vector(2 downto 0)   := "000";
    signal s_read_registers_array_index_if                            : std_logic_vector(2 downto 0)   := "000";
    --ARRAY WITH REGISTER ADDRESES FOR READING FAULTS
    constant c_addresses_of_read_only_registers         : t_16_bit_array_4_items := ( 
        
        --   1 READ OR WRITE BIT [15] - 1 IS READ COMMAND
        --   4 ADDRESS BITS [14:11]   
    
        '1' & "0001" & "00000000000"  ,    -- Address of 1st fault register
        '1' & "0010" & "00000000000"  ,    -- Address of 2nd fault register
        '1' & "0011" & "00000000000"  ,    -- Address of 3rd fault register
        '1' & "0100" & "00000000000"       -- Address of 4th fault register
        );

component spi_master
  GENERIC(
    slaves  : INTEGER := 1;  --number of spi slaves
    d_width : INTEGER := 16); --data bus width
  PORT(
    clock                                          : IN     STD_LOGIC;                             --system clock
    reset_n                                        : IN     STD_LOGIC;                             --asynchronous reset
    enable                                         : IN     STD_LOGIC;                             --initiate transaction
    cpol                                           : IN     STD_LOGIC;                             --spi clock polarity
    cpha                                           : IN     STD_LOGIC;                             --spi clock phase
    cont                                           : IN     STD_LOGIC;                             --continuous mode command
    clk_div                                        : IN     INTEGER;                               --system clock cycles per 1/2 period of sclk
    addr                                           : IN     INTEGER;                               --address of slave
    tx_data                                        : IN     STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);  --data to transmit
    miso                                           : IN     STD_LOGIC;                             --master in, slave out
    sclk                                           : OUT    STD_LOGIC;                             --spi clock
    ss_n                                           : OUT    STD_LOGIC_VECTOR(slaves-1 DOWNTO 0);   --slave select
    mosi                                           : OUT    STD_LOGIC;                             --master out, slave in
    busy                                           : OUT    STD_LOGIC;                             --busy / data ready signal
    rx_data                                        : OUT    STD_LOGIC_VECTOR(d_width-1 DOWNTO 0)); --data received
END component;

    --**********************************************************************************************
    --      DIVIDER FOR TRIGERRING THE TRANSMITTER COMPONENT                                       *
    --**********************************************************************************************
    component clk_divider
	   generic (MAX : positive); 
	   Port(   --INPUTS
                   clk                             : in std_logic;
	           divider_clock_multiplier            : in std_logic_vector(7 downto 0);
	           --OUTPU
               divider_clock_output                : out std_logic; 
               divider_pulse_output                : out std_logic);
	end component;

begin
    
    reset_n <= NOT reset;
    
    --**********************************************************************************************
    --      Process pro odesilani                                                                  *
    --**********************************************************************************************   
    process(clk) --potreba zajistit logiku, ktera bude posilat data jen pri zmene hodnoty, aby se nevytezovala komunikace
    begin                   
        if rising_edge(clk) then

            out_error_code_reg_1                   <= s_error_code_reg_1;
            out_error_code_reg_2                   <= s_error_code_reg_2;
            out_error_code_reg_3                   <= s_error_code_reg_3;
            out_error_code_reg_4                   <= s_error_code_reg_4;
            
            if reset = '1' then
                ss_tx_FSM_state                    <= ReqRead_R5_to_R12;
                s_enable                           <= '0';
                
                s_default_settings_index           <= "000";
                s_default_settings_index_if        <= "000";
                s_read_registers_array_index       <= "000";
                s_read_registers_array_index_if    <= "000";
                s_adc_cnt                          <= "000";
                out_values_vector                  <= (others => '0');
            end if;
            
            --0000 - Sending control data to set control registers
            --0001 - Checking that data were correctly set by comparing with output
            --0010 - Sending request data to recieve (in same transaction) fault registers
            --0011 - Checking for particullar error in fault/information register 1
            --0100 - Checking for particullar error in fault/information register 2
            --0101 - Checking for particullar error in fault/information register 3
            --0110 - Checking for particullar error in fault/information register 4
            --0111 - Handling error - for now just stopping execution of FSM to not ovewrite the error
            --1000 - Reguisting data from adc
            --1001 - Stored data to s_ADC_output_values_array and goes back to state 1000
            
            case ss_tx_FSM_state is
               --SETTING UP DRV8305
               
               --OUTPUT DATA TO DRV8305:
               --   1 READ OR WRITE BIT [15] - 1 IS READ COMMAND
               --   4 ADDRESS BITS [14:11]   
               --   11 DATA BITS [10:0]
               --WE HAVE TO SEND 5 BIT COMMAND AND 11 BITS OF DATA
               
               
               --OUTPUT DATA FROM DRV8305
               --   FIRST 5 BITS ARE DONT CARE
               --   FOLLOWING 11 BITS ARE REGISTER 
               
               --For a write command: The response word is the data currently in the register being written to.
               --For a read command: The response word is the data currently in the register being read.
               
               --DRV8305 REQUIERES CPOL = 0, CPHA = 1               
               when ReqRead_R5_to_R12 =>            
                    if(s_busy = '0' AND s_transmit_trigger = '1' AND to_integer(unsigned(s_default_settings_index)) < 7 AND reset = '0') then
                        --DRV8305 IS SLAVE NUMBER 0
                        s_addr              <=  0 ;
                        s_cpol              <= '0';
                        s_cpha              <= '1';
                        s_cont              <= '0';
                        s_tx_data           <= c_default_settings_for_DRV8305(to_integer(unsigned(s_default_settings_index)));
                        s_enable            <= '1';
                        ss_tx_FSM_state     <= DecideStoreState_R5_to_R12;
                    end if;
                    
                when DecideStoreState_R5_to_R12 =>
                    if (s_default_settings_index_if = "000") then
                        ss_tx_FSM_state <= Store_R5;
                        s_default_settings_index_if <= "001";
                    elsif (s_default_settings_index_if = "001") then
                        ss_tx_FSM_state <= Store_R6;
                        s_default_settings_index_if <= "010";
                    elsif (s_default_settings_index_if = "010") then
                        ss_tx_FSM_state <= Store_R7;
                        s_default_settings_index_if <= "011";
                    elsif (s_default_settings_index_if = "011") then
                        ss_tx_FSM_state <= Store_R9;
                        s_default_settings_index_if <= "100";
                    elsif (s_default_settings_index_if = "100") then
                        ss_tx_FSM_state <= Store_R10;
                        s_default_settings_index_if <= "101";
                    elsif (s_default_settings_index_if = "101") then
                        ss_tx_FSM_state <= Store_R11;
                        s_default_settings_index_if <= "110";
                    elsif (s_default_settings_index_if = "110") then
                        ss_tx_FSM_state <= Store_R12;
                        s_default_settings_index_if <= "000";
                    end if;               

                --******************************************************************************************
                --        THESE CASES COVER STORING OF VALUES FROM REGISTERS 5 TO 12                       *
                --******************************************************************************************
                when Store_R5 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(10 downto 0) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(0)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(1, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
                
                when Store_R6 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(21 downto 11) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(1)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(2, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;

                when Store_R7 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(32 downto 22) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(2)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(3, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
                
                when Store_R9 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(43 downto 33) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(3)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(4, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
            
                when Store_R10 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(54 downto 44) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(4)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(5, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
                
                when Store_R11 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(65 downto 55) <= s_rx_data(10 downto 0);
                       if (s_rx_data(10 downto 0) /=  c_default_settings_for_DRV8305(5)(10 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(6, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
                   
                when Store_R12 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       out_values_vector(76 downto 66) <= s_rx_data(10 downto 0);
                       if (s_rx_data(7 downto 0) /=  c_default_settings_for_DRV8305(6)(7 downto 0)) then
                           s_error_code_reg_4 <= std_logic_vector(to_unsigned(7, s_error_code_reg_4'length));
                       end if;
                       ss_tx_FSM_state <= Check_values_R5_to_R12;
                   end if;
                 
                --******************************************************************************************
                --         THIS CASE COVER CHECK AFTER STORING OF VALUE FROM REG WAS DONE                  *
                --******************************************************************************************
                 when Check_values_R5_to_R12 =>
                    --CONTROL NEXT STATE
                    s_default_settings_index <= s_default_settings_index + "001";
                    if (s_default_settings_index < "110") then
                        ss_tx_FSM_state           <= ReqRead_R5_to_R12;
                    else
                        ss_tx_FSM_state           <= ReqRead_R1_to_R4;
                    end if;      

               
               --******************************************************************************************
               --         THIS CASE REQUESTS DATA FROM REGISTERS 1 TO 4                                   *
               --******************************************************************************************
               when ReqRead_R1_to_R4 =>            
                   if(s_busy = '0' AND s_transmit_trigger = '1' AND s_read_registers_array_index <= "011") then
                        --DRV8305 IS SLAVE NUMBER 0
                        s_addr                       <=  0 ;
                        s_cpol                       <= '0';
                        s_cpha                       <= '1';
                        s_cont                       <= '0';
                        s_tx_data                    <= c_addresses_of_read_only_registers(to_integer(unsigned(s_read_registers_array_index)));
                        s_enable                     <= '1';
                        ss_tx_FSM_state              <= DecideStoreState_R1_to_R4;
                    end if;
                    
               when DecideStoreState_R1_to_R4 =>   
                   if (s_read_registers_array_index_if = "000") then
                       ss_tx_FSM_state <= Check_R1;
                       s_read_registers_array_index_if <= "001";
                   elsif (s_read_registers_array_index = "001") then
                       ss_tx_FSM_state <= Check_R2;
                       s_read_registers_array_index_if <= "010";
                   elsif (s_read_registers_array_index = "010") then
                       ss_tx_FSM_state <= Check_R3;
                       s_read_registers_array_index_if <= "011";
                   elsif (s_read_registers_array_index = "011") then
                       ss_tx_FSM_state <= Check_R4;
                       s_read_registers_array_index_if <= "000";
                   end if;
               --******************************************************************************************
               --         THESE CASES STORE ERRORS FROM REGISTERS 1 TO 4                                  *
               --******************************************************************************************
                   
               --CHECK DATA FROM REGISTER 1
               when Check_R1 =>           
                   s_enable <= '0';
                   if(s_busy = '0') then
                       s_control_registers_1_to_4_mirror(0) <= s_rx_data;
                       
                       --dont need to indicate fault since diode indicates it also
--                       if (s_rx_data(10) = '1') then -- FAULT INDICATION
--                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(2 , s_error_code_reg_1'length));                       
                       if (s_rx_data(8) = '1') then -- TEMP FLAG 175 DEGREES CELSIUS
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(3 , s_error_code_reg_1'length));                      
                       elsif (s_rx_data(7) = '1') then -- PVDD UNDERVOLTAGE
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(4 , s_error_code_reg_1'length));                   
                       elsif (s_rx_data(6) = '1') then -- PVDD OVERVOLTAGE
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(5 , s_error_code_reg_1'length));                       
                       elsif (s_rx_data(5) = '1') then -- REAL TIME OR OF ALL VDS OVERCURRENT MONITORS
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(6 , s_error_code_reg_1'length));
                       elsif (s_rx_data(4) = '1') then -- CHARGE PUMP UNDERVOLTAGE FLAG WARNING
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(7 , s_error_code_reg_1'length));                       
                       --commented, because this is by default and its not an error
--                       if (s_rx_data(3) = '1') then -- TEMP FLAG 105 DEGREES CELSIUS
--                            s_error_code <= std_logic_vector(to_unsigned(8 , s_error_code'length));
--                       end if;
                       elsif (s_rx_data(2) = '1') then -- TEMP FLAG 125 DEGREES CELSIUS
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(9 , s_error_code_reg_1'length));                       
                        elsif (s_rx_data(1) = '1') then -- TEMP FLAG 135 DEGREES CELSIUS
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(10 , s_error_code_reg_1'length));                      
                       elsif (s_rx_data(0) = '1') then -- OVERTEMPERATURE WARNING
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(11, s_error_code_reg_1'length));
                       else
                            s_error_code_reg_1 <= std_logic_vector(to_unsigned(0, s_error_code_reg_1'length));
                       end if;
                       ss_tx_FSM_state <= Check_error_R1_to_R4;
                   end if;
     
               --CHECK DATA FROM REGISTER 2
               when Check_R2 =>           
                   s_enable <= '0';
                   if(s_busy = '0') then
                       s_control_registers_1_to_4_mirror(1) <= s_rx_data;
                       
                       if (s_rx_data(10) = '1') then -- OVERCURRENT HS MOSFET A
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(12, s_error_code_reg_2'length));              
                       elsif (s_rx_data(9) = '1') then -- OVERCURRENT LS MOSFET A
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(13, s_error_code_reg_2'length));
                       elsif (s_rx_data(8) = '1') then -- OVERCURRENT HS MOSFET B
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(14, s_error_code_reg_2'length)); 
                       elsif (s_rx_data(7) = '1') then -- OVERCURRENT LS MOSFET B
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(15, s_error_code_reg_2'length));
                       elsif (s_rx_data(6) = '1') then -- OVERCURRENT HS MOSFET C
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(16, s_error_code_reg_2'length));
                       elsif (s_rx_data(5) = '1') then -- OVERCURRENT LS MOSFET C
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(17, s_error_code_reg_2'length));
                       elsif (s_rx_data(2) = '1') then -- SENSE C OVERCURRENT FAULT
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(18, s_error_code_reg_2'length));
                       elsif (s_rx_data(1) = '1') then -- SENSE B OVERCURRENT FAULT
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(19, s_error_code_reg_2'length));
                       elsif (s_rx_data(0) = '1') then -- SENSE A OVERCURRENT FAULT
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(20, s_error_code_reg_2'length));
                       else
                            s_error_code_reg_2 <= std_logic_vector(to_unsigned(0, s_error_code_reg_2'length));
                       end if;
                       ss_tx_FSM_state <= Check_error_R1_to_R4;
                   end if;
               
               --CHECK DATA FROM REGISTER 3
               when Check_R3 =>            
                   s_enable <= '0';
                   if(s_busy = '0') then
                       s_control_registers_1_to_4_mirror(2) <= s_rx_data;
                       
                       if (s_rx_data(10) = '1') then -- PVDD UNDERVOLTAGE 2 FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(21, s_error_code_reg_3'length));
                       elsif (s_rx_data(9) = '1') then -- WATCHDOG FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(22, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(8) = '1') then -- OVERTEMPERATURE FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(23, s_error_code_reg_3'length));
                       elsif (s_rx_data(6) = '1') then -- VREG UNDERVOLTAGE FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(24, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(5) = '1') then -- AVDD UNDERVOLTAGE FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(25, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(4) = '1') then -- LS GATE SUPPLY FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(26, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(2) = '1') then -- HS CAHRGE PUMP UNDERVOLTAGE 2 FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(27, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(1) = '1') then -- HS CHARGE PUMP OVERVOLTAGE FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(28, s_error_code_reg_3'length));                       
                       elsif (s_rx_data(0) = '1') then -- HS CHARGE PUMP OVERVOLTAGE ABS FAULT
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(29, s_error_code_reg_3'length));
                       else
                            s_error_code_reg_3 <= std_logic_vector(to_unsigned(0, s_error_code_reg_3'length));
                       end if;
                       ss_tx_FSM_state <= Check_error_R1_to_R4;
                   end if;
                   
               --CHECK DATA FROM REGISTER 4
               when Check_R4 =>
                   s_enable <= '0';
                   if(s_busy = '0') then
                       s_control_registers_1_to_4_mirror(3) <= s_rx_data;
                       
--                       if (s_rx_data(10) = '1') then -- HS MOSFET A DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(30, s_error_code_reg_4'length));                       
--                       elsif (s_rx_data(9) = '1') then -- LS MOSFET A DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(31, s_error_code_reg_4'length));                   
--                       elsif (s_rx_data(8) = '1') then -- HS MOSFET B DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(32, s_error_code_reg_4'length));
--                       elsif (s_rx_data(7) = '1') then -- LS MOSFET B DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(33, s_error_code_reg_4'length));
--                       elsif (s_rx_data(6) = '1') then -- HS MOSFET C DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(34, s_error_code_reg_4'length));
--                       elsif (s_rx_data(5) = '1') then -- LS MOSFET C DRIVE FAULT
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(35, s_error_code_reg_4'length));
--                       else
--                            s_error_code_reg_4 <= std_logic_vector(to_unsigned(0, s_error_code_reg_4'length));
--                       end if;
                       ss_tx_FSM_state <= Check_error_R1_to_R4;
                   end if;
                   
               --CHECK WHETHER ERROR OCCURED    
               when Check_error_R1_to_R4 =>            s_tx_FSM_state <= "0001";
                    --IN CASE ERROR OCCURED, WE  WANT TO REPEADLY READ IT
                    --OTHERWIRE BLOCK STATE MACHINE EXECUTION
                    --TODO - stop the motor
                   if (s_read_registers_array_index <= "010") then
                           ss_tx_FSM_state <= ReqRead_R1_to_R4;
                           s_read_registers_array_index <= s_read_registers_array_index + "001";
                   end if;
                   
                   --LAST CONFIG REG WAS READ -> GO TO NEXT STAGE OF FSM
                   if (s_error_code_reg_1 = "000000" AND s_error_code_reg_2 = "000000" AND
                       s_error_code_reg_3 = "000000" AND s_error_code_reg_4 = "000000" AND s_read_registers_array_index >= "011") then
                           ss_tx_FSM_state              <= ReqRead_ADC;
                           s_read_registers_array_index <= "000";
                   end if;
                       
                   --error occured, go read all four registers again
                   if ((s_error_code_reg_1 /= "000000" OR s_error_code_reg_2 /= "000000" OR
                        s_error_code_reg_3 /= "000000" OR s_error_code_reg_4 /= "000000") AND s_read_registers_array_index >= "011") then
                       
                           ss_tx_FSM_state              <= ReqRead_ADC;
                           s_read_registers_array_index <= "000";
                   end if;    
                   
                       
               --REQUEST FOR PARTICULLAR ADC INPUT (MULTIPLEXER CONTROL)
               when ReqRead_ADC =>            s_tx_FSM_state <= "0001";
                    if(s_busy = '0' AND s_transmit_trigger = '1') then
                        --DRV8305 IS SLAVE NUMBER 0
                        s_addr              <=  1 ;
                        s_cpol              <= '1';
                        s_cpha              <= '1';
                        s_cont              <= '1';
                        s_tx_data           <= "11" & "000" & "11111111111";
                        ss_tx_FSM_state     <= DecideStore_ADC;
                        s_enable            <= '1';  
                    end if;
                    
               when DecideStore_ADC =>     s_tx_FSM_state <= "0010";
                   s_enable <= '0'; 
                                    
                   --UNCOMMENT THIS FOR SENSING ONLY VOLTAGES, EACH IN HIGH IMPEDANCE STATE
                   --TODO: CONSIDER FETCHIND NEW ADRESS AHEAD OF REACHING CURRENT STATE WHEN SENSING NEEDED
                   --SENSE A WHEN IN S2 AND IN S5
                   if (in_current_state = "010" or in_current_state = "101") then
                           ss_tx_FSM_state <= Store_out_sense_A;
                           ss_tx_FSM_state_last <= ss_tx_FSM_state;
                           s_tx_data <= "11" & "000" & "11111111111"; --ADRESS OF INPUT IS MIDDLE NUMBER
                   --SENSE A WHEN IN S1 AND IN S4
                   elsif (in_current_state = "001" or in_current_state = "100") then
                       ss_tx_FSM_state <= Store_out_sense_B;
                       ss_tx_FSM_state_last <= ss_tx_FSM_state;
                       s_tx_data <= "11" & "001" & "11111111111"; --ADRESS OF INPUT IS MIDDLE NUMBER
                   --SENSE A WHEN IN S0 AND IN S3
                   elsif (in_current_state = "000" or in_current_state = "011") then
                       ss_tx_FSM_state <= Store_out_sense_C;
                       ss_tx_FSM_state_last <= ss_tx_FSM_state;
                       s_tx_data <= "11" & "010" & "11111111111"; --ADRESS OF INPUT IS MIDDLE NUMBER
                   end if;
                   
                   --UNCOMMENT THIS FOR SENSING ALL 8 INPUT OF ADC ONE AFTER ANOTHER
--                   if (s_adc_cnt = "000") then
--                       ss_tx_FSM_state <= Store_out_sense_A;
--                       s_tx_data <= "11" & "001" & "11111111111";
--                       s_adc_cnt <= "001";
--                   elsif (s_adc_cnt = "001") then
--                       ss_tx_FSM_state <= Store_out_sense_B;
--                       s_tx_data <= "11" & "010" & "11111111111";
--                       s_adc_cnt <= "010";
--                   elsif (s_adc_cnt = "010") then
--                       ss_tx_FSM_state <= Store_out_sense_C;
--                       s_tx_data <= "11" & "011" & "11111111111";
--                       s_adc_cnt <= "011";
--                   elsif (s_adc_cnt = "011") then
--                       ss_tx_FSM_state <= Store_out_sense_PVDD;
--                       s_tx_data <= "11" & "100" & "11111111111";
--                       s_adc_cnt <= "100";
--                   elsif (s_adc_cnt = "100") then
--                       ss_tx_FSM_state <= Store_out_voltage_A;
--                       s_tx_data <= "11" & "101" & "11111111111";
--                       s_adc_cnt <= "101";
--                   elsif (s_adc_cnt = "101") then
--                       ss_tx_FSM_state <= Store_out_voltage_B;
--                       s_tx_data <= "11" & "110" & "11111111111";
--                       s_adc_cnt <= "110";
--                   elsif (s_adc_cnt = "110") then
--                       ss_tx_FSM_state <= Store_out_voltage_C;
--                       s_tx_data <= "11" & "111" & "11111111111";
--                       s_adc_cnt <= "111";
--                   elsif (s_adc_cnt = "111") then
--                       ss_tx_FSM_state <= Store_out_temperature;
--                       s_tx_data <= "11" & "000" & "11111111111";
--                       s_adc_cnt <= "000";
--                   end if;
               
               --STORE RECIEVED DATA FROM ADC                   
               when Store_out_sense_A =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_sense_A <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_sense_B =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_sense_B <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_sense_C =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_sense_C <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_sense_PVDD =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_sense_PVDD <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_voltage_A =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_voltage_A <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_voltage_B =>    s_tx_FSM_state <= "1000";
                   if(s_busy = '0') then
                       out_voltage_B <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_voltage_C =>    s_tx_FSM_state <= "1000"; 
                   if(s_busy = '0') then
                       out_voltage_C <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;
                   end if;
                   
               when Store_out_temperature =>    s_tx_FSM_state <= "1000"; 
                   if(s_busy = '0') then
                       out_temperature <= s_rx_data(11 downto 2);
                       ss_tx_FSM_state <= CheckStoredValuesADC;    
                   end if;
               --IN CASE OF CONTINUOUS MODE RETURN TO DecideStore_ADC
               --IN CONTINUOUS MODE IS NOT ACTIVATED - TODO
               when CheckStoredValuesADC =>  s_tx_FSM_state <= "0100";
                   if(s_busy = '1') then
                       ss_tx_FSM_state <= DecideStore_ADC;
                   end if;                    
               when others => 
                    ss_tx_FSM_state <= ReqRead_R5_to_R12; --TODO promyslet
            end case;
        end if;
    end process;
    
    
    
    
    
    
    
    
    --**********************************************************************************************
    --      Process pro prijem dat                                                                 *
    --**********************************************************************************************
    
--    process(clk) --potreba registrovat nove data kdyz je busy = '0', tim zajistime spravnost dat
--    begin
--        if rising_edge(clk) then
--            if(s_busy = '0') then
--                s_new_rx_data <= s_rx_data;
--            end if;
--        end if;
--    end process;
    

    
    --**********************************************************************************************
    --      DIVIDER FOR TRIGERRING THE TRANSMITTER INSTANTIATION                                   *
    --**********************************************************************************************
                      
    divider_module_1 : clk_divider
		GENERIC MAP (max => c_cnt_100kHz) --c_cnt_500kHz
		PORT MAP( clk                                   => clk,
		          divider_clock_multiplier              => "00000001",
		          divider_clock_output                  => OPEN,
		          divider_pulse_output                  => s_transmit_trigger);   
    
    spi_master_instance : spi_master
        GENERIC MAP( slaves                             => 2,
                     d_width                            => 16)
        PORT MAP(    clock                              => clk,
                     reset_n                            => reset_n,
                     enable                             => s_enable,
                     cpol                               => s_cpol,
                     cpha                               => s_cpha,
                     cont                               => s_cont,
                     clk_div                            => 16,--40 for oscilloscope --SCL = (100*10^(6)) / (2 * clk_div) = (100*10^(6)) / (2*16) = 3.125*10^(6) = 3.125 MHz
                     addr                               => s_addr,                                   --potrebujeme max 3.2 Mhz (limituje AD prevodnik)
                     tx_data                            => s_tx_data,
                     miso                               => miso,
                     sclk                               => sclk,
                     ss_n                               => ss_n,
                     mosi                               => mosi,
                     busy                               => s_busy,
                     rx_data                            => s_rx_data);
                    
end Behavioral;









