--------------------------------------------------------------------------------
-- Title   : Leds
-- Project : TimEX3
--------------------------------------------------------------------------------
-- Description : Leds management
--
--            | OFF                 | ON                  | BLINKING
--      ======|=====================|=====================|=====================
--      GREEN | FPGA not configured | OK                  | synchro pulse
--            |                     |                     | detected
--      ======|=====================|=====================|=====================
--      RED   | OK                  | simultaneous SPM    |
--            |                     | and LPM             |
--      ======|=====================|=====================|=====================
--
--------------------------------------------------------------------------------
-- File     : linacMON_leds.vhdl
-- Revision : x.x.x
-- Created  : July 09, 2013
-- Updated  : February 03, 2014
--------------------------------------------------------------------------------
-- Author       : Jean-Paul Ricaud
-- Organization : Synchrotron Soleil
-- Web          : http://www.synchrotron-soleil.fr
-- Email        : jean-paul.ricaud@synchrotron-soleil.fr
--------------------------------------------------------------------------------
-- Copyright (C) 2012 - 2014 Synchrotron Soleil
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Lesser General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
-- Modifications :
-- Modifications :
--   Version 1.6.0 ; November 29 2013 ; Jean-Paul Ricaud
--     * Monitoring now reacts on rising edge of the signal instead
--       of level
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.registers_init.all;

--------------------------------------------------------------------------------
--------------------------------- ENTITY ---------------------------------------
--------------------------------------------------------------------------------
entity linacMON_leds is
  port (
    p_inTTL           : in  std_logic_vector (1 downto 0); -- input TTL
    p_clk1kHz         : in  std_logic;
    p_clk500mHz       : in  std_logic;
    p_clk60MHz        : in  std_logic;
    p_missingSPMDelay : in  std_logic_vector (31 downto 0);
    p_missingLPMDelay : in  std_logic_vector (31 downto 0);
    p_csw             : in  std_logic_vector (1 downto 0);
    p_reset           : in  std_logic;
    p_simTriggError   : in  std_logic;
    p_delayError      : out std_logic_vector (1 downto 0);
    p_led             : out std_logic_vector (1 downto 0)
  );
end entity linacMON_leds;

--------------------------------------------------------------------------------
------------------------------- ARCHITECTURE -----------------------------------
--------------------------------------------------------------------------------
architecture rtl_linacMON_leds of linacMON_leds is

  ------------------------------------------------------------------------------
  -- constant
  ------------------------------------------------------------------------------
  constant s_cnt1max : unsigned (3 downto 0)  := "1011"; -- 5s

  ------------------------------------------------------------------------------
  -- signal
  ------------------------------------------------------------------------------
  signal s_cnt1       : unsigned (3  downto 0); -- counter
  signal s_cnt2       : unsigned (31 downto 0); -- SPM counter
  signal s_cnt2max    : unsigned (31 downto 0); -- SPM max delay
  signal s_cnt3       : unsigned (31 downto 0); -- LPM counter
  signal s_cnt3max    : unsigned (31 downto 0); -- LPM max delay
  signal s_greenLedON : std_logic;
  signal s_blink      : std_logic;
  signal s_rstCNT2    : std_logic; -- reset the conter after a software SPM delay update
  signal s_rstCNT3    : std_logic; -- reset the conter after a software LPM delay update
  signal s_start      : std_logic_vector (1 downto 0);
  signal s_stop       : std_logic_vector (1 downto 0);
  signal s_hold1      : std_logic_vector (1 downto 0);
  signal s_hold2      : std_logic_vector (1 downto 0);

  ------------------------------------------------------------------------------
  --------------------------------- Main ---------------------------------------
  ------------------------------------------------------------------------------
  begin


  -- Green LED
  -- The green LED is blinked for 5s after a reset or after a input pulse is
  -- détected. It remains ON in other cases.
  process (p_reset, p_inTTL(0), p_inTTL(1), p_clk500mHz)
  begin
    if ((p_inTTL(0) = '1') or (p_inTTL(1) = '1') or (p_reset = '1')) then
      s_cnt1       <= (OTHERS => '0');
      s_greenLedON <= '1'; -- green LED ON
      s_blink      <= '1'; -- blink the green LED
    elsif (rising_edge(p_clk500mHz)) then
      if (s_blink = '1') then
        if (s_cnt1 < s_cnt1max) then
          s_cnt1       <= s_cnt1 + 1;
          s_greenLedON <= not s_greenLedON; -- blink the green LED
          s_blink      <= '1';              -- keep blinking
        else
          s_cnt1       <= s_cnt1; -- keep the max value
          s_greenLedON <= '1';    -- green LED ON
          s_blink      <= '0';    -- stop blinking
        end if;
      else
        s_cnt1       <= s_cnt1; -- keep the max value
        s_greenLedON <= '1';    -- green LED ON
        s_blink      <= '0';    -- stop blinking
      end if;
    end if;
  end process;

  -- Error if no SPM signal is detected after n mn.
  -- Set the status bit
  process (p_reset, p_inTTL(0), s_stop(0))
  begin
    if ((s_stop(0) = '1') or (p_reset = '1')) then
      s_start(0) <= '0';
    elsif (rising_edge(p_inTTL(0))) then
      s_start(0) <= '1';
    end if;
  end process;

  process (p_reset, s_start(0), p_clk1kHz)
  begin
    if ((s_start(0) = '0') or (p_reset = '1')) then
      s_hold1(0) <= '0';
      s_hold2(0) <= '0';
      s_stop(0)  <= '0';
    elsif (falling_edge(p_clk1kHz)) then
      s_hold1(0) <= '1';
      s_hold2(0) <= s_hold1(0);
      s_stop(0)  <= s_hold2(0);
    end if;
  end process;

  process (p_reset, s_stop(0), s_rstCNT2, p_clk1kHz)
  begin
    if ((s_stop(0) = '1') or (p_reset = '1') or (s_rstCNT2 = '1')) then
      s_cnt2 <= (OTHERS => '0');
      p_delayError(0)  <= '0'; -- red LED OFF
    elsif (rising_edge(p_clk1kHz)) then
      if (s_cnt2 < s_cnt2max) then
        s_cnt2 <= s_cnt2 + 1;
        p_delayError(0) <= '0'; -- red LED OFF
      else
        s_cnt2 <= s_cnt2;       -- keep the max value in case of overflow
        p_delayError(0) <= '1'; -- red LED ON
      end if;
    end if;
  end process;

  -- Error if no LPM signal is detected after n mn.
  -- Set the status bit
  process (p_reset, p_inTTL(1), s_stop(1))
  begin
    if ((s_stop(1) = '1') or (p_reset = '1')) then
      s_start(1) <= '0';
    elsif (rising_edge(p_inTTL(1))) then
      s_start(1) <= '1';
    end if;
  end process;

  process (p_reset, s_start(1), p_clk1kHz)
  begin
    if ((s_start(1) = '0') or (p_reset = '1')) then
      s_hold1(1) <= '0';
      s_hold2(1) <= '0';
      s_stop(1)  <= '0';
    elsif (falling_edge(p_clk1kHz)) then
      s_hold1(1) <= '1';
      s_hold2(1) <= s_hold1(1);
      s_stop(1)  <= s_hold2(1);
    end if;
  end process;

  process (p_reset, s_stop(1), s_rstCNT3, p_clk1kHz)
  begin
    if ((s_stop(1) = '1') or (p_reset = '1') or (s_rstCNT3 = '1')) then
      s_cnt3 <= (OTHERS => '0');
      p_delayError(1)  <= '0';
    elsif (rising_edge(p_clk1kHz)) then
      if (s_cnt3 < s_cnt3max) then
        s_cnt3 <= s_cnt3 + 1;
        p_delayError(1) <= '0';
      else
        s_cnt3 <= s_cnt3; -- keep the max value in case of overflow
        p_delayError(1) <= '1';
      end if;
    end if;
  end process;

  -- Latch from the register the maximum delay before a missing SPM pulse
  -- is signaled
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_cnt2max <= unsigned (c_wRegister_init(9));
      s_rstCNT2 <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (p_csw(0) = '1') then
        s_cnt2max <= unsigned (p_missingSPMDelay);
        s_rstCNT2 <= '1';
      else
        s_cnt2max <= s_cnt2max;
        s_rstCNT2 <= '0';
      end if;
    end if;
  end process;

  -- Latch from the register the maximum delay before a missing LPM pulse
  -- is signaled
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_cnt3max <= unsigned (c_wRegister_init(11));
      s_rstCNT3 <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (p_csw(1) = '1') then
        s_cnt3max <= unsigned (p_missingLPMDelay);
        s_rstCNT3 <= '1';
      else
        s_cnt3max <= s_cnt3max;
        s_rstCNT3 <= '0';
      end if;
    end if;
  end process;

  ------------------------------------------------------------------------------
  ------------------------------------------------------------------------------
  p_led(0) <= p_simTriggError; -- red led
  p_led(1) <= s_greenLedON;    -- green led

end architecture rtl_linacMON_leds;
