Skip to content

Commit 940a207

Browse files
committed
implement atc example
1 parent c9f067a commit 940a207

File tree

6 files changed

+368
-0
lines changed

6 files changed

+368
-0
lines changed

examples/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,14 @@ install(
4949
COMPONENT dev)
5050

5151
add_subdirectory(roundtrip)
52+
53+
install(
54+
FILES atc/publisher.cpp
55+
atc/subscriber.cpp
56+
atc/ATCDataModel.idl
57+
atc/CMakeLists.txt
58+
atc/readme.rst
59+
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/atc"
60+
COMPONENT dev)
61+
62+
add_subdirectory(atc)

examples/atc/ATCDataModel.idl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
7+
* v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
module ATCDataModule
13+
{
14+
struct Position
15+
{
16+
short x; // latitude
17+
short y; // longitude
18+
short z; // altitude
19+
};
20+
21+
struct Flight
22+
{
23+
/** Flight Call ID */
24+
long ID; //@Key
25+
26+
Position pos;
27+
// float Speed;
28+
/** Current Region we are flying into*/
29+
string CurrentRegion;
30+
};
31+
#pragma keylist Flight ID
32+
};

examples/atc/CMakeLists.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#
2+
# Copyright(c) 2020 to 2022 ZettaScale Technology and others
3+
#
4+
# This program and the accompanying materials are made available under the
5+
# terms of the Eclipse Public License v. 2.0 which is available at
6+
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
7+
# v. 1.0 which is available at
8+
# http://www.eclipse.org/org/documents/edl-v10.php.
9+
#
10+
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
#
12+
cmake_minimum_required(VERSION 3.16)
13+
project(atc LANGUAGES C CXX)
14+
15+
set(CMAKE_CXX_STANDARD 17)
16+
17+
if(NOT TARGET CycloneDDS-CXX::ddscxx)
18+
find_package(CycloneDDS-CXX REQUIRED)
19+
endif()
20+
21+
idlcxx_generate(TARGET ATCDataModel FILES ATCDataModel.idl WARNINGS no-implicit-extensibility)
22+
23+
add_executable(pubATC publisher.cpp)
24+
add_executable(subATC subscriber.cpp)
25+
26+
# Link both executables to idl data type library and ddscxx.
27+
target_link_libraries(pubATC CycloneDDS-CXX::ddscxx ATCDataModel)
28+
target_link_libraries(subATC CycloneDDS-CXX::ddscxx ATCDataModel)
29+
30+
# Disable the static analyzer in GCC to avoid crashing the GNU C++ compiler
31+
# on Azure Pipelines
32+
if(DEFINED ENV{SYSTEM_TEAMFOUNDATIONSERVERURI})
33+
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND ANALYZER STREQUAL "on")
34+
target_compile_options(pubATC PRIVATE -fno-analyzer)
35+
target_compile_options(subATC PRIVATE -fno-analyzer)
36+
endif()
37+
endif()
38+
39+
set_property(TARGET pubATC PROPERTY CXX_STANDARD ${cyclonedds_cpp_std_to_use})
40+
set_property(TARGET subATC PROPERTY CXX_STANDARD ${cyclonedds_cpp_std_to_use})

examples/atc/publisher.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
7+
* v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
#include <iostream>
13+
#include "dds/dds.hpp"
14+
#include "ATCDataModel.hpp"
15+
16+
17+
int main() {
18+
std::cout << "Cyclone- ATC Pub" << std::endl;
19+
20+
/** A dds::domain::DomainParticipant is created for the default domain. */
21+
dds::domain::DomainParticipant dp(0);
22+
dds::topic::qos::TopicQos topicQos = dp.default_topic_qos();
23+
24+
/** A dds::topic::Topic is created for our sample type on the domain participant. */
25+
dds::topic::Topic<ATCDataModule::Flight> topic(dp, "FlightData", topicQos);
26+
27+
/** 5 dds Publishers are associated to 5 different partitions. */
28+
dds::pub::qos::PublisherQos PubGotalandQoS = dp.default_publisher_qos();
29+
dds::pub::qos::PublisherQos PubSardegnaQoS = dp.default_publisher_qos();
30+
dds::pub::qos::PublisherQos PubNorrlandQoS = dp.default_publisher_qos();
31+
dds::pub::qos::PublisherQos PubLombardiaQoS = dp.default_publisher_qos();
32+
dds::pub::qos::PublisherQos pubSiciliaQoS = dp.default_publisher_qos();
33+
dds::pub::qos::PublisherQos pubZeelandQoS = dp.default_publisher_qos();
34+
dds::pub::qos::PublisherQos pubDrentheQoS = dp.default_publisher_qos();
35+
36+
PubGotalandQoS << dds::core::policy::Partition("/Europe/Sweden/Gotaland");
37+
PubNorrlandQoS << dds::core::policy::Partition("/Europe/Sweden/Norrland");
38+
PubSardegnaQoS << dds::core::policy::Partition("/Europe/Italy/Sardegna");
39+
PubLombardiaQoS << dds::core::policy::Partition("/Europe/Italy/Lombardia");
40+
pubSiciliaQoS << dds::core::policy::Partition("/Europe/Italy/Sicilia");
41+
pubZeelandQoS << dds::core::policy::Partition("/Europe/Netherlands/Zeeland");
42+
pubDrentheQoS << dds::core::policy::Partition("/Europe/Netherlands/Drenthe");
43+
44+
dds::pub::Publisher pubGotaland(dp, PubGotalandQoS);
45+
dds::pub::Publisher pubNorrland(dp, PubNorrlandQoS);
46+
dds::pub::Publisher pubSardegna(dp, PubSardegnaQoS);
47+
dds::pub::Publisher pubLombardia(dp, PubLombardiaQoS);
48+
dds::pub::Publisher pubSicilia(dp, pubSiciliaQoS);
49+
dds::pub::Publisher pubZeeland(dp, pubZeelandQoS);
50+
dds::pub::Publisher pubDrenthe(dp, pubDrentheQoS);
51+
52+
/** A dds::pub::DataWriter is created on the Publisher & Topic with the associated Partition Qos. */
53+
dds::pub::qos::DataWriterQos dwqos = topic.qos();
54+
55+
dds::pub::DataWriter<ATCDataModule::Flight> dwGotaland(pubGotaland, topic, dwqos);
56+
dds::pub::DataWriter<ATCDataModule::Flight> dwNorrland(pubNorrland, topic, dwqos);
57+
dds::pub::DataWriter<ATCDataModule::Flight> dwSardegna(pubSardegna, topic, dwqos);
58+
dds::pub::DataWriter<ATCDataModule::Flight> dwLombardia(pubLombardia, topic, dwqos);
59+
dds::pub::DataWriter<ATCDataModule::Flight> dwsicilia(pubSicilia, topic, dwqos);
60+
dds::pub::DataWriter<ATCDataModule::Flight> dwzeeland(pubZeeland, topic, dwqos);
61+
dds::pub::DataWriter<ATCDataModule::Flight> dwdrenthe(pubDrenthe, topic, dwqos);
62+
63+
// std::cout << "@ With ddsi, Let the Apps discover each other a bit ZZZzzz:" << std::endl;
64+
//dds_sleepfor (DDS_MSECS (5000));
65+
66+
std::cout << "===> Waiting for a subscriber. " << std::endl;
67+
while (dwdrenthe.publication_matched_status().current_count() == 0 &&
68+
dwzeeland.publication_matched_status().current_count() == 0 &&
69+
dwsicilia.publication_matched_status().current_count() == 0 &&
70+
dwLombardia.publication_matched_status().current_count() == 0 &&
71+
dwSardegna.publication_matched_status().current_count() == 0 &&
72+
dwNorrland.publication_matched_status().current_count() == 0 &&
73+
dwGotaland.publication_matched_status().current_count() == 0)
74+
{
75+
dds_sleepfor (DDS_MSECS (20));
76+
}
77+
std::cout << "===> Found a matching one ... " << std::endl;
78+
79+
for (int16_t i = 0; i < 5; i++) {
80+
ATCDataModule::Position p1(i+800, i+20, i+93 );
81+
ATCDataModule::Flight FlightInstance(i, p1,"** /Europe/Sweden/Gotaland partition ** ");
82+
dwGotaland << FlightInstance;
83+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Sweden/Gotaland Region " << std::endl;
84+
85+
dds_sleepfor (DDS_MSECS (500));
86+
}
87+
88+
for (int16_t i = 5; i < 10; i++) {
89+
ATCDataModule::Position p2(i+7900, i+20, i+93 );
90+
ATCDataModule::Flight FlightInstance(i, p2, "** /Europe/Sweden/Norrland partition ++");
91+
dwNorrland << FlightInstance;
92+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Sweden/Norrland Region " << std::endl;
93+
94+
dds_sleepfor (DDS_MSECS (500));
95+
}
96+
97+
for (int16_t i = 10; i < 15; i++) {
98+
ATCDataModule::Position p3(i+800, i+20, i+93 );
99+
ATCDataModule::Flight FlightInstance(i, p3, "** /Europe/Italy/Sardegna partition &&");
100+
dwSardegna << FlightInstance;
101+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Sardegna Region " << std::endl;
102+
103+
dds_sleepfor (DDS_MSECS (500));
104+
}
105+
106+
for (int16_t i = 15; i < 20; i++) {
107+
ATCDataModule::Position p4(i+99, i+97, i+93 );
108+
ATCDataModule::Flight FlightInstance(i, p4, "** /Europe/Italy/Lombardia partition %%");
109+
dwLombardia << FlightInstance;
110+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Lombardia Region " << std::endl;
111+
112+
dds_sleepfor (DDS_MSECS (500));
113+
}
114+
115+
for (int16_t i = 20; i < 25; i++) {
116+
ATCDataModule::Position p5(i+242, i+240, i+930 );
117+
ATCDataModule::Flight FlightInstance(i,p5, "** /Europe/Italy/Sicilia partition $$");
118+
dwsicilia << FlightInstance;
119+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Sicilia Region " << std::endl;
120+
121+
dds_sleepfor (DDS_MSECS (500));
122+
}
123+
124+
for (int16_t i = 25; i < 30; i++) {
125+
ATCDataModule::Position p6(i+22, i+20, i+930 );
126+
ATCDataModule::Flight FlightInstance(i,p6, "** /Europe/Netherlands/Zeeland partition &&");
127+
dwzeeland << FlightInstance;
128+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Netherlands/Zeeland Region " << std::endl;
129+
130+
dds_sleepfor (DDS_MSECS (500));
131+
}
132+
133+
for (int16_t i = 30; i < 35; i++) {
134+
ATCDataModule::Position p7(i+22, i+20, i+930 );
135+
ATCDataModule::Flight FlightInstance(i,p7, "** /Europe/Netherlands/Drenthe partition &&");
136+
dwdrenthe << FlightInstance;
137+
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Netherlands/Drenthe Region " << std::endl;
138+
139+
dds_sleepfor (DDS_MSECS (500));
140+
}
141+
142+
dds_sleepfor (DDS_MSECS (5000));
143+
return 0;
144+
}

examples/atc/readme.rst

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
..
2+
Copyright(c) 2006 to 2022 ZettaScale Technology and others
3+
4+
This program and the accompanying materials are made available under the
5+
terms of the Eclipse Public License v. 2.0 which is available at
6+
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
7+
v. 1.0 which is available at
8+
http://www.eclipse.org/org/documents/edl-v10.php.
9+
10+
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
12+
ATC
13+
==========
14+
15+
Description
16+
***********
17+
18+
This example mimics, in its most simplistic form, an Air Traffic Controller System , made of two subsystems:
19+
20+
A **Radar System** that, detects and publishes Flights in different region in Europe, within a dedicated Global data space,
21+
and an Air **Flight Visualiser system** that can build *different views* of that space, either Per country, Per Region or Per the Entire continent.
22+
23+
Design
24+
******
25+
26+
The Radar system is modelled by the Publishing program ( **pubATC** ). This program
27+
28+
- Get involved in the European Global Data Space DDS domain (domainId=0),
29+
- Creates 6 DDS partitions that corresponds to the 6 regions shown on the Map (see Fig below), then it
30+
- Publishes 5 Flights with different Call signs (CIDs) as well as their respective positions .
31+
32+
The European Global Data Space is organized hierarchically following this pattern: `/<Continent>/<Country>/<Region>`.
33+
34+
The Air Flight Visualizer is modelled by the Subscribing program (**subATC**).
35+
This program allows you to Subscribe to a specific region, for example, to the region `/Europe/Sweden/Norrland` or
36+
at the scale of the country (`/Europe/Italy/*`) or the scale of the entire continent (`/*`), Regular expressions can be used to specify the scopes .
37+
38+
The subATC program will create one subscriber to get all the data corresponding to the view you are building using the DDS concept of Partition.
39+
40+
The subATC program takes at most one argument. This argument specifies the absolute name of the region i.e `/<Continent>/<Country>/<Region>`.
41+
42+
Both programs use the default DDS QoS but the PartitionQoS.
43+
44+
The example helps you understand the concept of partition in DDS and how it can be used to creates different
45+
views on the data or split the dds domain in smaller logical groups.
46+
47+
48+
Running the examples
49+
********************
50+
51+
It is recommended to run one Publishing program (pubATC) and several Subscribing programs in different terminals .
52+
53+
**Scenario1** : Subscribing to all the flights to have a global view on all the flights
54+
55+
`./pubATC`
56+
57+
`./subATC "*"`
58+
59+
**Scenario2** : Gross grain Subscription, subscribe to an entire country view
60+
61+
`./pubATC`
62+
63+
`./subATC /Europe/Netherlands/*`
64+
65+
**Scenario3** : Fine grain Subscription, subscribe to a give region
66+
67+
`./pubATC`
68+
69+
`./subATC /Europe/Netherlands/Zeeland`
70+

examples/atc/subscriber.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
7+
* v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
#include<iostream>
13+
#include "dds/dds.hpp"
14+
#include "ATCDataModel.hpp"
15+
16+
17+
int main(int argc, char* argv[]) {
18+
std::cout << " Cyclone- ATC Subscriber, Flight Visualiser per Country or Region *** " << std::endl;
19+
20+
/** A domain participant and topic are created identically as in the ::publisher */
21+
dds::domain::DomainParticipant dp(0);
22+
dds::topic::qos::TopicQos topicQos = dp.default_topic_qos();
23+
dds::topic::Topic<ATCDataModule::Flight> topic(dp, "FlightData", topicQos);
24+
25+
/** A dds::pub::Sub is created on the domain participant. */
26+
std::string PartitionName;
27+
28+
if (argc<2) {
29+
std::cout << "=< Specify the Region Name (Partition) , a regular expression with * or ? " << std::endl;
30+
std::cout << "=< for examples :*;/* ; /E*; /Europe/*; or ..." << std::endl;
31+
std::cout << "=< : /Europe/Italy/*; /Europe/Italy/Sardegna; /Europe/Italy/Sicilia; /Europe/Netherlands/*, ..." << std::endl;
32+
std::cout << "=< Enter the Region Name or Expression:" << std::endl;
33+
34+
std::cin >> PartitionName;
35+
std::cout << " Thanks !" << std::endl;
36+
} else {
37+
PartitionName=argv[1];
38+
}
39+
//std::cout << " The partition is..:" << PartitionName <<std::endl;
40+
dds::sub::qos::SubscriberQos subQos = dp.default_subscriber_qos() << dds::core::policy::Partition(PartitionName);;
41+
dds::sub::Subscriber sub(dp, subQos);
42+
43+
/** A dds::sub::DataReader is created on the Subscriber & Topic with the DataReaderQos. */
44+
dds::sub::qos::DataReaderQos drqos = topic.qos();
45+
46+
dds::sub::DataReader<ATCDataModule::Flight> dr(sub, topic, drqos);
47+
48+
bool sampleReceived = false;
49+
// The Subscriber is going to wait during 120 seconds then leaves , to allow receiving all the instances and their samples
50+
int count = 0;
51+
do {
52+
dds::sub::LoanedSamples<ATCDataModule::Flight> samples = dr.take();
53+
for (dds::sub::LoanedSamples<ATCDataModule::Flight>::const_iterator sample = samples.begin(); sample < samples.end(); ++sample) {
54+
if (sample->info().valid()) {
55+
std::cout << "=== [Flight Visualiser] Flight with ID :" << sample->data().ID() <<" Visualized"<<std::endl;
56+
std::cout << " In the Region of: \"" << sample->data().CurrentRegion() << "\"" << std::endl;
57+
sampleReceived = true;
58+
} else {
59+
// std::cout << "data disposed, explicitely or the DW lost his liveliness" << std::endl;
60+
}
61+
}
62+
63+
dds_sleepfor (DDS_MSECS (1));
64+
++count;
65+
} while (count < 120000 ) ;
66+
67+
if (!sampleReceived) {
68+
std::cerr << "Warning: Waited too long (120 seconds) but no sample received" << std::endl;
69+
}
70+
return 0;
71+
}

0 commit comments

Comments
 (0)