--
-- VHDL Architecture FACT_FAD_lib.led_controller.bahavior
--
-- Created:
--          by - dneise.UNKNOWN (E5B-LABOR6)
--          at - 11:04:17 04.01.2011
--
-- using Mentor Graphics HDL Designer(TM) 2009.2 (Build 10)
--
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
use ieee.STD_LOGIC_UNSIGNED.all;

library FACT_FAD_lib;


use FACT_FAD_lib.fad_definitions.all;


ENTITY led_controller IS
GENERIC( 
  HEARTBEAT_PWM_DIVIDER : integer := 500;   
  WAITING_DIVIDER : integer := 500000000  
);
PORT(
    CLK : IN std_logic;
    
    -- LED outs -- inverted logic
    green : OUT std_logic;
    amber : OUT std_logic; 
    red : OUT std_logic; 
    additional_flasher_out : OUT std_logic;
    
    
    -- status INs
    trigger : IN std_logic; -- when trigger is received green should toggle
	
	w5300_reset : in std_logic;
	trigger_veto : in std_logic;
    
	refclk_too_high : in std_logic;
	refclk_too_low : in std_logic;
	
    socks_waiting : IN std_logic;
    socks_connected: IN std_logic
    
	
    --heartbeat_en : IN std_logic
  );
END ENTITY led_controller;

--
ARCHITECTURE bahavior OF led_controller IS
  
  type states is ( INIT, WAITING, CONNECTED); 
    signal state,next_state : states := INIT;
  
  -- noninverted logic
  signal green_loc : std_logic := '1';  -- on in order to show power
  signal amber_loc : std_logic := '0'; --default off
  signal red_loc  : std_logic := '0'; --default off
  signal flasher : std_logic;
  
  signal heartbeat_counter: integer range 0 to HEARTBEAT_PWM_DIVIDER - 1 := 0;
  constant ontime_update : integer := 100;
  signal ontime_update_counter : integer range 0 to ontime_update - 1 := 0;
  signal on_time: integer range 0 to HEARTBEAT_PWM_DIVIDER - 1 := 0;
  constant ontime_divider : integer range 0 to HEARTBEAT_PWM_DIVIDER - 1 := 1;
  signal delta_ontime : integer range 0 to HEARTBEAT_PWM_DIVIDER - 1 := 1;
  signal DIR : std_logic := '0';
  
BEGIN
  -- since leds have inverted logic, the outs are inverted at this point.
  green <= not green_loc;
  
  --amber <= not amber_loc;
  amber <= w5300_reset;
  
  --red <= not red_loc;
  red <= not trigger_veto;
  
  additional_flasher_out <= flasher;
  
  -- MAIN FSM: go to next state if rising edge
    FSM_Registers: process(CLK)
    begin
      if Rising_edge(CLK) then
        state <= next_state;
      end if;
    end process;

    -- MAIN FSM
    FSM_logic: process(state, socks_connected, socks_waiting)
    begin
      next_state <= state;
      case state is
    

      when INIT =>
        green_loc <= '0';
      if (socks_waiting = '1') then
        next_state <= WAITING;
      else 
        next_state <= INIT;
      end if;

      when WAITING =>
        green_loc <= flasher;
        if (socks_connected = '1') then
          next_state <= CONNECTED;
        else
          next_state <= WAITING;
        end if;

      when CONNECTED =>
        green_loc <= '1';
        if (socks_connected = '0') then
          next_state <= INIT;
        else
          next_state <= CONNECTED;
        end if;
      end case;
    end process FSM_logic;


  -- if trigger is received red_loc toggles
  trigger_proc : process (trigger)
    begin
      if Rising_edge(trigger) then
        red_loc <= not red_loc;
      end if;
    end process trigger_proc;
    
  -- heartbeat process:
  -- as long as nothing else is to be done for the red led
  -- it will show a ~2Hz heartbeat
  -- can be switched off with heartbeat_en high
  heartbeat : process (CLK)
      
      
      
      
    begin
      if rising_edge(CLK) then
        if (heartbeat_counter < HEARTBEAT_PWM_DIVIDER - 1) then 
          heartbeat_counter <= heartbeat_counter + 1;
        else 
          heartbeat_counter <= 0;
        end if;
        
		-- calculate the change in on_time
		-- if the change is too small... then change at least by 1.
        if ( on_time / (2*ontime_divider) = 0) then
			delta_ontime <= 1;
		else
			delta_ontime <= on_time / (2*ontime_divider);
		end if;
	if (heartbeat_counter = 0) then
		if (ontime_update_counter < ontime_update - 1) then
			ontime_update_counter <= ontime_update_counter + 1;
		else
			ontime_update_counter <= 0;
			
			-- set new on_time	
			if (DIR = '0') then -- increase on_time
				if (on_time + delta_ontime < HEARTBEAT_PWM_DIVIDER - 1) then 
					on_time <= on_time + delta_ontime;
				else
					on_time <= HEARTBEAT_PWM_DIVIDER - 1;
					DIR <= '1';
				end if;
			else -- DIR is '1' -- count down
				if (on_time - delta_ontime > 0) then 
					on_time <= on_time - delta_ontime;
				else 
					on_time <= 0;
					DIR <= '0';
				end if;
			end if;            
			
		end if;
	end if;
	
	
        
        if (heartbeat_counter = 0) then 
          amber_loc <= '1';  
        end if;
        if (heartbeat_counter = on_time) then
          amber_loc <= '0';
        end if;
      end if;
    end process heartbeat; 
    
    
      -- sock_waiting_flasher process:
      sock_waiting_flasher : process (CLK)
          variable Y: integer range 0 to WAITING_DIVIDER - 1;
        begin
          if rising_edge(CLK) then
            if (Y < WAITING_DIVIDER - 1) then 
              Y := Y + 1;
            else 
              Y := 0;
            end if;
            if (Y = 0) then 
              flasher <= '1';
            end if;
            if (Y = WAITING_DIVIDER / 2) then 
              flasher <= '0';
            end if;
          end if;
        end process sock_waiting_flasher; 
    
   
END ARCHITECTURE bahavior;

