library IEEE;
library work;

use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.bicolor_led_ctrl_pkg.ALL;

package rs485_pkg is

   constant c_NUMBER_OF_CHANNELS  : NATURAL := 6;

   constant c_NB_ARRAY_LEDS       : NATURAL := 12;
   constant c_LED_INTENSITY       : STD_LOGIC_VECTOR(6 downto 0) := "0011111";

   --! Front array LEDs individual assignment
   --! Pairings:
   --!  COLUMN      t_led_state
   --!       0           0 -  6
   --!       1           1 -  7
   --!       2           2 -  8
   --!       3           3 -  9
   --!       4           4 - 10
   --!       5           5 - 11
   constant c_LED_NB_WR_ADDR    : NATURAL := 0;
   constant c_LED_NB_WR_GMT     : NATURAL := 1;
   constant c_LED_NB_WR_LINK    : NATURAL := 2;
   constant c_LED_NB_WR_OK      : NATURAL := 3;
   constant c_LED_NB_MULTICAST0 : NATURAL := 4;
   constant c_LED_NB_MULTICAST1 : NATURAL := 5;
   constant c_LED_NB_I2C        : NATURAL := 6;
   constant c_LED_NB_TTL_N      : NATURAL := 7;
   constant c_LED_NB_ERR        : NATURAL := 8;
   constant c_LED_NB_PWR        : NATURAL := 9;
   constant c_LED_NB_MULTICAST2 : NATURAL := 10;
   constant c_LED_NB_MULTICAST3 : NATURAL := 11;

   constant c_LED_COLOR_PWR        : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_ERR        : STD_LOGIC_VECTOR(1 downto 0) := c_LED_RED;
   constant c_LED_COLOR_TTL_N      : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_I2C        : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_WR_OK      : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_WR_LINK    : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_WR_GMT     : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_WR_ADDR    : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_MULTICAST3 : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_MULTICAST2 : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_MULTICAST1 : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;
   constant c_LED_COLOR_MULTICAST0 : STD_LOGIC_VECTOR(1 downto 0) := c_LED_GREEN;

   type t_leds_array_top is
      record
         PWR      : STD_LOGIC;
         ERR      : STD_LOGIC;
         TTL_N    : STD_LOGIC;
         I2C      : STD_LOGIC;
      end record;

   type t_leds_array_middle is
      record
         WR_OK    : STD_LOGIC;
         WR_LINK  : STD_LOGIC;
         WR_GMT   : STD_LOGIC;
         WR_ADDR  : STD_LOGIC;
      end record;

   type t_leds_array_bottom is
      record
         MULTICAST : UNSIGNED(3 downto 0);
      end record;

   type t_leds_array is
      record
         top     : t_leds_array_top;
         middle  : t_leds_array_middle;
         bottom  : t_leds_array_bottom;
      end record;

   type t_led_state is
      record
         STATE   : STD_LOGIC_VECTOR(1 downto 0);
      end record;

   type t_led_state_array is array(natural range <>) of t_led_state;


--   constant c_leds_array_top_default     : t_leds_array_top := (PWR     => '0',
--                                                                ERR     => '0',
--                                                                TTL_N   => '0',
--                                                                I2C     => '0');
--
--   constant c_leds_array_middle_default  : t_leds_array_middle := (WR_OK   => '0',
--                                                                   WR_LINK => '0',
--                                                                   WR_GMT  => '0',
--                                                                   WR_ADDR => '0');
--
--   constant c_leds_array_bottom_default  : t_leds_array_bottom := (MULTICAST
--                                                    => (others => '0'));

   constant c_NB_COLUMN  : NATURAL := 6;
   constant c_NB_LINE    : NATURAL := 6;

   component bicolor_led_ctrl is
   generic(g_NB_COLUMN    : NATURAL := c_NB_COLUMN;
           g_NB_LINE      : NATURAL := c_NB_LINE;
           g_CLK_FREQ     : NATURAL := 20000000;  -- in Hz
           g_REFRESH_RATE : NATURAL := 250);       -- in Hz
   port(rst_n_i         : in  STD_LOGIC;
        clk_i           : in  STD_LOGIC;
        led_intensity_i : in  STD_LOGIC_VECTOR(6 downto 0);
        led_state_i     : in  STD_LOGIC_VECTOR(
                               (g_NB_LINE * g_NB_COLUMN * 2) - 1 downto 0);
        column_o        : out STD_LOGIC_VECTOR(g_NB_COLUMN - 1 downto 0);
        line_o          : out STD_LOGIC_VECTOR(  g_NB_LINE - 1 downto 0);
        line_oen_o      : out STD_LOGIC_VECTOR(  g_NB_LINE - 1 downto 0));
   end component;


   component image1_top is
   generic(g_NUMBER_OF_CHANNELS : NATURAL := 6);
   port (FPGA_CLK_P        : in STD_LOGIC; --Using the 125MHz clock
         FPGA_CLK_N        : in STD_LOGIC;
         led_pw_o          : out STD_LOGIC;
         led_err_o         : out STD_LOGIC;
         led_ttl_o         : out STD_LOGIC;
         led_o_front       : out STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         led_o_rear        : out STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         pulse_i_front     : in  STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         pulse_o_front     : out STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         pulse_i_rear      : in  STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         pulse_o_rear      : out STD_LOGIC_VECTOR(g_NUMBER_OF_CHANNELS downto 1);
         inv_i             : in  STD_LOGIC_VECTOR(4 downto 1);
         inv_o             : out STD_LOGIC_VECTOR(4 downto 1);
         --! Lines for the i2c_slave
         SCL_I             : in  STD_LOGIC;
         SCL_O             : out STD_LOGIC;
         SCL_OE            : out STD_LOGIC;
         SDA_I             : in  STD_LOGIC;
         SDA_O             : out STD_LOGIC;
         SDA_OE            : out STD_LOGIC;
         FPGA_GA           : in  STD_LOGIC_VECTOR(4 downto 0);
         FPGA_GAP          : in  STD_LOGIC;
         --! Pins of the SPI interface to write into the Flash memory
         FPGA_PROM_CCLK    : out STD_LOGIC;
         FPGA_PROM_CSO_B_N : out STD_LOGIC;
         FPGA_PROM_DIN     : in  STD_LOGIC;
         FPGA_PROM_MOSI    : out STD_LOGIC;
         --! This LED will show the status of the PLL
         led_link_up_o     : out STD_LOGIC;
         led_pps_o         : out STD_LOGIC;
         led_wr_ok_o       : out STD_LOGIC;
         --! RTM identifiers, should match with the expected values
         --! TODO: add matching
         fpga_o_en         : out STD_LOGIC;
         fpga_o_blo_en     : out STD_LOGIC;
         fpga_o_ttl_en     : out STD_LOGIC;
         fpga_o_inv_en     : out STD_LOGIC;
         level             : in  STD_LOGIC;
         switch_i          : in  STD_LOGIC;   --! General enable
         manual_rst_n_o    : out STD_LOGIC;   --! It allows power sequencing of the
                                              --! 24V rail after a security given
                                              --! delay
         FPGA_RTMM         : in STD_LOGIC_VECTOR(2 downto 0);
         FPGA_RTMP         : in STD_LOGIC_VECTOR(2 downto 0));
   end component;

   function f_LED_STATE(state: STD_LOGIC_VECTOR(1 downto 0)) return t_led_state;

   function f_STD_LOGIC_VECTOR(led_state : t_led_state) return STD_LOGIC_VECTOR;

   function f_STD_LOGIC_VECTOR(led_state_array : t_led_state_array)
                                                        return STD_LOGIC_VECTOR;

end rs485_pkg;
package body rs485_pkg is

   --! @brief        Translation function from STD_LOGIC_VECTOR to t_led_state
   --! @param state  LED state in STD_LOGIC_VECTOR format
   function f_LED_STATE(state: STD_LOGIC_VECTOR(1 downto 0)) return t_led_state is
      variable v_return  : t_led_state;
   begin
      v_return.STATE(0) := state(0);
      v_return.STATE(1) := state(1);
      return v_return;
   end f_LED_STATE;


   --! @brief                  Translation function from STD_LOGIC_VECTOR to
   --!                          t_led_state
   --! @param led_state_array  LED state in STD_LOGIC_VECTOR format
   function f_STD_LOGIC_VECTOR(led_state : t_led_state)
                                                      return STD_LOGIC_VECTOR is
      variable v_return  : STD_LOGIC_VECTOR(1 downto 0);
   begin
      v_return(0) := led_state.STATE(0);
      v_return(1) := led_state.STATE(1);
      return v_return;
   end f_STD_LOGIC_VECTOR;


   --! @brief                  Translation function from STD_LOGIC_VECTOR to
   --!                          t_led_state_array
   --! @param led_state_array  LED array state in STD_LOGIC_VECTOR format
   function f_STD_LOGIC_VECTOR(led_state_array : t_led_state_array)
                                                      return STD_LOGIC_VECTOR is
      variable v_return  : STD_LOGIC_VECTOR(c_NB_COLUMN*c_NB_LINE - 1 downto 0);
      variable v_led_state_tmp      : t_led_state;
      variable v_led_state_slv_tmp  : STD_LOGIC_VECTOR(1 downto 0);
   begin
      for i in 0 to c_NB_COLUMN*c_NB_LINE - 1 loop
         v_led_state_tmp     := led_state_array(i);
         v_led_state_slv_tmp := f_STD_LOGIC_VECTOR(v_led_state_tmp);
         v_return(2*i + 1 downto 2*i) := v_led_state_slv_tmp;
      end loop;
      return v_return;
   end f_STD_LOGIC_VECTOR;

end rs485_pkg;
