LIBRARY ieee;
USE ieee.numeric_std.all;
USE ieee.std_logic_1164.all;

ENTITY spi_parser IS
	PORT 
	(
		CLK				:	IN std_logic;								--! interni hodinovy signal
		RST				:	IN std_logic;								--! signal reset aktivni v log. 1
		
		SCLK			:	IN std_logic;								--! Hodinovy signal SPI
		CS_N			:	IN std_logic;								--! Chip select signal SPI
		MOSI			:	IN std_logic;								--! Master Out Slave In SPI 
		MISO			:	OUT std_logic;								--! Master In Slave Out SPI	
		
		EPWM_add		:	OUT std_logic_vector(7 DOWNTO 0);			--! adresa periferie ePWM
		EPWM_reg		:	OUT std_logic_vector(7 DOWNTO 0);			--! adresa registru ePWM
		EPWM_val		:	OUT std_logic_vector(15 DOWNTO 0);			--! hodnota pro zapis do registru ePWM
		EPWM_vld		:	OUT std_logic;								--! validni impuls prijatych dat
		EPWM_dat		:	IN std_logic_vector(15 DOWNTO 0)			--! cteni dat z registru ePWM
	);
END spi_parser;

ARCHITECTURE Behavioral OF spi_parser IS

	-- spi
	SIGNAL DOUT 				:	std_logic_vector(15 DOWNTO 0)	:= (OTHERS => '0');
	SIGNAL DOUT_VLD				:	std_logic						:= '0';
	SIGNAL DOUT_VLD_prev		:	std_logic						:= '0';
	SIGNAL DOUT_VLD_redge		:	std_logic						:= '0';
	SIGNAL DOUT_ERR				:	std_logic						:= '0';

	SIGNAL iEPWM				:	std_logic_vector(31 DOWNTO 0)	:= (OTHERS => '0');
	CONSTANT RECIEVE_TIMEOUT	:	integer							:=	3000; -- 1/f_clk*t
	SIGNAL RECIEVE_ERROR		:	std_logic						:= '0';

	TYPE 	t_State 			IS (Recieve1, Recieve2, Error, Succes, Valid);
	SIGNAL	State				:	t_State	  := Recieve1;

BEGIN

	spi_slave: ENTITY work.spi_slave
	GENERIC MAP
	(
		BYTES		=>	2
	)

	PORT MAP
	(
		CLK			=> CLK,
		RST			=> RST,
		SCLK		=> SCLK,
		CS_N 		=> CS_N,
		MOSI		=> MOSI,
		MISO		=> MISO,
		DIN			=> EPWM_dat,
		DOUT		=> DOUT,
		DOUT_VLD	=> DOUT_VLD,
		DOUT_ERR	=> DOUT_ERR
	);
	

	PROCESS (CLK)
	BEGIN
		IF (rising_edge(CLK)) THEN
			DOUT_VLD_prev <= DOUT_VLD;
		END IF;
	END PROCESS;

	DOUT_VLD_redge <= DOUT_VLD AND NOT DOUT_VLD_prev;

	PROCESS (CLK)
		VARIABLE cnt : integer := 0;
	BEGIN
		IF rising_edge(CLK) THEN
			IF (RST = '1') THEN
				State <= Recieve1;
			ELSE
				CASE State IS

					-- cekani na prijeti prvniho datoveho ramce
					WHEN Recieve1 =>
						EPWM_vld <= '0';
						IF (DOUT_VLD_redge = '1') THEN
							iEPWM(31 DOWNTO 16) <= DOUT;
							IF(DOUT(7) = '1') THEN
								State <= Succes; -- pokud se jedna o cteni, tak neprijimame dalsi hodnotu
							ELSE
								State <= Recieve2; -- pokud se jedna o zapis
							END IF;
						END IF;

					-- cekani na prijeti druheho datoveho ramce s timeoutem
					WHEN Recieve2 =>
						IF (cnt = RECIEVE_TIMEOUT) THEN
							iEPWM <= (OTHERS => '0');
							cnt := 0;
							State <= Error;
						ELSIF (DOUT_VLD_redge = '1') THEN
							iEPWM(15 DOWNTO 0) <= DOUT;
							cnt := 0;
							State <= Succes;
						ELSE
							cnt := cnt + 1;
						END IF;

					-- chybovy stav, ktery je zpusoben vyprsenim casu mezi prijetim ramcu
					WHEN Error =>
						IF (RST = '1') THEN
							--RECIEVE_ERROR <= '0';
							State <= Recieve1;
						ELSE
							--RECIEVE_ERROR <= '1';
						END IF;

					-- v pripade uspesne komunikace se hodnoty zapisi do vystupniho registru
					WHEN Succes =>
						IF(iEPWM(23) = '0') THEN
							EPWM_val <= iEPWM(15 DOWNTO 0); -- v pripade ze jde o zapis
						END IF;
						EPWM_add <= iEPWM(31 DOWNTO 24);
						EPWM_reg <= iEPWM(23 DOWNTO 16);
						State <= Valid;

					-- vysle impuls, ze data jsou validni
					WHEN Valid =>
						EPWM_vld <= '1';
						State <= Recieve1;	
				END CASE;
			END IF;
		END IF;
	END PROCESS;

END Behavioral;