Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,14 @@ install(
COMPONENT dev)

add_subdirectory(roundtrip)

install(
FILES atc/publisher.cpp
atc/subscriber.cpp
atc/ATCDataModel.idl
atc/CMakeLists.txt
atc/readme.rst
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/atc"
COMPONENT dev)

add_subdirectory(atc)
32 changes: 32 additions & 0 deletions examples/atc/ATCDataModel.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
module ATCDataModule
{
struct Position
{
short x; // latitude
short y; // longitude
short z; // altitude
};

struct Flight
{
/** Flight Call ID */
long ID; //@Key

Position pos;
// float Speed;
/** Current Region we are flying into*/
string CurrentRegion;
};
#pragma keylist Flight ID
};
40 changes: 40 additions & 0 deletions examples/atc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# Copyright(c) 2020 to 2022 ZettaScale Technology and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.16)
project(atc LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 17)

if(NOT TARGET CycloneDDS-CXX::ddscxx)
find_package(CycloneDDS-CXX REQUIRED)
endif()

idlcxx_generate(TARGET ATCDataModel FILES ATCDataModel.idl WARNINGS no-implicit-extensibility)

add_executable(pubATC publisher.cpp)
add_executable(subATC subscriber.cpp)

# Link both executables to idl data type library and ddscxx.
target_link_libraries(pubATC CycloneDDS-CXX::ddscxx ATCDataModel)
target_link_libraries(subATC CycloneDDS-CXX::ddscxx ATCDataModel)

# Disable the static analyzer in GCC to avoid crashing the GNU C++ compiler
# on Azure Pipelines
if(DEFINED ENV{SYSTEM_TEAMFOUNDATIONSERVERURI})
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND ANALYZER STREQUAL "on")
target_compile_options(pubATC PRIVATE -fno-analyzer)
target_compile_options(subATC PRIVATE -fno-analyzer)
endif()
endif()

set_property(TARGET pubATC PROPERTY CXX_STANDARD ${cyclonedds_cpp_std_to_use})
set_property(TARGET subATC PROPERTY CXX_STANDARD ${cyclonedds_cpp_std_to_use})
144 changes: 144 additions & 0 deletions examples/atc/publisher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <iostream>
#include "dds/dds.hpp"
#include "ATCDataModel.hpp"


int main() {
std::cout << "Cyclone- ATC Pub" << std::endl;

/** A dds::domain::DomainParticipant is created for the default domain. */
dds::domain::DomainParticipant dp(0);
dds::topic::qos::TopicQos topicQos = dp.default_topic_qos();

/** A dds::topic::Topic is created for our sample type on the domain participant. */
dds::topic::Topic<ATCDataModule::Flight> topic(dp, "FlightData", topicQos);

/** 5 dds Publishers are associated to 5 different partitions. */
dds::pub::qos::PublisherQos PubGotalandQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos PubSardegnaQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos PubNorrlandQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos PubLombardiaQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos pubSiciliaQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos pubZeelandQoS = dp.default_publisher_qos();
dds::pub::qos::PublisherQos pubDrentheQoS = dp.default_publisher_qos();

PubGotalandQoS << dds::core::policy::Partition("/Europe/Sweden/Gotaland");
PubNorrlandQoS << dds::core::policy::Partition("/Europe/Sweden/Norrland");
PubSardegnaQoS << dds::core::policy::Partition("/Europe/Italy/Sardegna");
PubLombardiaQoS << dds::core::policy::Partition("/Europe/Italy/Lombardia");
pubSiciliaQoS << dds::core::policy::Partition("/Europe/Italy/Sicilia");
pubZeelandQoS << dds::core::policy::Partition("/Europe/Netherlands/Zeeland");
pubDrentheQoS << dds::core::policy::Partition("/Europe/Netherlands/Drenthe");

dds::pub::Publisher pubGotaland(dp, PubGotalandQoS);
dds::pub::Publisher pubNorrland(dp, PubNorrlandQoS);
dds::pub::Publisher pubSardegna(dp, PubSardegnaQoS);
dds::pub::Publisher pubLombardia(dp, PubLombardiaQoS);
dds::pub::Publisher pubSicilia(dp, pubSiciliaQoS);
dds::pub::Publisher pubZeeland(dp, pubZeelandQoS);
dds::pub::Publisher pubDrenthe(dp, pubDrentheQoS);

/** A dds::pub::DataWriter is created on the Publisher & Topic with the associated Partition Qos. */
dds::pub::qos::DataWriterQos dwqos = topic.qos();

dds::pub::DataWriter<ATCDataModule::Flight> dwGotaland(pubGotaland, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwNorrland(pubNorrland, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwSardegna(pubSardegna, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwLombardia(pubLombardia, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwsicilia(pubSicilia, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwzeeland(pubZeeland, topic, dwqos);
dds::pub::DataWriter<ATCDataModule::Flight> dwdrenthe(pubDrenthe, topic, dwqos);

// std::cout << "@ With ddsi, Let the Apps discover each other a bit ZZZzzz:" << std::endl;
//dds_sleepfor (DDS_MSECS (5000));

std::cout << "===> Waiting for a subscriber. " << std::endl;
while (dwdrenthe.publication_matched_status().current_count() == 0 &&
dwzeeland.publication_matched_status().current_count() == 0 &&
dwsicilia.publication_matched_status().current_count() == 0 &&
dwLombardia.publication_matched_status().current_count() == 0 &&
dwSardegna.publication_matched_status().current_count() == 0 &&
dwNorrland.publication_matched_status().current_count() == 0 &&
dwGotaland.publication_matched_status().current_count() == 0)
{
dds_sleepfor (DDS_MSECS (20));
}
std::cout << "===> Found a matching one ... " << std::endl;

for (int16_t i = 0; i < 5; i++) {
ATCDataModule::Position p1(i+800, i+20, i+93 );
ATCDataModule::Flight FlightInstance(i, p1,"** /Europe/Sweden/Gotaland partition ** ");
dwGotaland << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Sweden/Gotaland Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 5; i < 10; i++) {
ATCDataModule::Position p2(i+7900, i+20, i+93 );
ATCDataModule::Flight FlightInstance(i, p2, "** /Europe/Sweden/Norrland partition ++");
dwNorrland << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Sweden/Norrland Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 10; i < 15; i++) {
ATCDataModule::Position p3(i+800, i+20, i+93 );
ATCDataModule::Flight FlightInstance(i, p3, "** /Europe/Italy/Sardegna partition &&");
dwSardegna << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Sardegna Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 15; i < 20; i++) {
ATCDataModule::Position p4(i+99, i+97, i+93 );
ATCDataModule::Flight FlightInstance(i, p4, "** /Europe/Italy/Lombardia partition %%");
dwLombardia << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Lombardia Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 20; i < 25; i++) {
ATCDataModule::Position p5(i+242, i+240, i+930 );
ATCDataModule::Flight FlightInstance(i,p5, "** /Europe/Italy/Sicilia partition $$");
dwsicilia << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Italy/Sicilia Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 25; i < 30; i++) {
ATCDataModule::Position p6(i+22, i+20, i+930 );
ATCDataModule::Flight FlightInstance(i,p6, "** /Europe/Netherlands/Zeeland partition &&");
dwzeeland << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Netherlands/Zeeland Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

for (int16_t i = 30; i < 35; i++) {
ATCDataModule::Position p7(i+22, i+20, i+930 );
ATCDataModule::Flight FlightInstance(i,p7, "** /Europe/Netherlands/Drenthe partition &&");
dwdrenthe << FlightInstance;
std::cout << "=> [Radar Simulator] detecting FlightID: "<< FlightInstance.ID() << " in the /Europe/Netherlands/Drenthe Region " << std::endl;

dds_sleepfor (DDS_MSECS (500));
}

dds_sleepfor (DDS_MSECS (5000));
return 0;
}
69 changes: 69 additions & 0 deletions examples/atc/readme.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
..
Copyright(c) 2006 to 2022 ZettaScale Technology and others

This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.

SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause

ATC
==========

Description
***********

This example mimics, in its most simplistic form, an Air Traffic Controller System , made of two subsystems:

A **Radar System** that, detects and publishes Flights in different region in Europe, within a dedicated Global data space,
and an Air **Flight Visualiser system** that can build *different views* of that space, either Per country, Per Region or Per the Entire continent.

Design
******

The Radar system is modelled by the Publishing program ( **pubATC** ). This program

- Get involved in the European Global Data Space DDS domain (domainId=0),
- Creates 6 DDS partitions that corresponds to the 6 regions shown on the Map (see Fig below), then it
- Publishes 5 Flights with different Call signs (CIDs) as well as their respective positions .

The European Global Data Space is organized hierarchically following this pattern: `/<Continent>/<Country>/<Region>`.

The Air Flight Visualizer is modelled by the Subscribing program (**subATC**).
This program allows you to Subscribe to a specific region, for example, to the region `/Europe/Sweden/Norrland` or
at the scale of the country (`/Europe/Italy/*`) or the scale of the entire continent (`/*`), Regular expressions can be used to specify the scopes .

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.

The subATC program takes at most one argument. This argument specifies the absolute name of the region i.e `/<Continent>/<Country>/<Region>`.

Both programs use the default DDS QoS but the PartitionQoS.

The example helps you understand the concept of partition in DDS and how it can be used to creates different
views on the data or split the dds domain in smaller logical groups.


Running the examples
********************

It is recommended to run one Publishing program (pubATC) and several Subscribing programs in different terminals .

**Scenario1** : Subscribing to all the flights to have a global view on all the flights

`./pubATC`

`./subATC "*"`

**Scenario2** : Gross grain Subscription, subscribe to an entire country view

`./pubATC`

`./subATC /Europe/Netherlands/*`

**Scenario3** : Fine grain Subscription, subscribe to a give region

`./pubATC`

`./subATC /Europe/Netherlands/Zeeland`
71 changes: 71 additions & 0 deletions examples/atc/subscriber.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright(c) 2006 to 2020 ZettaScale Technology and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include<iostream>
#include "dds/dds.hpp"
#include "ATCDataModel.hpp"


int main(int argc, char* argv[]) {
std::cout << " Cyclone- ATC Subscriber, Flight Visualiser per Country or Region *** " << std::endl;

/** A domain participant and topic are created identically as in the ::publisher */
dds::domain::DomainParticipant dp(0);
dds::topic::qos::TopicQos topicQos = dp.default_topic_qos();
dds::topic::Topic<ATCDataModule::Flight> topic(dp, "FlightData", topicQos);

/** A dds::pub::Sub is created on the domain participant. */
std::string PartitionName;

if (argc<2) {
std::cout << "=< Specify the Region Name (Partition) , a regular expression with * or ? " << std::endl;
std::cout << "=< for examples :*;/* ; /E*; /Europe/*; or ..." << std::endl;
std::cout << "=< : /Europe/Italy/*; /Europe/Italy/Sardegna; /Europe/Italy/Sicilia; /Europe/Netherlands/*, ..." << std::endl;
std::cout << "=< Enter the Region Name or Expression:" << std::endl;

std::cin >> PartitionName;
std::cout << " Thanks !" << std::endl;
} else {
PartitionName=argv[1];
}
//std::cout << " The partition is..:" << PartitionName <<std::endl;
dds::sub::qos::SubscriberQos subQos = dp.default_subscriber_qos() << dds::core::policy::Partition(PartitionName);;
dds::sub::Subscriber sub(dp, subQos);

/** A dds::sub::DataReader is created on the Subscriber & Topic with the DataReaderQos. */
dds::sub::qos::DataReaderQos drqos = topic.qos();

dds::sub::DataReader<ATCDataModule::Flight> dr(sub, topic, drqos);

bool sampleReceived = false;
// The Subscriber is going to wait during 120 seconds then leaves , to allow receiving all the instances and their samples
int count = 0;
do {
dds::sub::LoanedSamples<ATCDataModule::Flight> samples = dr.take();
for (dds::sub::LoanedSamples<ATCDataModule::Flight>::const_iterator sample = samples.begin(); sample < samples.end(); ++sample) {
if (sample->info().valid()) {
std::cout << "=== [Flight Visualiser] Flight with ID :" << sample->data().ID() <<" Visualized"<<std::endl;
std::cout << " In the Region of: \"" << sample->data().CurrentRegion() << "\"" << std::endl;
sampleReceived = true;
} else {
// std::cout << "data disposed, explicitely or the DW lost his liveliness" << std::endl;
}
}

dds_sleepfor (DDS_MSECS (1));
++count;
} while (count < 120000 ) ;

if (!sampleReceived) {
std::cerr << "Warning: Waited too long (120 seconds) but no sample received" << std::endl;
}
return 0;
}
Loading