-------------------------------------------------------------------------------
-- Receiver for Behringer UltraNet
-- based on OpenCore's i2s_interface by Geir Drange (https://opencores.org/projects/i2s_interface)
--
-- UltraNet sends eight 24-bit audio-samples in AES/EBU-format.
-- this file expects I2S-data converted from AES/EBU
--
-- bsync (Z subframe in AES/EBU) will signal channel 1 followed by seven more samples
-- individual samples are identified by lrclk
------------------------------------------------------------------------------- 

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all; 
use ieee.numeric_std.all; -- lib for unsigned and signed

entity i2s_deser is
	generic ( CHANNELS : integer range 2 to 8 := 2
    		);
	port (
			clk 		: in std_logic; -- Master clock
			bsync		: in std_logic; -- Block start (asserted when Z subframe is being transmitted)
			bclk 		: in std_logic; -- output serial data clock (AES3-clock)
			lrclk		: in std_logic; -- Frame sync (asserted for channel A, negated for B)
			sdata1		: in std_logic; -- output serial data
			sdata2		: in std_logic; -- output serial data
			
			sample_out1	: out std_logic_vector(23 downto 0); -- received audio-sample
			sample_out2	: out std_logic_vector(23 downto 0); -- received audio-sample
			new_data	: out std_logic; -- new data received successfully
			new_data_2x	: out std_logic -- new data received successfully
        );
end i2s_deser;

architecture rtl of i2s_deser is
	signal sample_data1			: std_logic_vector(23 downto 0);
	signal sample_data2			: std_logic_vector(23 downto 0);
	signal bsync_pos_edge		: std_logic;
	signal neg_edge, pos_edge 	: std_logic;
	signal lr_edge					: std_logic;
	signal rx_sampledata 		: std_logic;

	signal zbsync, zzbsync, zzzbsync	: std_logic;
	signal zbclk, zzbclk, zzzbclk 	: std_logic;
	signal zlrclk, zzlrclk, zzzlrclk	: std_logic;

	signal bit_cnt					: integer range 0 to 31 := 0;
begin
	detect_bsync_pos_edge : process(clk)
	begin
		if rising_edge(clk) then
			zbsync <= bsync;
			zzbsync <= zbsync;
			zzzbsync <= zzbsync;
			if zzbsync = '1' and zzzbsync = '0' then
				bsync_pos_edge <= '1';
			else
				bsync_pos_edge <= '0';
			end if;
		end if;
	end process;

	detect_edge : process(clk)
	begin
		if rising_edge(clk) then
			zbclk <= bclk;
			zzbclk <= zbclk;
			zzzbclk <= zzbclk;
			if zzbclk = '1' and zzzbclk = '0' then
				pos_edge <= '1';
			elsif zzbclk = '0' and zzzbclk = '1' then
				neg_edge <= '1';
			else
				pos_edge <= '0';
				neg_edge <= '0';
			end if;
		end if;
	end process;
 
   detect_lr_edge : process(clk)
	begin
		if rising_edge(clk) then
			zlrclk <= lrclk;
			zzlrclk <= zlrclk;
			zzzlrclk <= zzlrclk;
			if zzlrclk /= zzzlrclk then
				lr_edge <= '1';
			else
				lr_edge <= '0';
			end if;
		end if;
	end process;
 
	detect_sample : process(clk)
	begin
		if rising_edge(clk) then
			if bsync_pos_edge = '1' then
				bit_cnt <= 0;
				new_data <= '0';
                new_data_2x <= '0';
			else
				if lr_edge = '1' then -- rising or falling edge on LRCLK detected
					bit_cnt <= 0;
				end if;

				if pos_edge = '1' then
					bit_cnt <= bit_cnt + 1; -- increment bit_cnt until bit 31
				end if;

				if neg_edge = '1' then  	
                    -- Only read the first 24 bits
					if bit_cnt = 0 then
						rx_sampledata <= '1';
					elsif bit_cnt >= 24 then
						rx_sampledata <= '0';
					end if;
				end if;

                -- raise new_data-signal within the unused 4bits at the end of the frame
				if bit_cnt = 31 and neg_edge = '1' then 
					new_data <= '1';
				else
					new_data <= '0';
				end if;
				if (bit_cnt = 31 or bit_cnt = 15) and neg_edge = '1' then 
					new_data_2x <= '1';
				else
					new_data_2x <= '0';
				end if;

			end if;
		end if;
	end process;

	--sample_out <= "0000" & sample_data(19 downto 0); -- take only 20 bit
	sample_out1 <= sample_data1; -- take all 24 bits
	sample_out2 <= sample_data2; -- take all 24 bits

	get_data : process(clk)
	begin
		if rising_edge(clk) then
			-- receive individual bits for audio-data (24 bits)
			if pos_edge = '1' and rx_sampledata = '1' then
				--sample_data <= sample_data(sample_data'high - 1 downto 0) & sdata1;
				sample_data1 <= sdata1 & sample_data1(sample_data1'high downto 1); -- in AES3/EBU the first bit after preamble is LSB, so we have to shift from the left to the right
				sample_data2 <= sdata2 & sample_data2(sample_data2'high downto 1); -- in AES3/EBU the first bit after preamble is LSB, so we have to shift from the left to the right
			end if;
		end if;
	end process;
end rtl;
        