---------------------------------------------------------------------------------------------------
--
-- Title       : Ultran Power Control State Machine
-- Design      : PowerControlSim
-- Author      : Jason Morgan
-- Company     : VPN Solutions Ltd
--
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
--
-- Description :  Controls the status of the internal supplies of the ultran HVPA board
--
---------------------------------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity UltranPowerSm is 
	port (
		Clock: in STD_LOGIC;						  --State machine clock no need for speed
		nHT_I_OOT: in STD_LOGIC;					  --Input from amplifier to indicate HT current overload
		nHT_IS_EN: in STD_LOGIC;					  --Input from amplifier to indicate HT is enabled
		nHT_V_OOT: in STD_LOGIC;					  --Input from amplifier to indicate HT voltage OOT
		nPowerOOT: in STD_LOGIC;					  --Input from amplifier to indicate internal supplier OOT
		Req_HT_ON: in STD_LOGIC;					  --Connect to register bit to turn on HT
		Req_P_ON: in STD_LOGIC;						  --Connect to register bit to turn on amplifier supplies
		nReset: in STD_LOGIC;						  --Reset for state machine
		Fault: out STD_LOGIC_VECTOR (3 downto 0);	  --Indication of fault code - connect to register
		Interrupt: out STD_LOGIC;					  --Interrupt request during serious fault codes
		nHT_ON: out STD_LOGIC;						  --Logic output to amplifier that turns on HT
		nPowerON: out STD_LOGIC);					  --Logic output to amplifier that turns on supplies
end UltranPowerSm;

architecture power_sm_arch of UltranPowerSm is

-- diagram DECLARATION
type FaultCodes is (OK,STARTUP,TOO_SOON,POWER_FAIL,BAD_EXT_POWER,BAD_INT_POWER,HT_POWER_FAIL,HT_I_OOT,HT_V_OOT,BAD_HT_I,BAD_HT_V);

-- diagram signals declarations
signal DelayCount: STD_LOGIC_VECTOR (3 downto 0);
signal DelayReq: STD_LOGIC;
signal FaultCode: FaultCodes;
signal IntCount: STD_LOGIC_VECTOR (3 downto 0);
signal IntReq: STD_LOGIC;

-- SYMBOLIC ENCODED state machine: DelayGenSM
type DelayGenSM_type is (
    Reset_State, Idle, Delay_State
);
-- attribute enum_encoding of DelayGenSM_type: type is ... -- enum_encoding attribute is not supported for symbolic encoding

signal DelayGenSM: DelayGenSM_type;

-- SYMBOLIC ENCODED state machine: InterruptGenSM
type InterruptGenSM_type is (
    Idle, Reset_State, Int_State
);
-- attribute enum_encoding of InterruptGenSM_type: type is ... -- enum_encoding attribute is not supported for symbolic encoding

signal InterruptGenSM: InterruptGenSM_type;

-- SYMBOLIC ENCODED state machine: PowerControlSM
type PowerControlSM_type is (
    Reset_State, Starting, PowerOFF, BOOT, PowerON, WaitOFF, HT_ON, I_ERR, V_ERR, HT_Start, HT_FAULT
);
-- attribute enum_encoding of PowerControlSM_type: type is ... -- enum_encoding attribute is not supported for symbolic encoding

signal PowerControlSM: PowerControlSM_type;

begin

-- concurrent signals assignments

-- diagram ACTION
Fault<=std_logic_vector(conv_unsigned(FaultCodes'POS(FaultCode),4));

----------------------------------------------------------------------
-- Machine: DelayGenSM
----------------------------------------------------------------------
DelayGenSM_machine: process (Clock, nReset)
begin
	if nReset='0' then	
		DelayGenSM <= Reset_State;
		-- Set default values for outputs, signals and variables
		-- ...
	elsif Clock'event and Clock = '1' then
		-- Set default values for outputs, signals and variables
		-- ...
		case DelayGenSM is
			when Reset_State =>
				DelayGenSM <= Idle;
			when Idle =>
				DelayCount <= "0000";
				if DelayReq='1' then	
					DelayGenSM <= Delay_State;
				end if;
			when Delay_State =>
				if DelayCount="1111" then	
					DelayGenSM <= Idle;
				else
					DelayGenSM <= Delay_State;
					DelayCount <= DelayCount+1;
				end if;
			when others =>
				null;
		end case;
	end if;
end process;


----------------------------------------------------------------------
-- Machine: InterruptGenSM
----------------------------------------------------------------------
InterruptGenSM_machine: process (Clock, nReset)
begin
	if nReset='0' then	
		InterruptGenSM <= Reset_State;
		-- Set default values for outputs, signals and variables
		-- ...
	elsif Clock'event and Clock = '1' then
		-- Set default values for outputs, signals and variables
		-- ...
		case InterruptGenSM is
			when Idle =>
				IntCount <= "0000";
				Interrupt <= '0';
				if IntReq='1' then	
					InterruptGenSM <= Int_State;
				end if;
			when Reset_State =>
				InterruptGenSM <= Idle;
			when Int_State =>
				Interrupt <= '1';
				if IntCount="1111" then	
					InterruptGenSM <= Idle;
				else
					InterruptGenSM <= Int_State;
					IntCount <= IntCount+1;
				end if;
			when others =>
				null;
		end case;
	end if;
end process;


----------------------------------------------------------------------
-- Machine: PowerControlSM
----------------------------------------------------------------------
PowerControlSM_machine: process (Clock, nReset)
begin
	if nReset='0' then	
		PowerControlSM <= Reset_State;
		-- Set default values for outputs, signals and variables
		-- ...
		FaultCode <= OK;
		nPowerON <= '1';
		nHT_ON <= '1';
	elsif Clock'event and Clock = '1' then
		-- Set default values for outputs, signals and variables
		-- ...
		case PowerControlSM is
			when Reset_State =>
				FaultCode <= OK;
				nPowerON <= '1';
				nHT_ON <= '1';
				PowerControlSM <= BOOT;
			when Starting =>
				nPowerON <= '0';
				FaultCode <= STARTUP;
				if Req_P_ON='0' then	
					PowerControlSM <= BOOT;
				elsif DelayCount="1111" then	
					PowerControlSM <= PowerON;
				end if;
			when PowerOFF =>
				if Req_P_ON='1' and nPowerOOT='1' then	
					PowerControlSM <= Starting;
				elsif Req_P_ON ='1' and nPowerOOT='0' then	
					PowerControlSM <= WaitOFF;
					FaultCode <= BAD_EXT_POWER;
				elsif Req_HT_ON='1' then	
					PowerControlSM <= BOOT;
				end if;
			when BOOT =>
				nPowerON <= '1';
				nHT_ON <= '1';
				if Req_P_ON/='0' or Req_HT_ON/='0' then	
					PowerControlSM <= BOOT;
					FaultCode <= TOO_SOON;
				else
					PowerControlSM <= PowerOFF;
				end if;
			when PowerON =>
				FaultCode <= OK;
				nHT_ON <= '1';
				if Req_P_ON='0' then	
					PowerControlSM <= BOOT;
				elsif nPowerOOT='1' and Req_HT_ON='1' then	
					PowerControlSM <= HT_Start;
				elsif nPowerOOT='0' then	
					PowerControlSM <= WaitOFF;
					FaultCode <= BAD_INT_POWER;
				end if;
			when WaitOFF =>
				nPowerON <= '1';
				nHT_ON <= '1';
				if Req_P_ON='1' then	
					PowerControlSM <= WaitOFF;
				elsif Req_P_ON='0' then	
					PowerControlSM <= BOOT;
				end if;
			when HT_ON =>
				if nHT_V_OOT='0' and IntCount="0000" then	
					PowerControlSM <= V_ERR;
					FaultCode <= HT_V_OOT;
				elsif nHT_I_OOT='0' and IntCount="0000" then	
					PowerControlSM <= I_ERR;
					FaultCode <= HT_I_OOT;
				elsif Req_P_ON='0' then	
					PowerControlSM <= BOOT;
				elsif nHT_V_OOT='1' and nHT_I_OOT='1' and nPowerOOT='0' then	
					PowerControlSM <= WaitOFF;
					FaultCode <= BAD_INT_POWER;
				elsif Req_HT_ON='0' then	
					PowerControlSM <= PowerON;
				end if;
			when I_ERR =>
				if nPowerOOT='0' then	
					PowerControlSM <= WaitOFF;
					FaultCode <= BAD_HT_I;
				else
					PowerControlSM <= HT_ON;
				end if;
			when V_ERR =>
				if nPowerOOT='0' then	
					PowerControlSM <= WaitOFF;
					FaultCode <= BAD_HT_V;
				else
					PowerControlSM <= HT_ON;
				end if;
			when HT_Start =>
				nHT_ON <= '0';
				if nHT_IS_EN='1' and DelayCount="1111" then	
					PowerControlSM <= HT_FAULT;
					FaultCode <= HT_POWER_FAIL;
					nHT_ON <= '1';
				elsif nHT_IS_EN='0' and DelayCount="1111" then	
					PowerControlSM <= HT_ON;
				end if;
			when HT_FAULT =>
				if Req_HT_ON='0' then	
					PowerControlSM <= PowerON;
				end if;
			when others =>
				null;
		end case;
	end if;
end process;

-- signal assignment statements for combinatorial outputs
DelayReq_assignment:
DelayReq <= '1' when (PowerControlSM = PowerOFF and (Req_P_ON='1' and nPowerOOT='1')) else
            '1' when (PowerControlSM = PowerON and (nPowerOOT='1' and Req_HT_ON='1' and not (Req_P_ON='0'))) else
            '0';

IntReq_assignment:
IntReq <= '1' when (PowerControlSM = I_ERR) else
          '1' when (PowerControlSM = V_ERR) else
          '0';

end power_sm_arch;
