Esempio n. 1
0
        /// <summary>
        /// Main function, receiving structured command-line arguments
        /// via the System.Console.DragonFruit package.
        /// For example: dotnet run -- --domain-id 54 --sample-count 5
        /// </summary>
        /// <param name="domainId">The domain ID to create the DomainParticipant</param>
        /// <param name="sampleCount">The number of data samples to receive before exiting</param>
        public static void Main(int domainId = 0, int sampleCount = int.MaxValue)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // DomainParticipant QoS is configured in USER_QOS_PROFILES.xml
            //
            // A participant needs to be Disposed to release middleware resources.
            // The 'using' keyword indicates that it will be Disposed when this
            // scope ends.
            using DomainParticipant participant = DomainParticipantFactory.Instance
                                                  .CreateParticipant(domainId);

            // A Topic has a name and a datatype. Create dynamically-typed
            // Topic named "HelloWorld Topic" with the type definition of
            // "HelloWorld" in hello_world.xml. To get the type we use a QosProvider
            var provider = new QosProvider("../hello_world.xml");
            Topic <DynamicData> topic = participant.CreateTopic(
                "Example HelloWorld",
                provider.GetType("HelloWorld"));

            // A Subscriber allows an application to create one or more DataReaders
            // Subscriber QoS is configured in USER_QOS_PROFILES.xml
            Subscriber subscriber = participant.CreateSubscriber();

            // This DataReader reads data of type Temperature on Topic
            // "ChocolateTemperature". DataReader QoS is configured in
            // USER_QOS_PROFILES.xml
            DataReader <DynamicData> reader = subscriber.CreateDataReader(topic);

            // Obtain the DataReader's Status Condition
            StatusCondition statusCondition = reader.StatusCondition;

            // Enable the 'data available' status.
            statusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate an event handler with the status condition.
            // This will run when the condition is triggered, in the context of
            // the dispatch call (see below)
            int samplesRead = 0;

            statusCondition.Triggered += _ => samplesRead += ProcessData(reader);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);
            while (samplesRead < sampleCount)
            {
                // Dispatch will call the handlers associated to the WaitSet
                // conditions when they activate
                Console.WriteLine("HelloWorld subscriber sleeping for 4 sec...");
                waitset.Dispatch(Duration.FromSeconds(4));
            }
        }
Esempio n. 2
0
        public bool Initialize(Parameters parameters)
        {
            this.parameters = parameters;
            if (!ParseConfig())
            {
                return(false);
            }

            string baseProfile = parameters.QosLibrary + "::BaseProfileQos";
            string pingProfile = parameters.QosLibrary + "::ThroughputQos";
            string pongProfile = parameters.QosLibrary + "::ThroughputQos";

            var qosProvider    = new QosProvider(parameters.QosFile);
            var participantQos = GetParticipantQos(baseProfile);

            if (parameters.LatencyTest)
            {
                pongSemaphore = new Semaphore(0, 1);
            }

            if (SecureUseSecure)
            {
                // validate arguments
                if (!ValidateSecureArgs())
                {
                    Console.Error.WriteLine("Failure validating arguments");
                    return(false);
                }
                ConfigureSecurePlugin(ref participantQos);
            }

            participant = DomainParticipantFactory.Instance.CreateParticipant(parameters.Domain, participantQos);
            if (participant == null)
            {
                Console.Error.Write("Problem creating participant.\n");
                return(false);
            }

            publisher = participant.CreatePublisher(qosProvider.GetPublisherQos(pingProfile));
            if (publisher == null)
            {
                Console.Error.WriteLine("Problem creating publisher.");
                return(false);
            }
            subscriber = participant.CreateSubscriber(qosProvider.GetSubscriberQos(pongProfile));
            if (subscriber == null)
            {
                Console.Error.WriteLine("Problem creating subscriber.");
                return(false);
            }
            return(true);
        }
        private void RunExample(int domainId, int sampleCount)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // DomainParticipant QoS is configured in USER_QOS_PROFILES.xml
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId);

            // A Topic has a name and a datatype. Create a Topic named
            // "ChocolateTemperature" with type Temperature
            // In this example we use a DynamicType defined in XML, which creates
            // a DynamicData topic.
            var provider = new QosProvider("../chocolate_factory.xml");
            Topic <DynamicData> topic = participant.CreateTopic(
                "ChocolateTemperature",
                provider.GetType("Temperature"));

            // A Subscriber allows an application to create one or more DataReaders
            // Subscriber QoS is configured in USER_QOS_PROFILES.xml
            Subscriber subscriber = participant.CreateSubscriber();

            // This DataReader reads data of type Temperature on Topic
            // "ChocolateTemperature". DataReader QoS is configured in
            // USER_QOS_PROFILES.xml
            DataReader <DynamicData> reader = subscriber.CreateDataReader(topic);

            // Obtain the DataReader's Status Condition
            StatusCondition statusCondition = reader.StatusCondition;

            // Enable the 'data available' status.
            statusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate an event handler with the status condition.
            // This will run when the condition is triggered, in the context of
            // the dispatch call (see below)
            int samplesRead = 0;

            statusCondition.Triggered += _ => samplesRead += ProcessData(reader);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);
            while (samplesRead < sampleCount && !shutdownRequested)
            {
                // Dispatch will call the handlers associated to the WaitSet
                // conditions when they activate
                Console.WriteLine("ChocolateTemperature subscriber sleeping for 4 sec...");
                waitset.Dispatch(Duration.FromSeconds(4));
            }
        }
Esempio n. 4
0
        private DomainParticipantQos GetParticipantQos(string profile)
        {
            var qosProvider    = new QosProvider(parameters.QosFile);
            var participantQos = qosProvider.GetDomainParticipantQos(profile);

            // set initial peers and not use multicast
            if (peerHostCount > 0)
            {
                participantQos = participantQos.WithDiscovery(policy =>
                {
                    policy.InitialPeers.InsertRange(0, peerHostArray);
                    policy.MulticastReceiveAddresses.Clear();
                    // qos.discovery.multicast_receive_addresses = new DDS.StringSeq();
                });
            }

            if (!transport.ConfigureTransport(ref participantQos))
            {
                return(null);
            }

            /*
             * At this point, and not before is when we know the transport message size.
             * Now we can decide if we need to use asynchronous or not.
             */
            maxSynchronousSize = transport.MinimumMessageSizeMax - (PerftestTransport.MessageOverheadBytes);

            if (!DataSizeRelatedCalculations())
            {
                Console.Error.Write("[Error] Failed to configure the data size settings.\n");
                return(null);
            }

            if (parameters.EnableAutoThrottle)
            {
                participantQos = participantQos.WithProperty(policy =>
                                                             policy.Add("dds.domain_participant.auto_throttle.enable", "true"));
            }

            return(participantQos);
        }
Esempio n. 5
0
        /// <summary>
        /// Main function, receiving structured command-line arguments
        /// via the System.Console.DragonFruit package.
        /// For example: dotnet run -- --domain-id 54 --sample-count 5
        /// </summary>
        /// <param name="domainId">The domain ID to create the DomainParticipant</param>
        /// <param name="sampleCount">The number of data samples to publish</param>
        public static void Main(int domainId = 0, int sampleCount = int.MaxValue)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // DomainParticipant QoS is configured in USER_QOS_PROFILES.xml
            //
            // A participant needs to be Disposed to release middleware resources.
            // The 'using' keyword indicates that it will be Disposed when this
            // scope ends.
            using DomainParticipant participant = DomainParticipantFactory.Instance
                                                  .CreateParticipant(domainId);

            // A Topic has a name and a datatype. Create dynamically-typed
            // Topic named "HelloWorld Topic" with the type definition of
            // "HelloWorld" in hello_world.xml. To get the type we use a QosProvider
            var provider = new QosProvider("../hello_world.xml");
            Topic <DynamicData> topic = participant.CreateTopic(
                "Example HelloWorld",
                provider.GetType("HelloWorld"));

            // A Publisher allows an application to create one or more DataWriters
            // Publisher QoS is configured in USER_QOS_PROFILES.xml
            Publisher publisher = participant.CreatePublisher();

            // This DataWriter will write data on Topic "HelloWorld Topic"
            // DataWriter QoS is configured in USER_QOS_PROFILES.xml
            DataWriter <DynamicData> writer = publisher.CreateDataWriter(topic);

            var sample = writer.CreateData();

            for (int count = 0; count < sampleCount; count++)
            {
                // Modify the data to be written here
                sample.SetValue("msg", $"Hello {count}");

                Console.WriteLine($"Writing {sample}");
                writer.Write(sample);

                Thread.Sleep(1000);
            }
        }
Esempio n. 6
0
        private void RunExample(int domainId, string stationKind)
        {
            if (!Enum.TryParse <StationKind>(stationKind, out var currentStation))
            {
                throw new ArgumentException("Invalid station");
            }

            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // Uses TemperingApplication QoS profile to set participant name.
            var qosProvider = new QosProvider("./qos_profiles.xml");

            // By specifying a default library, we can later refer to the
            // profiles without the library name
            qosProvider.DefaultLibrary = "ChocolateFactoryLibrary";

            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(
                domainId,
                qosProvider.GetDomainParticipantQos("IngredientApplication"));

            Topic <Temperature> temperatureTopic =
                participant.CreateTopic <Temperature>("ChocolateTemperature");
            Topic <ChocolateLotState> lotStateTopic =
                participant.CreateTopic <ChocolateLotState>("ChocolateLotState");

            ContentFilteredTopic <ChocolateLotState> filteredLotStateTopic =
                participant.CreateContentFilteredTopic(
                    name: "FilteredLot",
                    relatedTopic: lotStateTopic,
                    filter: new Filter(
                        expression: "next_station = %0",
                        parameters: new string[] { $"'{stationKind}'" }));

            Publisher publisher = participant.CreatePublisher();

            // Create DataWriter of Topic "ChocolateLotState"
            // using ChocolateLotStateProfile QoS profile for State Data
            DataWriter <ChocolateLotState> lotStateWriter = publisher.CreateDataWriter(
                lotStateTopic,
                qosProvider.GetDataWriterQos("ChocolateLotStateProfile"));

            Subscriber subscriber = participant.CreateSubscriber();

            // Create DataReader of Topic "ChocolateLotState", filtered by
            // next_station, and using ChocolateLotStateProfile QoS profile for
            // State Data.
            DataReader <ChocolateLotState> lotStateReader = subscriber.CreateDataReader(
                filteredLotStateTopic,
                qosProvider.GetDataReaderQos("ChocolateLotStateProfile"));

            // Monitor the DataAvailable status
            StatusCondition statusCondition = lotStateReader.StatusCondition;

            statusCondition.EnabledStatuses = StatusMask.DataAvailable;
            statusCondition.Triggered      +=
                _ => ProcessLot(currentStation, lotStateReader, lotStateWriter);
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);

            while (!shutdownRequested)
            {
                // Wait for ChocolateLotState
                Console.WriteLine("Waiting for lot");
                waitset.Dispatch(Duration.FromSeconds(10));
            }
        }
Esempio n. 7
0
        private DataWriterQos GetWriterQos(string topicName)
        {
            string qosProfile = parameters.QosLibrary + "::" + GetQoSProfileName(topicName);

            var qosProvider = new QosProvider(parameters.QosFile);

            DataWriterQos dataWriterQos = qosProvider.GetDataWriterQos(qosProfile);

            if (parameters.NoPositiveAcks &&
                (qosProfile == "PerftestQosLibrary::ThroughputQos" ||
                 qosProfile == "PerftestQosLibrary::LatencyQos"))
            {
                dataWriterQos = dataWriterQos.WithProtocol(policy =>
                {
                    policy.DisablePositiveAcks = true;
                    if (parameters.KeepDurationUsec != -1)
                    {
                        policy.RtpsReliableWriter.DisablePositiveAcksMinSampleKeepDuration =
                            Duration.FromMilliseconds((ulong)parameters.KeepDurationUsec / 1000);
                    }
                });
            }

            if (isLargeData || parameters.Asynchronous)
            {
                dataWriterQos = dataWriterQos.WithPublishMode(policy =>
                {
                    policy.Kind = PublishModeKind.Asynchronous;
                    if (!parameters.FlowController.StartsWith("default", true, null))
                    {
                        policy.FlowControllerName = "dds.flow_controller.token_bucket." + parameters.FlowController;
                    }
                });
            }

            // only force reliability on throughput/latency topics
            if (topicName != ANNOUNCEMENT_TOPIC_NAME.Value)
            {
                if (!parameters.BestEffort)
                {
                    // default: use the setting specified in the qos profile
                    dataWriterQos = dataWriterQos.WithReliability(policy =>
                                                                  policy.Kind = ReliabilityKind.Reliable);
                }
                else
                {
                    // override to best-effort
                    dataWriterQos = dataWriterQos.WithReliability(policy =>
                                                                  policy.Kind = ReliabilityKind.BestEffort);
                }
            }

            // These Qos settings are only set for the Throughput datawriter
            if (topicName == THROUGHPUT_TOPIC_NAME.Value)
            {
                if (transport.UseMulticast)
                {
                    dataWriterQos = dataWriterQos.WithProtocol(policy =>
                                                               policy.RtpsReliableWriter.EnableMulticastPeriodicHeartbeat = true);
                }

                if (parameters.BatchSize > 0)
                {
                    dataWriterQos = dataWriterQos.WithBatch(policy =>
                    {
                        policy.Enable       = true;
                        policy.MaxDataBytes = parameters.BatchSize;
                    });
                    dataWriterQos = dataWriterQos.WithResourceLimits(policy =>
                                                                     policy.MaxSamples = LengthUnlimited.Value);
                    dataWriterQos = dataWriterQos.WithWriterResourceLimits(policy =>
                                                                           policy.MaxBatches = (int)parameters.SendQueueSize);
                }
                else
                {
                    dataWriterQos = dataWriterQos.WithResourceLimits(policy =>
                                                                     policy.MaxSamples = (int)parameters.SendQueueSize);
                }

                if (parameters.EnableAutoThrottle)
                {
                    dataWriterQos = dataWriterQos.WithProperty(policy =>
                                                               policy.Add("dds.data_writer.auto_throttle.enable", "true"));
                }
                if (parameters.EnableTurboMode)
                {
                    dataWriterQos = dataWriterQos.WithProperty(policy =>
                                                               policy.Add("dds.data_writer.enable_turbo_mode", "true"));
                    dataWriterQos = dataWriterQos.WithBatch(policy =>
                                                            policy.Enable = false);
                    dataWriterQos = dataWriterQos.WithWriterResourceLimits(policy =>
                                                                           policy.MaxBatches = (int)parameters.SendQueueSize);
                    dataWriterQos = dataWriterQos.WithResourceLimits(policy =>
                                                                     policy.MaxSamples = AllocationSettings.Unlimited);
                }
            }

            return(dataWriterQos);
        }
Esempio n. 8
0
        private DataReaderQos GetReaderQos(string topicName)
        {
            string qosProfile  = parameters.QosLibrary + "::" + GetQoSProfileName(topicName);
            var    qosProvider = new QosProvider(parameters.QosFile);

            DataReaderQos dataReaderQos = qosProvider.GetDataReaderQos(qosProfile);

            // only force reliability on throughput/latency topics
            if (topicName != ANNOUNCEMENT_TOPIC_NAME.Value)
            {
                if (!parameters.BestEffort)
                {
                    dataReaderQos = dataReaderQos.WithReliability(policy =>
                                                                  policy.Kind = ReliabilityKind.Reliable);
                }
                else
                {
                    dataReaderQos = dataReaderQos.WithReliability(policy =>
                                                                  policy.Kind = ReliabilityKind.BestEffort);
                }
            }

            if (parameters.NoPositiveAcks &&
                (topicName == THROUGHPUT_TOPIC_NAME.Value ||
                 topicName == LATENCY_TOPIC_NAME.Value))
            {
                dataReaderQos = dataReaderQos.WithProtocol(policy =>
                                                           policy.DisablePositiveAcks = true);
            }

            if (topicName == THROUGHPUT_TOPIC_NAME.Value ||
                (topicName == LATENCY_TOPIC_NAME.Value &&
                 !directCommunication &&
                 ((DurabilityKind)parameters.Durability == DurabilityKind.Transient ||
                  (DurabilityKind)parameters.Durability == DurabilityKind.Persistent)))
            {
                dataReaderQos = dataReaderQos = dataReaderQos.WithDurability(policy =>
                {
                    policy.Kind = (DurabilityKind)parameters.Durability;
                    policy.DirectCommunication = directCommunication;
                });
            }

            dataReaderQos = dataReaderQos.WithResourceLimits(policy =>
                                                             policy.InitialInstances = (int)(parameters.Instances + 1));
            if (instanceMaxCountReader != -1)
            {
                instanceMaxCountReader++;
            }

            dataReaderQos = dataReaderQos.WithResourceLimits(policy =>
                                                             policy.MaxInstances = instanceMaxCountReader);

            if (parameters.Instances > 1)
            {
                if (parameters.InstanceHashBuckets > 0)
                {
                    dataReaderQos = dataReaderQos.WithResourceLimits(policy =>
                                                                     policy.InstanceHashBuckets = parameters.InstanceHashBuckets);
                }
                else
                {
                    dataReaderQos = dataReaderQos.WithResourceLimits(policy =>
                                                                     policy.InstanceHashBuckets = (int)parameters.Instances);
                }
            }

            if (transport.UseMulticast && transport.AllowsMulticast())
            {
                string multicastAddr = transport.GetMulticastAddr(topicName);

                if (multicastAddr == null)
                {
                    Console.Error.WriteLine("topic name must either be "
                                            + THROUGHPUT_TOPIC_NAME.Value
                                            + " or " + LATENCY_TOPIC_NAME.Value
                                            + " or " + ANNOUNCEMENT_TOPIC_NAME.Value);
                    return(null);
                }

                dataReaderQos = dataReaderQos.WithMulticast(policy =>
                {
                    policy.Value.Add(Rti.Dds.Core.Policy.TransportMulticastSettings.Default);
                    policy.Value[0] = policy.Value[0].With(policy2 =>
                    {
                        policy2.ReceiveAddress = multicastAddr;
                        policy2.ReceivePort    = 0;
                    });
                });
            }

            if (parameters.UnboundedSize > 0)
            {
                dataReaderQos = dataReaderQos.WithProperty(policy =>
                                                           policy.Add("dds.data_reader.history.memory_manager.fast_pool.pool_buffer_max_size",
                                                                      parameters.UnboundedSize.ToString()));
            }

            return(dataReaderQos);
        }
        private void RunExample(int domainId, string sensorId)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // DomainParticipant QoS is configured in USER_QOS_PROFILES.xml
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId);

            // A Topic has a name and a datatype. Create Topics using the types
            // defined in chocolate_factory.xml
            var provider = new QosProvider("../chocolate_factory.xml");
            Topic <Temperature> temperatureTopic = participant.CreateTopic(
                "ChocolateTemperature",
                types.Temperature);
            Topic <ChocolateLotState> lotStateTopic = participant.CreateTopic(
                "ChocolateLotState",
                types.ChocolateLotState);

            // A Publisher allows an application to create one or more DataWriters
            // Publisher QoS is configured in USER_QOS_PROFILES.xml
            Publisher publisher = participant.CreatePublisher();

            // Create DataWriters of Topics "ChocolateTemperature" & "ChocolateLotState"
            // DataWriter QoS is configured in USER_QOS_PROFILES.xml
            DataWriter <Temperature> temperatureWriter =
                publisher.CreateDataWriter(temperatureTopic);
            DataWriter <ChocolateLotState> lotStateWriter =
                publisher.CreateDataWriter(lotStateTopic);

            // A Subscriber allows an application to create one or more DataReaders
            // Subscriber QoS is configured in USER_QOS_PROFILES.xml
            Subscriber subscriber = participant.CreateSubscriber();

            // This DataReader reads data of type Temperature on Topic
            // "ChocolateTemperature". DataReader QoS is configured in
            // USER_QOS_PROFILES.xml
            DataReader <ChocolateLotState> lotStateReader =
                subscriber.CreateDataReader(lotStateTopic);

            // Obtain the DataReader's Status Condition
            StatusCondition statusCondition = lotStateReader.StatusCondition;

            // Enable the 'data available' status.
            statusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate an event handler with the status condition.
            // This will run when the condition is triggered, in the context of
            // the dispatch call (see below)
            statusCondition.Triggered +=
                _ => ProcessLot(lotStateReader, lotStateWriter);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);

            // Create a thread to periodically publish the temperature
            Console.WriteLine($"ChocolateTemperature Sensor with ID: {sensorId} starting");
            var temperatureTask = Task.Run(
                () => PublishTemperature(temperatureWriter, sensorId));

            while (!shutdownRequested)
            {
                // Wait for ChocolateLotState
                Console.WriteLine("Waiting for lot");
                waitset.Dispatch(Duration.FromSeconds(4));
            }

            temperatureTask.Wait();
        }
Esempio n. 10
0
        private void RunExample(
            int domainId,
            int sampleCount,
            string sensorId)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // DomainParticipant QoS is configured in USER_QOS_PROFILES.xml
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId);

            // A Topic has a name and a datatype. Create a Topic named
            // "ChocolateTemperature" with type Temperature
            // In this example we use a DynamicType defined in XML, which creates
            // a DynamicData topic.
            var provider = new QosProvider("../chocolate_factory.xml");
            Topic <DynamicData> topic = participant.CreateTopic(
                "ChocolateTemperature",
                provider.GetType("Temperature"));

            // Exercise #2.1: Add new Topic
            Topic <DynamicData> lotStateTopic = participant.CreateTopic(
                "ChocolateLotState",
                provider.GetType("ChocolateLotState"));

            // A Publisher allows an application to create one or more DataWriters
            // Publisher QoS is configured in USER_QOS_PROFILES.xml
            Publisher publisher = participant.CreatePublisher();

            // This DataWriter writes data on Topic "ChocolateTemperature"
            // DataWriter QoS is configured in USER_QOS_PROFILES.xml
            DataWriter <DynamicData> writer = publisher.CreateDataWriter(topic);

            // Create a DynamicData sample for writing
            DynamicData sample = writer.CreateData();

            // Exercise #2.2: Add new DataWriter and data sample
            DataWriter <DynamicData> lotStateWriter =
                publisher.CreateDataWriter(lotStateTopic);
            DynamicData lotStateSample = lotStateWriter.CreateData();

            Random rand = new Random();

            for (int count = 0; count < sampleCount && !shutdownRequested; count++)
            {
                // Modify the data to be written here
                sample.SetValue("sensor_id", sensorId);
                sample.SetValue("degrees", rand.Next(30, 33));

                Console.WriteLine($"Writing ChocolateTemperature, count {count}");
                writer.Write(sample);

                // Exercise #2.3 Write data with new ChocolateLotState DataWriter
                lotStateWriter.SetValue("lot_id", count % 100);
                // SetAnyValue performs type conversions. In this case it can
                // translate a string to the corresponding enumerator.
                lotStateWriter.SetAnyValue("lot_status", "WAITING");
                lotStateWriter.Write(lotStateSample);

                // Exercise #1.1: Change this to sleep 100 ms in between writing temperatures


                Thread.Sleep(4000);
            }
        }
        private void RunExample(
            int domainId       = 0,
            uint lotsToProcess = 10)
        {
            // Loads the QoS from the qos_profiles.xml file.
            var qosProvider = new QosProvider("./qos_profiles.xml");

            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // Load DomainParticipant QoS profile
            var participantQos = qosProvider.GetDomainParticipantQos(
                "ChocolateFactoryLibrary::MonitoringControlApplication");
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId, participantQos);

            // A Topic has a name and a datatype. Create a Topic with type
            // ChocolateLotState.  Topic name is a constant defined in the IDL file.
            Topic <ChocolateLotState> lotStateTopic =
                participant.CreateTopic <ChocolateLotState>("ChocolateLotState");
            // Add a Topic for Temperature to this application
            Topic <Temperature> temperatureTopic =
                participant.CreateTopic <Temperature>("ChocolateTemperature");
            ContentFilteredTopic <Temperature> filteredTemperatureTopic =
                participant.CreateContentFilteredTopic(
                    name: "FilteredTemperature",
                    relatedTopic: temperatureTopic,
                    filter: new Filter(
                        expression: "degrees > %0 or degrees < %1",
                        parameters: new string[] { "32", "30" }));

            // A Publisher allows an application to create one or more DataWriters
            // Publisher QoS is configured in USER_QOS_PROFILES.xml
            Publisher publisher = participant.CreatePublisher();

            // This DataWriter writes data on Topic "ChocolateLotState"
            var writerQos = qosProvider.GetDataWriterQos(
                "ChocolateFactoryLibrary::ChocolateLotStateProfile");
            DataWriter <ChocolateLotState> lotStateWriter =
                publisher.CreateDataWriter(lotStateTopic, writerQos);

            // A Subscriber allows an application to create one or more DataReaders
            // Subscriber QoS is configured in USER_QOS_PROFILES.xml
            Subscriber subscriber = participant.CreateSubscriber();

            // Create DataReader of Topic "ChocolateLotState".
            // DataReader QoS is configured in USER_QOS_PROFILES.xml
            var readerQos = qosProvider.GetDataReaderQos(
                "ChocolateFactoryLibrary::ChocolateLotStateProfile");
            DataReader <ChocolateLotState> lotStateReader =
                subscriber.CreateDataReader(lotStateTopic, readerQos);

            // Add a DataReader for Temperature to this application
            readerQos = qosProvider.GetDataReaderQos(
                "ChocolateFactoryLibrary::ChocolateTemperatureProfile");
            DataReader <Temperature> temperatureReader =
                subscriber.CreateDataReader(filteredTemperatureTopic, readerQos);

            // Obtain the DataReader's Status Condition
            StatusCondition temperatureStatusCondition = temperatureReader.StatusCondition;

            temperatureStatusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate a handler with the status condition. This will run when the
            // condition is triggered, in the context of the dispatch call (see below)
            temperatureStatusCondition.Triggered +=
                _ => MonitorTemperature(temperatureReader);

            // Do the same with the lotStateReader's StatusCondition
            StatusCondition lotStateStatusCondition = lotStateReader.StatusCondition;

            lotStateStatusCondition.EnabledStatuses = StatusMask.DataAvailable;

            int lotsProcessed = 0;

            lotStateStatusCondition.Triggered +=
                _ => lotsProcessed            += MonitorLotState(lotStateReader);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(lotStateStatusCondition);

            // Add the new DataReader's StatusCondition to the Waitset
            waitset.AttachCondition(temperatureStatusCondition);

            // Start publishing in a separate thread
            var startLotTask = Task.Run(() => PublishStartLot(lotStateWriter, lotsToProcess));

            while (!shutdownRequested && lotsProcessed < lotsToProcess)
            {
                waitset.Dispatch(Duration.FromSeconds(4));
            }

            startLotTask.Wait();
        }
        private void RunExample(int domainId, string sensorId)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // Uses TemperingApplication QoS profile to set participant name.
            var qosProvider    = new QosProvider("./qos_profiles.xml");
            var participantQos = qosProvider.GetDomainParticipantQos(
                "ChocolateFactoryLibrary::TemperingApplication");
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId, participantQos);

            // Create the topics
            Topic <Temperature> temperatureTopic =
                participant.CreateTopic <Temperature>("ChocolateTemperature");
            Topic <ChocolateLotState> lotStateTopic =
                participant.CreateTopic <ChocolateLotState>("ChocolateLotState");

            // Exercise #1.1: Create a Content-Filtered Topic that filters out
            // chocolate lot state unless the next_station = TEMPERING_CONTROLLER

            // A Publisher allows an application to create one or more DataWriters
            // Create Publisher with default QoS.
            Publisher publisher = participant.CreatePublisher();

            // Create DataWriter of Topic "ChocolateTemperature"
            // using ChocolateTemperatureProfile QoS profile for Streaming Data
            DataWriter <Temperature> temperatureWriter = publisher.CreateDataWriter(
                temperatureTopic,
                qos: qosProvider.GetDataWriterQos("ChocolateFactoryLibrary::ChocolateTemperatureProfile"));

            // Create DataWriter of Topic "ChocolateLotState"
            // using ChocolateLotStateProfile QoS profile for State Data
            DataWriter <ChocolateLotState> lotStateWriter = publisher.CreateDataWriter(
                lotStateTopic,
                qos: qosProvider.GetDataWriterQos("ChocolateFactoryLibrary::ChocolateLotStateProfile"));

            // A Subscriber allows an application to create one or more DataReaders
            Subscriber subscriber = participant.CreateSubscriber();

            // Create DataReader of Topic "ChocolateLotState".
            // using ChocolateLotStateProfile QoS profile for State Data
            // Exercise #1.2: Change the DataReader's Topic to use a
            // Content-Filtered Topic
            DataReader <ChocolateLotState> lotStateReader = subscriber.CreateDataReader(
                lotStateTopic,
                qos: qosProvider.GetDataReaderQos("ChocolateFactoryLibrary::ChocolateLotStateProfile"),
                preEnableAction: reader => reader.RequestedIncompatibleQos += OnRequestedIncompatibleQos);

            // Obtain the DataReader's Status Condition
            StatusCondition statusCondition = lotStateReader.StatusCondition;

            // Enable the 'data available' status.
            statusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate an event handler with the status condition.
            // This will run when the condition is triggered, in the context of
            // the dispatch call (see below)
            statusCondition.Triggered +=
                _ => ProcessLot(lotStateReader, lotStateWriter);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);

            // Create a thread to periodically publish the temperature
            Console.WriteLine($"ChocolateTemperature Sensor with ID: {sensorId} starting");
            var temperatureTask = Task.Run(
                () => PublishTemperature(temperatureWriter, sensorId));

            while (!shutdownRequested)
            {
                // Wait for ChocolateLotState
                Console.WriteLine("Waiting for lot");
                waitset.Dispatch(Duration.FromSeconds(10));
            }

            temperatureTask.Wait();
        }
        private void RunExample(int domainId, string sensorId)
        {
            // A DomainParticipant allows an application to begin communicating in
            // a DDS domain. Typically there is one DomainParticipant per application.
            // Uses TemperingApplication QoS profile to set participant name.
            var qosProvider    = new QosProvider("./qos_profiles.xml");
            var participantQos = qosProvider.GetDomainParticipantQos(
                "ChocolateFactoryLibrary::TemperingApplication");
            DomainParticipant participant = DomainParticipantFactory.Instance
                                            .CreateParticipant(domainId, participantQos);

            // A Topic has a name and a datatype.
            Topic <Temperature> temperatureTopic = participant.CreateTopic <Temperature>(
                CHOCOLATE_TEMPERATURE_TOPIC.Value);
            Topic <ChocolateLotState> lotStateTopic = participant.CreateTopic <ChocolateLotState>(
                CHOCOLATE_LOT_STATE_TOPIC.Value);

            // A Publisher allows an application to create one or more DataWriters
            // Create Publisher with default QoS.
            Publisher publisher = participant.CreatePublisher();

            // Create DataWriter of Topic "ChocolateTemperature"
            // using ChocolateTemperatureProfile QoS profile for Streaming Data
            DataWriter <Temperature> temperatureWriter = publisher.CreateDataWriter(
                temperatureTopic,
                qos: qosProvider.GetDataWriterQos("ChocolateFactoryLibrary::ChocolateTemperatureProfile"));

            // Create DataWriter of Topic "ChocolateLotState"
            // using ChocolateLotStateProfile QoS profile for State Data
            DataWriter <ChocolateLotState> lotStateWriter = publisher.CreateDataWriter(
                lotStateTopic,
                qos: qosProvider.GetDataWriterQos("ChocolateFactoryLibrary::ChocolateLotStateProfile"));

            // A Subscriber allows an application to create one or more DataReaders
            Subscriber subscriber = participant.CreateSubscriber();

            // This DataReader reads data of type Temperature on Topic
            // "ChocolateTemperature" using ChocolateLotStateProfile QoS
            // profile for State Data.
            //
            // We will handle the "requested incompatible qos" event. By doing
            // it as a preEnableAction, we avoid a race condition in which
            // the event could trigger right after the reader creation but
            // right before adding the event handler.
            DataReader <ChocolateLotState> lotStateReader = subscriber.CreateDataReader(
                lotStateTopic,
                qos: qosProvider.GetDataReaderQos("ChocolateFactoryLibrary::ChocolateLotStateProfile"),
                preEnableAction: reader => reader.RequestedIncompatibleQos += OnRequestedIncompatibleQos);

            // Obtain the DataReader's Status Condition
            StatusCondition statusCondition = lotStateReader.StatusCondition;

            // Enable the 'data available' status.
            statusCondition.EnabledStatuses = StatusMask.DataAvailable;

            // Associate an event handler with the status condition.
            // This will run when the condition is triggered, in the context of
            // the dispatch call (see below)
            statusCondition.Triggered +=
                _ => ProcessLot(lotStateReader, lotStateWriter);

            // Create a WaitSet and attach the StatusCondition
            var waitset = new WaitSet();

            waitset.AttachCondition(statusCondition);

            // Create a thread to periodically publish the temperature
            Console.WriteLine($"ChocolateTemperature Sensor with ID: {sensorId} starting");
            var temperatureTask = Task.Run(
                () => PublishTemperature(temperatureWriter, sensorId));

            while (!shutdownRequested)
            {
                // Wait for ChocolateLotState
                Console.WriteLine("Waiting for lot");
                waitset.Dispatch(Duration.FromSeconds(4));
            }

            temperatureTask.Wait();
        }