Implement ROS glue logic & ROS discovery data

All the necessary "glue" logic to convert ROS Data to a form that the
DDS/RTPS back-end can use is implemented in packages.
The ROS Node discovery information is statically generated in packages
(similar to the RTPS Participant Data), and a special dds writer is
implemented (ros_static_discovery_writer) that has this static data as
its only payload sample.
Some definitions are moved out of rtps_config_package to prevent
circular package dependency.
This commit is contained in:
Greek 2022-01-25 18:57:43 +01:00
parent 2d3c5cf896
commit b5741dc9ae
15 changed files with 672 additions and 51 deletions

View File

@ -71,14 +71,14 @@ architecture testbench of L2_Type1_test1 is
-- because I cannot use a qualified expression to define an enumeration literal (and direct type casting cannot be done because
-- the types are not closely related). So I have to do define explicit type conversions between the types...
function to_Lib2(input : DDS_WRITER_OPCODE_TYPE) return Testbench_Lib2.rtps_config_package.DDS_WRITER_OPCODE_TYPE is
function to_Lib2(input : DDS_WRITER_OPCODE_TYPE) return Testbench_Lib2.rtps_package.DDS_WRITER_OPCODE_TYPE is
begin
return Testbench_Lib2.rtps_config_package.DDS_WRITER_OPCODE_TYPE'VAL(DDS_WRITER_OPCODE_TYPE'POS(input));
return Testbench_Lib2.rtps_package.DDS_WRITER_OPCODE_TYPE'VAL(DDS_WRITER_OPCODE_TYPE'POS(input));
end function;
function to_Lib3(input : DDS_READER_OPCODE_TYPE) return Testbench_Lib3.rtps_config_package.DDS_READER_OPCODE_TYPE is
function to_Lib3(input : DDS_READER_OPCODE_TYPE) return Testbench_Lib3.rtps_package.DDS_READER_OPCODE_TYPE is
begin
return Testbench_Lib3.rtps_config_package.DDS_READER_OPCODE_TYPE'VAL(DDS_READER_OPCODE_TYPE'POS(input));
return Testbench_Lib3.rtps_package.DDS_READER_OPCODE_TYPE'VAL(DDS_READER_OPCODE_TYPE'POS(input));
end function;
begin

View File

@ -71,14 +71,14 @@ architecture testbench of L2_Type1_test2 is
-- because I cannot use a qualified expression to define an enumeration literal (and direct type casting cannot be done because
-- the types are not closely related). So I have to do define explicit type conversions between the types...
function to_Lib5(input : DDS_READER_OPCODE_TYPE) return Testbench_Lib5.rtps_config_package.DDS_READER_OPCODE_TYPE is
function to_Lib5(input : DDS_READER_OPCODE_TYPE) return Testbench_Lib5.rtps_package.DDS_READER_OPCODE_TYPE is
begin
return Testbench_Lib5.rtps_config_package.DDS_READER_OPCODE_TYPE'VAL(DDS_READER_OPCODE_TYPE'POS(input));
return Testbench_Lib5.rtps_package.DDS_READER_OPCODE_TYPE'VAL(DDS_READER_OPCODE_TYPE'POS(input));
end function;
function to_Lib5(input : DDS_WRITER_OPCODE_TYPE) return Testbench_Lib5.rtps_config_package.DDS_WRITER_OPCODE_TYPE is
function to_Lib5(input : DDS_WRITER_OPCODE_TYPE) return Testbench_Lib5.rtps_package.DDS_WRITER_OPCODE_TYPE is
begin
return Testbench_Lib5.rtps_config_package.DDS_WRITER_OPCODE_TYPE'VAL(DDS_WRITER_OPCODE_TYPE'POS(input));
return Testbench_Lib5.rtps_package.DDS_WRITER_OPCODE_TYPE'VAL(DDS_WRITER_OPCODE_TYPE'POS(input));
end function;
begin

21
src/ros2/ROS_IDL.txt Normal file
View File

@ -0,0 +1,21 @@
SERVICE
#######
GENERAL
=======
The Service VHDL generation closely follows the general RTPS IDL interface generation.
For each Service (i.e. .srv File) two files are generated, a server and a client file.
Each file contains both encoding and decoding functionality (similar to the key_holder files).
The code generation follows the normal code generation for encoding and decoding with following changes:
* Encoding and Decoding stages get a "RQ_"or "RR_" prepended to the <NAME> to differentiate between
Request and Response message members, respectively.
e.g. GET_A -> GET_RQ_A, WRITE_SUM -> WRITE_RR_SUM
* Similar to the previous point, the <SERVICENAME>_package differentiates the MAX_* sizes of the Request
and Response message members.
e.g. MAX_A_SIZE -> MAX_RQ_A_SIZE, MAX_SUM_SIZE -> MAX_RR_SUM_SIZE
* The <SERVICENAME>_package calculates both a maximum request and response message size, named
MAX_<SERVICENAME>_RQ_SIZE and MAX_<SERVICENAME>_RR_SIZE, respectively.
The maximum includes the service overhead bytes that are contained in the DDS Payloads. The constant
SERVICE_OVERHEAD_BYTES from ros_package gives this overhead bytes.

View File

@ -0,0 +1,78 @@
-- 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;
-- TODO: Move gen_user_string out of rtps_package?
use work.rtps_package.all; -- gen_user_string
package ros_config is
-- IPv4 Address of ROS System [Default 192.168.0.128]
constant ROS_ADDRESS : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := x"C0A80080";
-- Random Key used to generate GUIDs
constant ROS_RAND_KEY : std_logic_vector(47 downto 0) := x"97917E0BA8CF";
constant NUM_NODES : natural := 1;
constant ROS_NODES : ROS_NODE_ARRAY_TYPE(0 to NUM_NODES-1) := (
0 => (
name => gen_user_string("TestNode"),
namespace => gen_user_string(""),
domain_id => 1,
NUM_PUBS => 1,
NUM_SUBS => 1,
NUM_SERVICES => 1,
NUM_ACTIONS => 0
)
);
constant NUM_PUBS : natural := get_num_pubs(ROS_NODES);
constant NUM_SUBS : natural := get_num_subs(ROS_NODES);
constant NUM_SERVICES : natural := get_num_services(ROS_NODES);
constant NUM_ACTIONS : natural := get_num_actions(ROS_NODES);
constant ROS_PUBLICATIONS : ROS_TOPIC_ARRAY_TYPE(0 to NUM_PUBS-1) := (
0 => (
node_id => 0,
TOPICNAME => gen_user_string("Topic1"),
TYPENAME => gen_user_string("Type1"),
QOS => ROS_QOS_PROFILE_DEFAULT,
MAX_SIZE => 10
)
);
constant ROS_SUBSCRIPTIONS : ROS_TOPIC_ARRAY_TYPE(0 to NUM_SUBS-1) := (
0 => (
node_id => 0,
TOPICNAME => gen_user_string("Topic2"),
TYPENAME => gen_user_string("Type2"),
QOS => ROS_QOS_PROFILE_DEFAULT,
MAX_SIZE => 10
)
);
constant ROS_SERVICES : ROS_SERVICE_ARRAY_TYPE(0 to NUM_SERVICES-1) := (
0 => (
node_id => 0,
SERVICENAME => gen_user_string("Service1"),
TYPENAME => gen_user_string("Type3"),
QOS => ROS_QOS_PROFILE_SERVICES_DEFAULT,
MAX_RQ_SIZE => 10,
MAX_RR_SIZE => 10,
is_client => FALSE
)
);
-- TODO
constant ROS_ACTIONS : ROS_ACTION_ARRAY_TYPE(0 to NUM_ACTIONS-1) := (
others => (
node_id => 0
)
);
-- Defines sensible RTPS timings for simulation
constant SIMULATION_TIMING : boolean := FALSE;
end package;

View File

@ -0,0 +1,195 @@
-- 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.ros_package.all;
use work.ros_config.all;
package user_config is
--*****USER CONFIG*****
-- Period of system clock
constant CLOCK_PERIOD : time := 50 ns;
-- Maximum number of supported remote Participants (Affects generated Memory Size)
constant MAX_REMOTE_PARTICIPANTS : natural := 50;
-- Maximum number of supported remote Endpoints (Affects generated Memory Size)
constant MAX_REMOTE_ENDPOINTS : natural := 50;
-- If Multicast Locators should be used instead of Unicast Locators
constant PREFER_MULTICAST_LOCATORS : boolean := FALSE;
-- Unicast IPv4 Address used by all RTPS Entities [Default 192.168.0.128]
constant DEFAULT_IPv4_ADDRESS : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := ROS_ADDRESS;
-- Number of RTPS Writer Endpoints
constant NUM_WRITERS : natural := NUM_PUBS + NUM_SERVICES + 1;
-- Number of RTPS Reader Endpoints
constant NUM_READERS : natural := NUM_SUBS + NUM_SERVICES;
-- Number of RTPS Endpoints (Do not modify)
constant NUM_ENDPOINTS : natural := NUM_READERS+NUM_WRITERS;
-- PB Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_PB : natural := 7400;
-- DG Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_DG : natural := 250;
-- PG Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_PG : natural := 2;
-- D0 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D0 : natural := 0;
-- D1 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D1 : natural := 10;
-- D2 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D2 : natural := 1;
-- D3 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D3 : natural := 11;
-- MAC Address of underlying network stack (Used to generate GUIDs)
constant MAC_ADDRESS : std_logic_vector(47 downto 0) := ROS_RAND_KEY;
-- Domain ID
constant USER_DOMAIN_ID : natural := get_domain_id(ROS_NODES);
-- Domain TAG
constant USER_DOMAIN_TAG : USER_STRING_TYPE := gen_user_string("");
-- *TIMING CHARACTERISTICS*
-- Timing Characteristics for Participant
constant PARTICIPANT_ANNOUNCEMENT_PERIOD : DURATION_TYPE;
constant PARTICIPANT_LEASE_DURATION : DURATION_TYPE;
-- Denotes how much faster then the deadline/period we schedule in order to account for transport delay.
constant DURATION_DELTA : DURATION_TYPE;
-- Timing Characteristics for built-in Endpoints (Discovery Module)
constant PARTICIPANT_HEARTBEAT_PERIOD : DURATION_TYPE;
constant PARTICIPANT_HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE;
constant PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE;
constant PARTICIPANT_ACKNACK_RESPONSE_DELAY : DURATION_TYPE;
constant PARTICIPANT_ACKNACK_SUPPRESSION_DELAY : DURATION_TYPE;
-- *ENDPOINT CONFIG*
constant ENDPOINT_CONFIG : CONFIG_ARRAY_TYPE(0 to NUM_ENDPOINTS-1); -- Deferred to Package Body
-- Set to TRUE for Simulation Testing (Extra Code generated)
constant SIMULATION_FLAG : boolean := SIMULATION_TIMING;
end package;
package body user_config is
function duration_mux(a : DURATION_TYPE; b : DURATION_TYPE; sel : boolean) return DURATION_TYPE is
begin
if (sel) then
return a;
else
return b;
end if;
end function;
constant PARTICIPANT_ANNOUNCEMENT_PERIOD : DURATION_TYPE := duration_mux(gen_duration(50 us), gen_duration(30 sec), SIMULATION_TIMING);
constant PARTICIPANT_LEASE_DURATION : DURATION_TYPE := duration_mux(DEFAULT_PARTICIPANT_LEASE_DURATION, DEFAULT_PARTICIPANT_LEASE_DURATION, SIMULATION_TIMING);
constant DURATION_DELTA : DURATION_TYPE := duration_mux(gen_duration(50 ns), gen_duration(100 ms), SIMULATION_TIMING);
constant PARTICIPANT_HEARTBEAT_PERIOD : DURATION_TYPE := duration_mux(gen_duration(40 us), gen_duration(1 sec), SIMULATION_TIMING);
constant PARTICIPANT_HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE := duration_mux(gen_duration(500 ns), gen_duration(500 ms), SIMULATION_TIMING);
constant PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE := duration_mux(gen_duration(100 ns), gen_duration(0 ms), SIMULATION_TIMING);
constant PARTICIPANT_ACKNACK_RESPONSE_DELAY : DURATION_TYPE := duration_mux(gen_duration(500 ns), gen_duration(200 ms), SIMULATION_TIMING);
constant PARTICIPANT_ACKNACK_SUPPRESSION_DELAY : DURATION_TYPE := duration_mux(gen_duration(100 ns), gen_duration(0 ms), SIMULATION_TIMING);
procedure set_sim_timing (ref : inout CONFIG_TYPE; sel : in boolean) is
begin
if (sel) then
ref.HEARTBEAT_PERIOD := gen_duration(10 us);
ref.HEARTBEAT_RESPONSE_DELAY := gen_duration(500 ns);
ref.HEARTBEAT_SUPPRESSION_DELAY := gen_duration(100 ns);
ref.ACKNACK_RESPONSE_DELAY := gen_duration(500 ns);
ref.ACKNACK_SUPPRESSION_DELAY := gen_duration(100 ns);
end if;
end procedure;
-- NOTE: This function sets also the
function gen_config return CONFIG_ARRAY_TYPE is
variable ret : CONFIG_ARRAY_TYPE(0 to NUM_ENDPOINTS-1);
variable index : natural;
variable tmp : USER_STRING_TYPE;
begin
check_node_mapping(ROS_NODES, ROS_PUBLICATIONS, ROS_SUBSCRIPTIONS, ROS_SERVICES, ROS_ACTIONS);
index := 0;
-- SUBSCRIPTIONS
for i in 0 to ROS_SUBSCRIPTIONS'length-1 loop
ret(index) := DEFAULT_READER_CONFIG;
set_from_qos_profile(ROS_SUBSCRIPTIONS(i).QOS, ret(index));
set_sim_timing(ret(index),SIMULATION_TIMING);
ret(index).TYPENAME := ROS_SUBSCRIPTIONS(i).TYPENAME;
ret(index).MAX_PAYLOAD_SIZE := ROS_SUBSCRIPTIONS(i).MAX_SIZE;
tmp := gen_fqn(ROS_NODES(ROS_SUBSCRIPTIONS(i).node_id).namespace, ROS_NODES(ROS_SUBSCRIPTIONS(i).node_id).name, ROS_SUBSCRIPTIONS(i).TOPICNAME);
if (not ROS_SUBSCRIPTIONS(i).QOS.AVOID_ROS_NAMESPACE_CONVENTION) then
ret(index).TOPICNAME := concat("rt",tmp);
else
ret(index).TOPICNAME := tmp;
end if;
index := index + 1;
end loop;
-- SERVICE SUBS
for i in 0 to ROS_SERVICES'length-1 loop
ret(index) := DEFAULT_READER_CONFIG;
set_from_qos_profile(ROS_SERVICES(i).QOS, ret(index));
set_sim_timing(ret(index),SIMULATION_TIMING);
ret(index).TYPENAME := ROS_SERVICES(i).TYPENAME;
tmp := gen_fqn(ROS_NODES(ROS_SERVICES(i).node_id).namespace, ROS_NODES(ROS_SERVICES(i).node_id).name, ROS_SERVICES(i).SERVICENAME);
if (ROS_SERVICES(i).is_client) then
ret(index).TOPICNAME := concat("rr",concat(tmp,"Response"));
ret(index).MAX_PAYLOAD_SIZE := ROS_SERVICES(i).MAX_RR_SIZE;
else
ret(index).TOPICNAME := concat("rq",concat(tmp,"Request"));
ret(index).MAX_PAYLOAD_SIZE := ROS_SERVICES(i).MAX_RQ_SIZE;
end if;
index := index + 1;
end loop;
-- PUBLICATIONS
for i in 0 to ROS_PUBLICATIONS'length-1 loop
ret(index) := DEFAULT_WRITER_CONFIG;
set_from_qos_profile(ROS_PUBLICATIONS(i).QOS, ret(index));
set_sim_timing(ret(index),SIMULATION_TIMING);
ret(index).TYPENAME := ROS_PUBLICATIONS(i).TYPENAME;
ret(index).MAX_PAYLOAD_SIZE := ROS_PUBLICATIONS(i).MAX_SIZE;
tmp := gen_fqn(ROS_NODES(ROS_PUBLICATIONS(i).node_id).namespace, ROS_NODES(ROS_PUBLICATIONS(i).node_id).name, ROS_PUBLICATIONS(i).TOPICNAME);
if (not ROS_PUBLICATIONS(i).QOS.AVOID_ROS_NAMESPACE_CONVENTION) then
ret(index).TOPICNAME := concat("rt",tmp);
else
ret(index).TOPICNAME := tmp;
end if;
index := index + 1;
end loop;
-- SERVICE PUBS
for i in 0 to ROS_SERVICES'length-1 loop
ret(index) := DEFAULT_WRITER_CONFIG;
set_from_qos_profile(ROS_SERVICES(i).QOS, ret(index));
set_sim_timing(ret(index),SIMULATION_TIMING);
ret(index).TYPENAME := ROS_SERVICES(i).TYPENAME;
tmp := gen_fqn(ROS_NODES(ROS_SERVICES(i).node_id).namespace, ROS_NODES(ROS_SERVICES(i).node_id).name, ROS_SERVICES(i).SERVICENAME);
if (ROS_SERVICES(i).is_client) then
ret(index).TOPICNAME := concat("rq",concat(tmp,"Request"));
ret(index).MAX_PAYLOAD_SIZE := ROS_SERVICES(i).MAX_RQ_SIZE;
else
ret(index).TOPICNAME := concat("rr",concat(tmp,"Response"));
ret(index).MAX_PAYLOAD_SIZE := ROS_SERVICES(i).MAX_RR_SIZE;
end if;
index := index + 1;
end loop;
-- ROS DISCOVERY PUB
ret(index) := DEFAULT_WRITER_CONFIG;
set_sim_timing(ret(index),SIMULATION_TIMING);
ret(index).RELIABILITY_QOS := RELIABLE_RELIABILITY_QOS;
ret(index).DURABILITY_QOS := TRANSIENT_LOCAL_DURABILITY_QOS;
ret(index).HISTORY_QOS := KEEP_LAST_HISTORY_QOS;
ret(index).HISTORY_DEPTH := std_logic_vector(to_unsigned(1, CDR_LONG_WIDTH));
ret(index).MAX_SAMPLES := std_logic_vector(to_unsigned(1, CDR_LONG_WIDTH));
ret(index).MAX_INSTANCES := std_logic_vector(to_unsigned(1, CDR_LONG_WIDTH));
ret(index).MAX_SAMPLES_PER_INSTANCE := std_logic_vector(to_unsigned(1, CDR_LONG_WIDTH));
ret(index).TOPICNAME := gen_user_string("ros_discovery_info");
ret(index).TYPENAME := gen_user_string("rmw_dds_common::msg::dds_::ParticipantEntitiesInfo_");
return ret;
end function;
constant ENDPOINT_CONFIG : CONFIG_ARRAY_TYPE(0 to NUM_ENDPOINTS-1) := gen_config;
end package body;

View File

@ -94,8 +94,8 @@ architecture arch of AddTwoInts_srv_client is
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE,RETURN_ROS,INITIATE_READ,WAIT_FOR_READER,WAIT_FOR_WRITER,WAIT_FOR_DATA,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,INITIATE_WRITE,WRITE_PAYLOAD_HEADER,PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD);
-- ###GENERATED START###
type ENCODE_STAGE_TYPE is (WRITE_RID_WGUID,WRITE_RID_SN,WRITE_A,WRITE_B);
type DECODE_STAGE_TYPE is (GET_RID_WGUID,GET_RID_SN,GET_OPTIONAL_HEADER,GET_SUM);
type ENCODE_STAGE_TYPE is (WRITE_RID_WGUID,WRITE_RID_SN,WRITE_RQ_A,WRITE_RQ_B);
type DECODE_STAGE_TYPE is (GET_RID_WGUID,GET_RID_SN,GET_OPTIONAL_HEADER,GET_RR_SUM);
-- ###GENERATED END###
-- *MAIN PROCESS*
@ -397,7 +397,7 @@ begin
service_info_sig_next.request_id.sequence_number <= to_double_word(unsigned(endian_swap(endian_flag, dw_latch)));
align_offset_next <= align_offset + 8;
-- ###GENERATED START###
decode_stage_next <= GET_SUM;
decode_stage_next <= GET_RR_SUM;
cnt_next <= 0;
-- ###GENERATED END###
when others =>
@ -405,7 +405,7 @@ begin
end case;
end if;
-- ###GENERATED START###
when GET_SUM =>
when GET_RR_SUM =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
@ -604,14 +604,14 @@ begin
stage_next <= PUSH;
align_offset_next <= align_offset + 8;
-- ###GENERATED START###
encode_stage_next <= WRITE_A;
encode_stage_next <= WRITE_RQ_A;
cnt_next <= 0;
-- ###GENERATED END###
when others =>
end case;
end if;
-- ###GENERATED START###
when WRITE_A =>
when WRITE_RQ_A =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
@ -627,12 +627,12 @@ begin
stage_next <= PUSH;
align_offset_next <= align_offset + 8;
encode_stage_next <= WRITE_B;
encode_stage_next <= WRITE_RQ_B;
cnt_next <= 0;
when others =>
end case;
end if;
when WRITE_B =>
when WRITE_RQ_B =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;

View File

@ -94,8 +94,8 @@ architecture arch of AddTwoInts_srv_server is
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE,RETURN_ROS,INITIATE_READ,WAIT_FOR_READER,WAIT_FOR_WRITER,WAIT_FOR_DATA,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,INITIATE_WRITE,WRITE_PAYLOAD_HEADER,PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD);
-- ###GENERATED START###
type ENCODE_STAGE_TYPE is (WRITE_RID_WGUID,WRITE_RID_SN,WRITE_SUM);
type DECODE_STAGE_TYPE is (GET_RID_WGUID,GET_RID_SN,GET_OPTIONAL_HEADER,GET_A,GET_B);
type ENCODE_STAGE_TYPE is (WRITE_RID_WGUID,WRITE_RID_SN,WRITE_RR_SUM);
type DECODE_STAGE_TYPE is (GET_RID_WGUID,GET_RID_SN,GET_OPTIONAL_HEADER,GET_RQ_A,GET_RQ_B);
-- ###GENERATED END###
-- *MAIN PROCESS*
@ -107,7 +107,7 @@ architecture arch of AddTwoInts_srv_server is
signal dw_latch, dw_latch_next : std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
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 tarGET_RQ_Align, tarGET_RQ_Align_next : ALIGN_TYPE;
signal data_in_latch, data_in_latch_next : std_logic_vector(WORD_WIDTH-1 downto 0);
signal optional, optional_next : std_logic;
signal data_out_latch, data_out_latch_next : std_logic_vector(WORD_WIDTH-1 downto 0);
@ -171,7 +171,7 @@ begin
last_word_in_latch_next <= last_word_in_latch;
decode_error_latch_next <= decode_error_latch;
align_offset_next <= align_offset;
target_align_next <= target_align;
tarGET_RQ_Align_next <= tarGET_RQ_Align;
data_out_latch_next <= data_out_latch;
finalize_payload_next <= finalize_payload;
optional_next <= optional;
@ -322,7 +322,7 @@ begin
end if;
when ALIGN_IN_STREAM =>
-- Target Stream Alignment reached
if (check_align(align_offset, target_align)) then
if (check_align(align_offset, tarGET_RQ_Align)) then
-- DONE
stage_next <= DECODE_PAYLOAD;
else
@ -348,7 +348,7 @@ begin
when GET_RID_WGUID =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_IN_STREAM;
else
case (cnt) is
@ -376,7 +376,7 @@ begin
when GET_RID_SN =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_IN_STREAM;
else
case (cnt) is
@ -395,7 +395,7 @@ begin
service_info_sig_next.request_id.sequence_number <= to_double_word(unsigned(endian_swap(endian_flag, dw_latch)));
align_offset_next <= align_offset + 8;
-- ###GENERATED START###
decode_stage_next <= GET_A;
decode_stage_next <= GET_RQ_A;
cnt_next <= 0;
-- ###GENERATED END###
when others =>
@ -403,10 +403,10 @@ begin
end case;
end if;
-- ###GENERATED START###
when GET_A =>
when GET_RQ_A =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_IN_STREAM;
else
case (cnt) is
@ -424,16 +424,16 @@ begin
when 2 =>
a_latch_next <= endian_swap(endian_flag, dw_latch);
align_offset_next <= align_offset + 8;
decode_stage_next <= GET_B;
decode_stage_next <= GET_RQ_B;
cnt_next <= 0;
when others =>
null;
end case;
end if;
when GET_B =>
when GET_RQ_B =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_IN_STREAM;
else
case (cnt) is
@ -461,7 +461,7 @@ begin
when GET_OPTIONAL_HEADER =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_4)) then
target_align_next <= ALIGN_4;
tarGET_RQ_Align_next <= ALIGN_4;
stage_next <= ALIGN_IN_STREAM;
else
case (cnt) is
@ -580,7 +580,7 @@ begin
end if;
when ALIGN_OUT_STREAM =>
-- Target Stream Alignment reached
if (check_align(align_offset, target_align)) then
if (check_align(align_offset, tarGET_RQ_Align)) then
-- DONE
stage_next <= ENCODE_PAYLOAD;
else
@ -596,7 +596,7 @@ begin
when WRITE_RID_WGUID =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_OUT_STREAM;
else
case (cnt) is
@ -616,7 +616,7 @@ begin
when WRITE_RID_SN =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_OUT_STREAM;
else
case (cnt) is
@ -629,17 +629,17 @@ begin
stage_next <= PUSH;
align_offset_next <= align_offset + 8;
-- ###GENERATED START###
encode_stage_next <= WRITE_SUM;
encode_stage_next <= WRITE_RR_SUM;
cnt_next <= 0;
-- ###GENERATED END###
when others =>
end case;
end if;
-- ###GENERATED START###
when WRITE_SUM =>
when WRITE_RR_SUM =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_8)) then
target_align_next <= ALIGN_8;
tarGET_RQ_Align_next <= ALIGN_8;
stage_next <= ALIGN_OUT_STREAM;
else
case (cnt) is
@ -693,7 +693,7 @@ begin
encode_stage <= WRITE_RID_WGUID;
decode_stage <= GET_RID_WGUID;
return_stage <= GET_RID_WGUID;
target_align <= ALIGN_1;
tarGET_RQ_Align <= ALIGN_1;
cnt <= 0;
endian_flag <= '0';
last_word_in_latch <= '0';
@ -718,7 +718,7 @@ begin
encode_stage <= encode_stage_next;
decode_stage <= decode_stage_next;
return_stage <= return_stage_next;
target_align <= target_align_next;
tarGET_RQ_Align <= tarGET_RQ_Align_next;
cnt <= cnt_next;
endian_flag <= endian_flag_next;
last_word_in_latch <= last_word_in_latch_next;

View File

@ -0,0 +1 @@
char[24] data

View File

@ -0,0 +1,4 @@
string<=256 node_namespace
string<=256 node_name
Gid[] reader_gid_seq
Gid[] writer_gid_seq

View File

@ -0,0 +1,2 @@
Gid gid
NodeEntitiesInfo[] node_entities_info_seq

View File

@ -0,0 +1,141 @@
-- 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.math_pkg.all;
use work.rtps_package.all;
use work.ros_package.all;
use work.ros_config.all;
use work.user_config.all;
use work.rtps_config_package.all;
package ros_config_package is
constant ENDPOINT_ROS_NODE_MAPPING : ENDPOINT_ROS_NODE_MAPPING_ARRAY_TYPE(0 to NUM_ENDPOINTS-1); -- Deferred to Package Body
constant ROS_DISCOVERY_DATA : OUTPUT_DATA_TYPE; --Deferred to package body
end package;
package body ros_config_package is
-- NOTE: This function has to mirror the behaviour of the 'gen_config' function of the user_config package
function gen_endpoint_node_mapping return ENDPOINT_ROS_NODE_MAPPING_ARRAY_TYPE is
variable ret : ENDPOINT_ROS_NODE_MAPPING_ARRAY_TYPE(0 to NUM_ENDPOINTS-1) := (others => 0);
variable index : natural;
begin
ret := (others => NUM_NODES);
index := 0;
-- SUBSCRIPTIONS
for i in 0 to ROS_SUBSCRIPTIONS'length-1 loop
ret(index) := ROS_SUBSCRIPTIONS(i).node_id;
index := index + 1;
end loop;
-- SERVICE SUBS
for i in 0 to ROS_SERVICES'length-1 loop
ret(index) := ROS_SERVICES(i).node_id;
index := index + 1;
end loop;
-- PUBLICATIONS
for i in 0 to ROS_PUBLICATIONS'length-1 loop
ret(index) := ROS_PUBLICATIONS(i).node_id;
index := index + 1;
end loop;
-- SERVICE PUBS
for i in 0 to ROS_SERVICES'length-1 loop
ret(index) := ROS_SERVICES(i).node_id;
index := index + 1;
end loop;
return ret;
end function;
constant ENDPOINT_ROS_NODE_MAPPING : ENDPOINT_ROS_NODE_MAPPING_ARRAY_TYPE(0 to NUM_ENDPOINTS-1) := gen_endpoint_node_mapping;
function gen_ros_discovery_data return OUTPUT_DATA_TYPE is
variable ret : OUTPUT_DATA_TYPE;
variable gid : GID_TYPE;
variable tmp : natural;
begin
ret.data := (others => (others => '0'));
ret.length := 0;
-- Sanity Check
if (NUM_NODES = 0) then
return ret;
end if;
-- Serialized Payload Header
ret.data(ret.length) := PL_CDR_BE & x"0000";
ret.length := ret.length + 1;
-- ParticipantEntitiesInfo.gid
gid := to_gid(to_guid(GUIDPREFIX,ENTITYID_PARTICIPANT));
for i in 0 to GID'length-1 loop
ret.data(ret.length) := gid(i);
ret.length := ret.length + 1;
end loop;
-- ParticipantEntitiesInfo.node_entities_info_seq [LENGTH]
ret.data(ret.length) := std_logic_vector(to_unsigned(NUM_NODES,WORD_WIDTH));
ret.length := ret.length + 1;
for i in 0 to NUM_NODES-1 loop
-- ParticipantEntitiesInfo.node_entities_info_seq[i].node_namespace
ret.data(ret.length) := std_logic_vector(to_unsigned(string_len(ROS_NODES(i).namespace),WORD_WIDTH));
ret.length := ret.length + 1;
for j in 0 to round_div(string_len(ROS_NODES(i).namespace),WORD_WIDTH/BYTE_WIDTH)-1 loop
ret.data(ret.length) := convert_string(ROS_NODES(i).namespace)(j);
ret.length := ret.length + 1;
end loop;
-- ParticipantEntitiesInfo.node_entities_info_seq[i].node_name
ret.data(ret.length) := std_logic_vector(to_unsigned(string_len(ROS_NODES(i).name),WORD_WIDTH));
ret.length := ret.length + 1;
for j in 0 to round_div(string_len(ROS_NODES(i).name),WORD_WIDTH/BYTE_WIDTH)-1 loop
ret.data(ret.length) := convert_string(ROS_NODES(i).name)(j);
ret.length := ret.length + 1;
end loop;
-- ParticipantEntitiesInfo.node_entities_info_seq[i].reader_gid_seq [LENGTH]
tmp := 0;
for j in 0 to NUM_READERS-1 loop
if (i = ENDPOINT_ROS_NODE_MAPPING(j)) then
tmp := tmp + 1;
end if;
end loop;
ret.data(ret.length) := std_logic_vector(to_unsigned(tmp,WORD_WIDTH));
ret.length := ret.length + 1;
-- ParticipantEntitiesInfo.node_entities_info_seq[i].reader_gid_seq[j]
for j in 0 to NUM_READERS-1 loop
if (i = ENDPOINT_ROS_NODE_MAPPING(j)) then
gid := to_gid(to_guid(GUIDPREFIX,ENTITYID(j)));
for k in 0 to GID'length-1 loop
ret.data(ret.length) := gid(k);
ret.length := ret.length + 1;
end loop;
end if;
end loop;
-- ParticipantEntitiesInfo.node_entities_info_seq[i].writer_gid_seq [LENGTH]
tmp := 0;
for j in NUM_READERS to NUM_ENDPOINTS-1 loop
if (i = ENDPOINT_ROS_NODE_MAPPING(j)) then
tmp := tmp + 1;
end if;
end loop;
ret.data(ret.length) := std_logic_vector(to_unsigned(tmp,WORD_WIDTH));
ret.length := ret.length + 1;
-- ParticipantEntitiesInfo.node_entities_info_seq[i].writer_gid_seq[j]
for j in NUM_READERS to NUM_ENDPOINTS-1 loop
if (i = ENDPOINT_ROS_NODE_MAPPING(j)) then
gid := to_gid(to_guid(GUIDPREFIX,ENTITYID(j)));
for k in 0 to GID'length-1 loop
ret.data(ret.length) := gid(k);
ret.length := ret.length + 1;
end loop;
end if;
end loop;
end loop;
return ret;
end function;
constant ROS_DISCOVERY_DATA : OUTPUT_DATA_TYPE := gen_ros_discovery_data;
end package body;

View File

@ -6,7 +6,6 @@ use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.rtps_package.all;
use work.rtps_config_package.all; --TODO: Remove after putting DDS_*_OPCODE_TYPE inside rtps_package
package ros_package is
@ -58,6 +57,18 @@ package ros_package is
AVOID_ROS_NAMESPACE_CONVENTION => FALSE
);
constant ROS_QOS_PROFILE_TRANSIENT : ROS_QOS_PROFILE_TYPE := (
HISTORY_QOS => KEEP_LAST_HISTORY_QOS,
HISTORY_DEPTH => std_logic_vector(to_unsigned(10, CDR_LONG_WIDTH)),
RELIABILITY_QOS => RELIABLE_RELIABILITY_QOS,
DURABILITY_QOS => TRANSIENT_LOCAL_DURABILITY_QOS,
DEADLINE_QOS => DEFAULT_DEADLINE_QOS,
LIFESPAN_QOS => DEFAULT_LIFESPAN_QOS,
LIVELINESS_QOS => DEFAULT_LIVELINESS_QOS,
LEASE_DURATION => DEFAULT_LEASE_DURATION,
AVOID_ROS_NAMESPACE_CONVENTION => FALSE
);
constant ROS_QOS_PROFILE_SERVICES_DEFAULT : ROS_QOS_PROFILE_TYPE := (
HISTORY_QOS => KEEP_LAST_HISTORY_QOS,
HISTORY_DEPTH => std_logic_vector(to_unsigned(10, CDR_LONG_WIDTH)),
@ -94,6 +105,8 @@ package ros_package is
AVOID_ROS_NAMESPACE_CONVENTION => FALSE
);
type ROS_NODE_TYPE is record
--context_id : natural;
name : USER_STRING_TYPE;
@ -110,6 +123,7 @@ package ros_package is
TOPICNAME : USER_STRING_TYPE;
TYPENAME : USER_STRING_TYPE;
QOS : ROS_QOS_PROFILE_TYPE;
MAX_SIZE : natural;
end record;
type ROS_SERVICE_TYPE is record
@ -117,6 +131,8 @@ package ros_package is
SERVICENAME : USER_STRING_TYPE;
TYPENAME : USER_STRING_TYPE;
QOS : ROS_QOS_PROFILE_TYPE;
MAX_RQ_SIZE : natural;
MAX_RR_SIZE : natural;
is_client : boolean;
end record;
@ -163,6 +179,8 @@ package ros_package is
function to_gid(guid : GUID_TYPE) return GID_TYPE;
constant SERVICE_OVERHEAD_BYTES : natural := 16;
function get_num_pubs(nodes : ROS_NODE_ARRAY_TYPE) return natural;
function get_num_subs(nodes : ROS_NODE_ARRAY_TYPE) return natural;
function get_num_services(nodes : ROS_NODE_ARRAY_TYPE) return natural;
@ -350,11 +368,11 @@ package body ros_package is
procedure check_node_mapping (nodes : in ROS_NODE_ARRAY_TYPE; pubs : in ROS_TOPIC_ARRAY_TYPE; subs : in ROS_TOPIC_ARRAY_TYPE; services : in ROS_SERVICE_ARRAY_TYPE; actions : in ROS_ACTION_ARRAY_TYPE) is
variable tmp : natural;
begin
for i in 0 to nodes'length loop
for i in 0 to nodes'length-1 loop
-- Check PUB Mapping
if (nodes(i).NUM_PUBS > 0) then
tmp := 0;
for j in 0 to pubs'length loop
for j in 0 to pubs'length-1 loop
if (pubs(j).node_id = i) then
tmp := tmp + 1;
end if;
@ -365,7 +383,7 @@ package body ros_package is
-- Check SUB Mapping
if (nodes(i).NUM_SUBS > 0) then
tmp := 0;
for j in 0 to subs'length loop
for j in 0 to subs'length-1 loop
if (subs(j).node_id = i) then
tmp := tmp + 1;
end if;
@ -376,7 +394,7 @@ package body ros_package is
-- Check SERVICE Mapping
if (nodes(i).NUM_SERVICES > 0) then
tmp := 0;
for j in 0 to services'length loop
for j in 0 to services'length-1 loop
if (services(j).node_id = i) then
tmp := tmp + 1;
end if;
@ -387,7 +405,7 @@ package body ros_package is
-- Check ACTION Mapping
if (nodes(i).NUM_ACTIONS > 0) then
tmp := 0;
for j in 0 to actions'length loop
for j in 0 to actions'length-1 loop
if (actions(j).node_id = i) then
tmp := tmp + 1;
end if;

View File

@ -0,0 +1,159 @@
-- 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.math_pkg.all;
use work.rtps_package.all;
use work.ros_config_package.all;
entity ros_static_discovery_writer is
port (
-- SYSTEM
clk : in std_logic;
reset : in std_logic;
-- TO/FROM RTPS ENDPOINT
start : in std_logic;
opcode : in HISTORY_CACHE_OPCODE_TYPE;
ack : out std_logic;
done : out std_logic;
ret : out HISTORY_CACHE_RESPONSE_TYPE;
seq_nr : in SEQUENCENUMBER_TYPE;
get_data : in std_logic;
data_out : out std_logic_vector(WORD_WIDTH-1 downto 0);
valid_out : out std_logic;
ready_out : in std_logic;
last_word_out : out std_logic;
liveliness_assertion : out std_logic;
data_available : out std_logic;
-- Cache Change
cc_instance_handle : out INSTANCE_HANDLE_TYPE;
cc_kind : out CACHE_CHANGE_KIND_TYPE;
cc_source_timestamp : out TIME_TYPE;
cc_seq_nr : out SEQUENCENUMBER_TYPE
);
end entity;
architecture arch of ros_static_discovery_writer is
constant SN : SEQUENCENUMBER_TYPE := FIRST_SEQUENCENUMBER;
--*****TYPE DECLARATION*****
type STAGE_TYPE is (IDLE,CACHE_CHANGE,DATA,RET_SN,RET_RTPS);
--*****SIGNAL DECLARATION*****
signal stage, stage_next : STAGE_TYPE;
signal ret_code, ret_code_next : HISTORY_CACHE_RESPONSE_TYPE;
signal data_available_sig, data_available_sig_next : std_logic;
signal cnt, cnt_next : integer range 0 to ROS_DISCOVERY_DATA.length;
begin
liveliness_assertion <= '0';
data_available <= data_available_sig;
main_prc : process(all)
begin
-- DEFAULT
stage_next <= stage;
cnt_next <= cnt;
ret_code_next <= ret_code;
data_available_sig_next <= data_available_sig;
-- DEFAULT Unregistered
ack <= '0';
done <= '0';
ret <= OK;
data_out <= (others => '0');
valid_out <= '0';
last_word_out <= '0';
cc_instance_handle <= HANDLE_NIL;
cc_kind <= ALIVE;
cc_source_timestamp <= TIME_INVALID;
cc_seq_nr <= SEQUENCENUMBER_UNKNOWN;
case (stage) is
when IDLE =>
if (start = '1') then
ack <= '1';
case (opcode) is
when GET_MIN_SN =>
stage_next <= RET_SN;
when GET_MAX_SN =>
-- Reset Data Available
data_available_sig_next <= '0';
stage_next <= RET_SN;
when GET_CACHE_CHANGE =>
cnt_next <= 0;
stage_next <= CACHE_CHANGE;
when ACK_CACHE_CHANGE =>
ret_code_next <= OK;
stage_next <= RET_RTPS;
when NACK_CACHE_CHANGE =>
ret_code_next <= OK;
stage_next <= RET_RTPS;
when REMOVE_CACHE_CHANGE =>
ret_code_next <= OK;
stage_next <= RET_RTPS;
when others =>
end case;
end if;
when CACHE_CHANGE =>
done <= '1';
ret <= OK;
cc_seq_nr <= SN;
if (get_data = '1') then
stage_next <= DATA;
else
stage_next <= IDLE;
end if;
when DATA =>
valid_out <= '1';
data_out <= ROS_DISCOVERY_DATA.data(cnt);
if (cnt = ROS_DISCOVERY_DATA.length-1) then
last_word_out <= '1';
end if;
if (ready_out = '1') then
if (cnt = ROS_DISCOVERY_DATA.length-1) then
stage_next <= IDLE;
else
cnt_next <= cnt + 1;
end if;
end if;
when RET_SN =>
done <= '1';
ret <= OK;
cc_seq_nr <= SN;
stage_next <= IDLE;
when RET_RTPS =>
done <= '1';
ret <= ret_code;
stage_next <= IDLE;
end case;
end process;
sync_prc : process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
stage <= IDLE;
cnt <= 0;
ret_code <= ERROR;
data_available_sig <= '1';
else
stage <= stage_next;
cnt <= cnt_next;
ret_code <= ret_code_next;
data_available_sig <= data_available_sig_next;
end if;
end if;
end process;
end architecture;

View File

@ -46,11 +46,6 @@ package rtps_config_package is
constant EMO_PARTICIPANT_UNMATCH : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000002";
constant EMO_LIVELINESS_UPDATE : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000003";
type HISTORY_CACHE_OPCODE_TYPE is (NOP, ADD_CACHE_CHANGE, GET_CACHE_CHANGE, ACK_CACHE_CHANGE, NACK_CACHE_CHANGE, REMOVE_CACHE_CHANGE, REMOVE_WRITER, GET_MIN_SN, GET_MAX_SN);
type KEY_HOLDER_OPCODE_TYPE is (NOP, PUSH_DATA, PUSH_SERIALIZED_KEY, READ_KEY_HASH, READ_SERIALIZED_KEY);
type HISTORY_CACHE_RESPONSE_TYPE is (OK, REJECTED, INVALID, ERROR);
type DDS_WRITER_OPCODE_TYPE is (NOP, REGISTER_INSTANCE, WRITE, DISPOSE, UNREGISTER_INSTANCE, LOOKUP_INSTANCE, WAIT_FOR_ACKNOWLEDGEMENTS, GET_OFFERED_DEADLINE_MISSED_STATUS, ASSERT_LIVELINESS, GET_LIVELINESS_LOST_STATUS);
type DDS_READER_OPCODE_TYPE is (NOP, READ, TAKE, READ_NEXT_SAMPLE, TAKE_NEXT_SAMPLE, READ_INSTANCE, TAKE_INSTANCE, READ_NEXT_INSTANCE, TAKE_NEXT_INSTANCE, GET_SAMPLE_REJECTED_STATUS, GET_REQUESTED_DEADLINE_MISSED_STATUS);
-- Sample Status Info Flags
constant SSI_DISPOSED_FLAG : natural := STATUS_INFO_DISPOSED_FLAG;
@ -99,6 +94,7 @@ package rtps_config_package is
data : WORD_ARRAY_TYPE(0 to 16371);
length : natural;
end record;
constant READER_ENDPOINT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body
constant WRITER_ENDPOINT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body
constant LOCAL_PARTICIPANT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body

View File

@ -476,6 +476,12 @@ package rtps_package is
constant EMPTY_USER_STRING : USER_STRING_TYPE := (others => NUL);
constant DEFAULT_USER_DOMAIN_TAG : USER_STRING_TYPE := EMPTY_USER_STRING;
type HISTORY_CACHE_OPCODE_TYPE is (NOP, ADD_CACHE_CHANGE, GET_CACHE_CHANGE, ACK_CACHE_CHANGE, NACK_CACHE_CHANGE, REMOVE_CACHE_CHANGE, REMOVE_WRITER, GET_MIN_SN, GET_MAX_SN);
type KEY_HOLDER_OPCODE_TYPE is (NOP, PUSH_DATA, PUSH_SERIALIZED_KEY, READ_KEY_HASH, READ_SERIALIZED_KEY);
type HISTORY_CACHE_RESPONSE_TYPE is (OK, REJECTED, INVALID, ERROR);
type DDS_WRITER_OPCODE_TYPE is (NOP, REGISTER_INSTANCE, WRITE, DISPOSE, UNREGISTER_INSTANCE, LOOKUP_INSTANCE, WAIT_FOR_ACKNOWLEDGEMENTS, GET_OFFERED_DEADLINE_MISSED_STATUS, ASSERT_LIVELINESS, GET_LIVELINESS_LOST_STATUS);
type DDS_READER_OPCODE_TYPE is (NOP, READ, TAKE, READ_NEXT_SAMPLE, TAKE_NEXT_SAMPLE, READ_INSTANCE, TAKE_INSTANCE, READ_NEXT_INSTANCE, TAKE_NEXT_INSTANCE, GET_SAMPLE_REJECTED_STATUS, GET_REQUESTED_DEADLINE_MISSED_STATUS);
function gen_user_string(input : string) return string;
function string_len (str : string) return natural;
function concat(A,B : string) return USER_STRING_TYPE;