library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

entity main is
	port (
		CLOCK_50 : in std_logic;
		GPIO_2 : inout std_logic_vector(12 downto 0)
	);
end entity;

-- -----------------------------------------------------------------------

architecture rtl of main is

	-- CLOCK_50 frequency
	constant CLOCK_FREQUENCY: natural := 50e6;
	
	-- RS232 baudrate
	constant BAUDRATE: natural := 115200;

	-- sample random flag with 150 kHz
	constant FREQUENCY_SAMPLER: natural := 150e3;
	constant CYCLES_SAMPLER: natural := CLOCK_FREQUENCY / FREQUENCY_SAMPLER / 2;
	signal counterSampler: integer range 0 to CYCLES_SAMPLER := CYCLES_SAMPLER;

	-- latch for random input signal
	signal randomLatch: std_logic := '0';
	signal randomLatch2: std_logic := '0';

	-- randomFlag is toggled as long as randomLath2 is 1
	signal randomFlag: std_logic := '0';
	signal randomByte: unsigned(7 downto 0) := (others => '0');

	-- RS232 transfer
	constant max_counter: natural := CLOCK_FREQUENCY / BAUDRATE;
	type state_type is (
		wait_for_data,
		send_start_bit,
		send_bits,
		send_stop_bit);
	signal state: state_type := wait_for_data;
	signal baudrate_counter: natural range 0 to max_counter := 0;
	signal bit_counter: natural range 0 to 7 := 0;
	signal shift_register: unsigned(7 downto 0) := (others => '0');
	signal tx: std_logic := '0';

begin

	process(CLOCK_50)
	begin
		if rising_edge(CLOCK_50) then
			-- latch random input
			randomLatch <= GPIO_2(0);
			randomLatch2 <= randomLatch;
			
			-- control output
			GPIO_2(2) <= randomLatch2;
			
			-- toggle randomFlag with max speed while random input is 1
			if randomLatch2 = '1' then
				randomFlag <= not randomFlag;
			end if;

			-- sample randomFlag with 150 kHz
			if counterSampler < CYCLES_SAMPLER then
				counterSampler <= counterSampler + 1;
			else
				counterSampler <= 0;
				randomByte <= randomByte(6 downto 0) & randomFlag;
			end if;
			
			-- send next byte
			case state is
				when wait_for_data =>
					baudrate_counter <= max_counter - 1;
					tx <= '0';
					shift_register <= randomByte;
					state <= send_start_bit;
				when send_start_bit =>
					if baudrate_counter = 0 then
						state <= send_bits;
						baudrate_counter <= max_counter - 1;
						tx <= shift_register(0);
						bit_counter <= 7;
					else
						baudrate_counter <= baudrate_counter - 1;
					end if;
				when send_bits =>
					if baudrate_counter = 0 then
						if bit_counter = 0 then
							state <= send_stop_bit;
							tx <= '1';
						else
							tx <= shift_register(1);
							shift_register <= shift_right(shift_register, 1);
							bit_counter <= bit_counter - 1;
						end if;
						baudrate_counter <= max_counter - 1;
					else
						baudrate_counter <= baudrate_counter - 1;
					end if;
				when send_stop_bit =>
					if baudrate_counter = 0 then
						state <= wait_for_data;
					else
						baudrate_counter <= baudrate_counter - 1;
					end if;
			end case;
			
			-- RS232 tx output
			GPIO_2(4) <= tx;

		end if;
	end process;

end architecture;
