----------------------------------------------------------------------------------
-- Company: 
-- Engineer: David Makowka
-- 
-- Create Date: 11/11/2019 09:01:40 PM
-- Design Name: 
-- Module Name: transmitter_vhdl - 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.numeric_std.all;

entity transmitter_vhdl is
    Port ( -- INPUTS
           clk              : in STD_LOGIC;
           reset            : in STD_LOGIC;
           transmit         : in STD_LOGIC;
           digit_1          : in STD_LOGIC_VECTOR (3 downto 0);
           digit_2          : in STD_LOGIC_VECTOR (3 downto 0);
           digit_3          : in STD_LOGIC_VECTOR (3 downto 0);
           digit_4          : in STD_LOGIC_VECTOR (3 downto 0);
           digit_5          : in STD_LOGIC_VECTOR (3 downto 0);
           -- OUTPUTS
           TxD              : out STD_LOGIC);
end transmitter_vhdl;


architecture Behavioral of transmitter_vhdl is

    -- COUNTERS --
    signal baudRateCounter      : natural range 0 to 10416;--std_logic_vector(13 downto 0);
    signal bitCounter           : natural range 0 to 15;--std_logic_vector(3 downto 0);
    signal digitCounter         : natural range 0 to 7;
    
    -- STATE MACHINE S --
    signal state                : std_logic;
    signal nextState            : std_logic;
    
    -- STATE MACHINE 2 STATES --
    signal state_2              : std_logic_vector(2 downto 0) := "000";
    signal nextState_2          : std_logic_vector(2 downto 0);
    signal change_digit         : std_logic;
    signal auto_transmit        : std_logic;
    
    -- DATA FLOW CONTROL --
    signal rightShiftRegister   : std_logic_vector(9 downto 0);
    signal shift                : std_logic;
    signal load                 : std_logic;
    signal clear                : std_logic;
             
    -- CONVERTING NUMBER TO ASCII CODE
    signal digit                : std_logic_vector(3 downto 0);
    signal ascii_code           : std_logic_vector(7 downto 0);

    signal s_transmit           : std_logic;
    
begin

    with digit select ascii_code <=
        "00110000" when "0000",
        "00110001" when "0001",
        "00110010" when "0010",
        "00110011" when "0011",
        "00110100" when "0100",
        "00110101" when "0101",
        "00110110" when "0110",
        "00110111" when "0111",
        "00111000" when "1000",
        "00111001" when "1001",
        "00111010" when "1010",
        "01000000" when "1011", -- zavinac @
        "00000000" when others;
	
    process(clk, reset)
    begin
        if (rising_edge(clk)) then
            if (reset = '1') then
                digit           <= "0000";
                auto_transmit   <= '0';
                nextState_2     <= "000";
            else
                case state_2 is
                    when "000" => 
                        digit           <= digit_5;
                        auto_transmit   <= '1';
                        nextState_2     <= "001";
                    -----------------------------------------------------------------------
                    when "001" => 
                        digit           <= digit_4;
                        auto_transmit   <= '1';
                        nextState_2     <= "010";
                    -----------------------------------------------------------------------
                    when "010" => 
                        digit           <= digit_3;
                        auto_transmit   <= '1';
                        nextState_2     <= "011";
                    -----------------------------------------------------------------------
                    when "011" => 
                        digit           <= digit_2;
                        auto_transmit   <= '1';
                        nextState_2     <= "100";
                    -----------------------------------------------------------------------
                    when "100" => 
                        digit           <= digit_1;
                        auto_transmit   <= '1';
                        nextState_2     <= "101";
                    -----------------------------------------------------------------------
                    when "101" => 
                        digit           <= "1011";
                        auto_transmit   <= '0';
                        nextState_2     <= "000";
                    -----------------------------------------------------------------------
                    when others =>
                        digit <= "0000";
                    end case;
                end if;
        end if;
    end process;

    process(clk)
    begin
        --this state machine executes every clock tick
        --it increments counter, which determines for how long is one bit exposed to serial communication line
        if (rising_edge(clk)) then
            if (reset = '1') then
                state               <= '0';
                baudRateCounter     <=  0;
                bitCounter          <=  0;
                digitCounter        <=  0;
            else
                baudRateCounter <= baudRateCounter + 1;
                --this block contains operation, that needs to happen only every 10415 clock ticks
                --
                if (baudRateCounter >= 10415) then
                    state                   <= nextState;
                    baudRateCounter         <= 0;
                    
                    -- CHANGE DIGIT
                    if (change_digit = '1') then
                        state_2             <= nextState_2;                         --changes to next digit
                    end if;
                    
                     -- ASSEMBLY START BIT, DATA AND STOP BIT
                    if (load = '1') then
                        rightShiftRegister  <= '1' & ascii_code & '0';
                    end if;
                    
                    -- CLEAR BIT COUNTER
                    if (clear = '1') then
                        bitCounter <= 0;
                    end if;
                    
                    -- SEND DATA ONE BY ONE STARTING LSB
                    if (shift = '1') then
                        rightShiftRegister  <= std_logic_vector(shift_right(unsigned(rightShiftRegister), 1));
                        bitCounter          <= bitCounter + 1;
                    end if;
                    
                end if;
            end if;
        end if;
    end process;

    process(clk, reset)
    begin
        --this state machine executes every clock tick
        --its state can change every 10415 clock ticks - meaning it can change only when a particullar bit is fully sent
        --it operates based on TRANSMIT signal and BIT_COUNTER (indicates that all bits were send) value
        
        --1. this state machine sends actual data to output port
        --2. it also send commands to clear bit counter, keep shifting data and load data
        if (rising_edge(clk)) then            
           
           if (transmit = '1') then
                s_transmit <= '1';
           end if;
           
           --load         <= '0'; 
           --shift        <= '0';
           --clear        <= '0';
           --TxD          <= '1';
           
           case (state) is
                -- IDLE STATE
                when '0' =>------------------------------------------------------------------------------------------------------
                    -- START TRANSMITTING WHEN TRANSMIT IS ENABLED
                    --                  OR
                    -- KEEP TRANSMITTING IF THE SEQUENCE (ALL DIGITS) IS NOT FULLY SEND
                    if (s_transmit = '1' OR auto_transmit = '1') then
                        nextState       <= '1';
                        load            <= '1';
                        shift           <= '0';
                        clear           <= '0';
                        change_digit    <= '0';
                        TxD             <= '1';
                    else
                        nextState       <= '0';
                        load            <= '0';
                        shift           <= '0';
                        clear           <= '0';
                        change_digit    <= '0';
                        TxD             <= '1';
                    end if;
                 -- TRANSMITTING STATE
                 when '1' =>-----------------------------------------------------------------------------------------------------
                    -- ALL BITS WERE SEND
                    if (bitcounter >= 10) then
                        nextState       <= '0';                       --sets this state machine to IDLE
                        load            <= '0';
                        shift           <= '0';
                        clear           <= '1';                       --clears bitCounter
                        change_digit    <= '1';
                        TxD             <= '1';
                        s_transmit      <= '0';
                    -- THERE ARE STILL SOME BITS TO BE SENT
                    else
                        nextState       <= '1';                       --keep transmitting
                        load            <= '0';
                        shift           <= '1';                       --keep shifting allowed
                        clear           <= '0';
                        change_digit    <= '0';
                        TxD             <= rightShiftRegister(0);     --send one bit
                        s_transmit      <= '0';
                        
                    end if;
                when others => nextState <= '0';
            end case;
        end if;
    end process;

end Behavioral;
