----------------------------------------------------------------------------------
-- Company: 
-- Engineer: mohammad mazraeh
-- 
-- Create Date:    18:52:05 06/06/2007 
-- Design Name: 
-- Module Name:    SERIAL_PACK - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SERIAL_PACK is
	generic(	oscillator_clk		:	integer		:=1843200;--7372800;--
				baud_rate			:	integer		:=115200;
				parity_enable		:	std_logic	:='1';
				parity_type			:	std_logic	:='0'	-- Even='0' , Odd='1'
				);
    port ( 	
				clk 					: 	in  	std_logic;
				serial_in 			: 	in  	std_logic;
				serial_out 			: 	out  	std_logic:='1';
				received_data		:	out	std_logic_vector(7 downto 0):=(others=>'0');
				send_data			:	in		std_logic_vector(7 downto 0);
				receive_enable		:	in		std_logic;
				send_enable			:	in		std_logic;
				receive_flag		:	out	std_logic:='0';
				send_flag			:	inout std_logic:='0';
				receive_error		:	out	std_logic:='0'
				);
end SERIAL_PACK;

architecture Behavioral of SERIAL_PACK is

type	SERIAL_RECEIVE_STATE_TYPE	is	
		(Receive_waiting, Receiving);
type	SERIAL_SEND_STATE_TYPE	is	
		(Send_waiting, Sending);

constant EVEN_PARITY						:	std_logic :='0';
constant ODD_PARITY						:	std_logic :='1';
constant	END_BAUD_COUNT_NUMBER		:	integer	:=	1000000;
constant	NO_PAR_PACKET_BIT_COUNT		:	integer	:=	10;
constant	PAR_PACKET_BIT_COUNT			:	integer	:=	11;

signal	rec_state			:	SERIAL_RECEIVE_STATE_TYPE	:=	Receive_waiting;
signal	send_state			:	SERIAL_SEND_STATE_TYPE	:=	Send_waiting;
signal	packet_bit_count	:	integer	range	0	to	11;

signal	rec_baud_counter	:integer range 0 to END_BAUD_COUNT_NUMBER :=0;
signal	rec_bit_counter	:integer range 0 to 11	:=0;
			
signal	send_baud_counter	:integer range 0 to END_BAUD_COUNT_NUMBER	:=0;
signal	send_bit_counter	:integer range 0 to 11	:=0;
			
signal	send_packet			:	std_logic_vector(PAR_PACKET_BIT_COUNT downto 0);
signal	rec_packet			:	std_logic_vector(PAR_PACKET_BIT_COUNT downto 0);

signal	end_baud_count		:	integer	range 0 to END_BAUD_COUNT_NUMBER; 
signal	send_baud_count	:	integer	range 0 to END_BAUD_COUNT_NUMBER/2;
signal	rec_baud_count		:	integer	range 0 to END_BAUD_COUNT_NUMBER/2;

signal	send_packet_par	:	std_logic:='0';

begin


end_baud_count	<=	(oscillator_clk	/ baud_rate) - 1;
rec_baud_count		<=	end_baud_count/2;
send_baud_count	<=	end_baud_count/2;


--=================================================
-- ============== receive ==========
--=================================================
BYTE_RECEIVE_PROCESS:
process(clk)
begin

------------
if (parity_enable='1')	then
	packet_bit_count	<=	PAR_PACKET_BIT_COUNT;
else
	packet_bit_count	<=	NO_PAR_PACKET_BIT_COUNT;
end if;	
	
------------
if (rising_edge (clk))	then
	case	rec_state	is
		----------
		when	Receive_waiting	=>
				rec_baud_counter	<=	0;
				rec_bit_counter	<=	0;
				--------
				receive_flag				<=	'0';
				--------
				if ((receive_enable='1') and (serial_in='0'))	then	
					rec_baud_counter	<=	1;
					rec_state			<=	Receiving;
				else
					rec_state			<=	Receive_waiting;
				end if;
		----------
		when	Receiving	=>
				----------
				if (rec_baud_counter = rec_baud_count)	then
					rec_packet(rec_bit_counter)	<=	serial_in;
					rec_baud_counter					<=	rec_baud_counter + 1;
				elsif (rec_baud_counter = end_baud_count)	then
					rec_baud_counter					<=	0;
					rec_bit_counter					<=	rec_bit_counter + 1;
				else
					rec_baud_counter					<=	rec_baud_counter + 1;
				end if;
				--------
				if	((rec_bit_counter = packet_bit_count-1) and (rec_baud_counter = end_baud_count)) then
					if	((rec_packet(packet_bit_count-1)='1') and (rec_packet(0)='0'))	then
						if	(parity_enable='1')	then
							if	(rec_packet(9) = (rec_packet(8) xor rec_packet(7) xor 
								 rec_packet(6) xor rec_packet(5) xor rec_packet(4) xor 
								 rec_packet(3) xor rec_packet(2) xor rec_packet(1) xor parity_type))	then
								receive_error				<=	'0';
								received_data				<=	rec_packet(8 downto 1);
								receive_flag				<=	'1';
							else
								receive_error				<=	'1';
							end if;
						else
							receive_error				<=	'0';
							received_data				<=	rec_packet(8 downto 1);
							receive_flag				<=	'1';
						end if;
					else
						receive_error	<=	'1';
					end if;
					rec_state		<=	Receive_waiting;
				else
					rec_state		<=	Receiving;
				end if;	

		------------
		when	others	=>
				rec_state			<=	Receive_waiting;
			--------

	end case;
end if;	
end process;



--=================================================
-- ============== send ==========
--=================================================
BYTE_SEND_PROCESS:
process(clk)
begin
-------------------
if (rising_edge (clk))	then
	-----------
	case	send_state	is
		--------------
		when	Send_waiting	=>
			send_baud_counter		<=	0;
			send_bit_counter		<=	0;
			if	((send_enable='1') and (send_flag='0'))	then
				if	(parity_enable='1')	then
					send_packet(packet_bit_count-1 downto 0)	<=	
							'1'& (send_data(7) xor send_data(6) xor 
									send_data(5) xor	send_data(4) xor 
									send_data(3) xor send_data(2) xor
									send_data(1) xor send_data(0) xor 
									parity_type) & send_data(7 downto 0) & '0';
				else
					send_packet(packet_bit_count-1 downto 0)	<=	
							'1'& send_data(7 downto 0) & '0';
				end if;
				send_flag			<=	'1';
				send_state			<=	Sending;
			else
				send_flag			<=	'0';
				send_state			<=	Send_waiting;
			end if;

		------------
		when	Sending	=>
			--------
			if (send_baud_counter=0)	then
				serial_out						<=	send_packet(send_bit_counter);
				send_baud_counter		<=	send_baud_counter + 1;
			elsif (send_baud_counter=end_baud_count)	then
				send_baud_counter		<=	0;
				send_bit_counter		<=	send_bit_counter + 1;
			else
				send_baud_counter		<=	send_baud_counter + 1;
			end if;
			--------
			if	((send_bit_counter=packet_bit_count-1) and (send_baud_counter=end_baud_count - 1))	then
				send_flag			<=	'0';
				send_state			<=	Send_waiting;
			else
				send_state			<=	Sending;
			end if;	
		------------
		when	others	=>
				send_state			<=	Send_waiting;
			--------


	end case;
end if;	

end process;


end Behavioral;



