-- altera vhdl_input_version vhdl_2008
-- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html)

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.rtps_package.all;
use work.rtps_config_package.all;
use work.ros_package.all;

entity TEMPLATE_pub is
    generic (
        LITTLE_ENDIAN   : std_logic := '0'
    );
    port (
        -- SYSTEM
        clk                         : in std_logic;
        reset                       : in std_logic;
        -- FROM DDS WRITER
        start_dds                   : out std_logic;
        ack_dds                     : in std_logic;
        opcode_dds                  : out DDS_WRITER_OPCODE_TYPE;
        instance_handle_in_dds      : out INSTANCE_HANDLE_TYPE;
        source_ts_dds               : out TIME_TYPE;
        max_wait_dds                : out DURATION_TYPE;
        done_dds                    : in std_logic;
        return_code_dds             : in std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        instance_handle_out_dds     : in INSTANCE_HANDLE_TYPE;
        valid_out_dds               : out std_logic;
        ready_out_dds               : in std_logic;
        data_out_dds                : out std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_out_dds           : out std_logic;
        valid_in_dds                : in std_logic;
        ready_in_dds                : out std_logic;
        data_in_dds                 : in std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_in_dds            : in std_logic;
        -- Communication Status
        status_dds                  : in std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        
        -- TO USER ENTITY
        start_user                  : in std_logic;
        opcode_user                 : in ROS_TOPIC_OPCODE_TYPE;
        ack_user                    : out std_logic;
        
        -- ###GENERATED START###
            -- TYPE SPECIFIC PORTS
        -- ###GENERATED END###
        
        done_user                   : out std_logic;
        return_code_user            : out std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0)
    );
end entity;

architecture arch of TEMPLATE_pub is
    
    --*****TYPE DECLARATION*****
    -- FSM states. Explained below in detail
    type STAGE_TYPE is (IDLE,INITIATE_WRITE,WRITE_PAYLOAD_HEADER,PUSH,ALIGN_STREAM,ENCODE_PAYLOAD,WAIT_FOR_WRITER,RETURN_ROS);
    -- ###GENERATED START###
    type ENCODE_STAGE_TYPE is (TODO);
    -- ###GENERATED END###
    
    -- *MAIN PROCESS*
    signal stage, stage_next : STAGE_TYPE;
    signal cnt, cnt_next : natural range 0 to 5;
    signal align_offset, align_offset_next  : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0);
    signal align_op, align_op_next : std_logic;
    signal target_align, target_align_next : ALIGN_TYPE;
    signal data_out_latch, data_out_latch_next : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal abort_mem : std_logic;
    signal finalize_payload, finalize_payload_next : std_logic;
    signal return_code_latch, return_code_latch_next : std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
    signal encode_stage, encode_stage_next : ENCODE_STAGE_TYPE;
    -- ###GENERATED START###
        -- SIGNAL DECLARATION
    -- ###GENERATED END###
    
    
begin
    
    -- ###GENERATED START###
        -- MEMORY INSTANTIATIONS
    -- ###GENERATED END###
    
    -- PASSTHROUGH
    instance_handle_in_dds  <= HANDLE_NIL;
    source_ts_dds           <= TIME_INVALID;
    max_wait_dds            <= DURATION_ZERO;
    ready_in_dds            <= '0'; -- DDS Writer Input is unused
    -- ###GENERATED START###
        -- PORT SIGNAL CONNECTIONS
    -- ###GENERATED END###
    
    main_prc : process (all)
    begin
        -- DEFAULT
        stage_next                  <= stage;
        encode_stage_next           <= encode_stage;
        cnt_next                    <= cnt;
        align_offset_next           <= align_offset;
        align_op_next               <= align_op;
        target_align_next           <= target_align;
        data_out_latch_next         <= data_out_latch;
        finalize_payload_next       <= finalize_payload;
        return_code_latch_next      <= return_code_latch;
        abort_mem                   <= '0';
        start_dds                   <= '0';
        opcode_dds                  <= NOP;
        valid_out_dds               <= '0';
        last_word_out_dds           <= '0';
        ack_user                    <= '0';    
        done_user                   <= '0';
        return_code_user            <= ROS_RET_OK;
        data_out_dds                <= (others => '0');
        -- ###GENERATED START###
            -- DEFAULT SIGNAL ASSIGNMENTS
        -- ###GENERATED END###
        
        case (stage) is
            when IDLE =>
                if (start_user = '1') then
                    ack_user    <= '1';
                    case (opcode_user) is
                        when PUBLISH =>
                            stage_next  <= INITIATE_WRITE;
                        when others =>
                            return_code_latch_next  <= ROS_RET_UNSUPPORTED;
                            stage_next              <= RETURN_ROS;
                    end case;
                    -- RESET
                    abort_mem   <= '1';
                else
                    -- ###GENERATED START###
                        -- MEMORY SIGNAL CONNECTIONS
                    -- ###GENERATED END###
                end if;
            when RETURN_ROS =>
                done_user           <= '1';
                return_code_user    <= return_code_latch;
                
                -- DONE
                stage_next  <= IDLE;
            when INITIATE_WRITE =>
                start_dds   <= '1';
                opcode_dds  <= WRITE;
                
                if (ack_dds = '1') then
                    stage_next  <= WRITE_PAYLOAD_HEADER;
                end if;
            
            when WRITE_PAYLOAD_HEADER =>
                valid_out_dds   <= '1';
                if (LITTLE_ENDIAN = '0') then
                    data_out_dds    <= CDR_BE & x"0000";
                else
                    data_out_dds    <= CDR_LE & x"0000";
                end if;
                -- Output Guard
                if (ready_out_dds = '1') then
                    stage_next          <= ENCODE_PAYLOAD;
                    -- Reset 
                    align_offset_next   <= (others => '0');
                    data_out_latch_next <= (others => '0');
                    -- ###GENERATED START###
                    encode_stage_next   <= TODO;
                    -- ###GENERATED END###
                end if;
            when PUSH =>
                -- Mark Last Word
                if (finalize_payload = '1') then
                    last_word_out_dds   <= '1';
                end if;
                
                valid_out_dds   <= '1';
                data_out_dds    <= data_out_latch;
                -- Output Guard
                if (ready_out_dds = '1') then
                    -- NOTE: Ensures all padding is zero.
                    data_out_latch_next <= (others => '0');
                    -- Alignment Operation in process
                    if (align_op = '1') then
                        stage_next      <= ALIGN_STREAM;
                        -- Reset
                        align_op_next   <= '0';
                    -- DONE
                    elsif (finalize_payload = '1') then
                        finalize_payload_next   <= '0';
                        stage_next              <= WAIT_FOR_WRITER;
                    else
                        stage_next  <= ENCODE_PAYLOAD;
                    end if;
                end if;
            when ALIGN_STREAM =>
                -- Target Stream Alignment reached
                if (check_align(align_offset, target_align)) then
                    -- DONE
                    stage_next  <= ENCODE_PAYLOAD;
                else
                    align_offset_next   <= align_offset + 1;
                    -- Need to push Word
                    if (align_offset(1 downto 0) = "11") then
                        align_op_next   <= '1';
                        stage_next      <= PUSH;
                    end if;
                end if;
            when ENCODE_PAYLOAD =>
                case (encode_stage) is
                    -- ###GENERATED START###
                    when TODO =>
                    -- ###GENERATED END###
                    when others =>
                        null;
                end case;
            when WAIT_FOR_WRITER =>
                if (done_dds = '1') then
                    case (return_code_dds) is
                        when RETCODE_OK =>
                            return_code_latch_next  <= ROS_RET_OK;
                            stage_next              <= RETURN_ROS;
                        when others =>
                            return_code_latch_next  <= ROS_RET_ERROR;
                            stage_next              <= RETURN_ROS;
                    end case;
                end if;
        end case;
    end process;
    
    sync_prc : process(clk)
    begin
        if rising_edge(clk) then
            if (reset = '1') then
                stage               <= IDLE;
                encode_stage        <= TODO;
                target_align        <= ALIGN_1;
                return_code_latch   <= ROS_RET_OK;
                cnt                 <= 0;
                finalize_payload    <= '0';
                align_op            <= '0';
                align_offset        <= (others => '0');
                data_out_latch      <= (others => '0');
                -- ###GENERATED START###
                    -- RESET SYNC SIGNAL VALUE
                -- ###GENERATED END###
            else
                stage               <= stage_next;
                encode_stage        <= encode_stage_next;
                target_align        <= target_align_next;
                return_code_latch   <= return_code_latch_next;
                cnt                 <= cnt_next;
                finalize_payload    <= finalize_payload_next;
                align_op            <= align_op_next;
                align_offset        <= align_offset_next;
                data_out_latch      <= data_out_latch_next;
                -- ###GENERATED START###
                    -- SYNC SIGNALS                
                -- ###GENERATED END###
            end if;
        end if;
    end process;
    
end architecture;