DetectorGraph  2.0
helloworld.cpp File Reference

The basics - A trivial Graph with a single Detector. More...

Go to the source code of this file.

Detailed Description

The basics - A trivial Graph with a single Detector.

Introduction

This examples cover the basics of using the DetectorGraph framework - a "Hello World" of sorts. For the purposes of this example imagine a temperature sensor that produces samples regularly and that we're tasked to signal other parts of the system whenever that temperature crosses a threshold.

We start by splitting the problem, within the scope of our task, in three parts:

Topics

Topics are defined by the DetectorGraph::TopicState type they carry. A TopicState is any C++ struct/class that inherits from DetectorGraph::TopicState.

For the 'input' to our system we'll declare a TemperatureSample TopicState:

131 struct TemperatureSample : public DetectorGraph::TopicState
132 {
133  TemperatureSample(int aTemp = 0) : temperature(aTemp) {}
134  int temperature;
135 };
Base struct for topic data types.
Definition: topicstate.hpp:52

The important here is that this struct inherits TopicState and that it has data field(s).

Next we define the 'output'; another struct that also inherits DetectorGraph::TopicState and has data fields:

139 struct OverheatingState : public DetectorGraph::TopicState
140 {
141  OverheatingState(bool aState = false) : isOverheating(aState) {}
142  bool isOverheating;
143 };
Base struct for topic data types.
Definition: topicstate.hpp:52

Detector

Now we just need to fill in the gap; the Detector that creates OverheatingState from TemperatureSample: two.

147 class OverheatingDetector : public DetectorGraph::Detector
148 , public DetectorGraph::SubscriberInterface<TemperatureSample>
149 , public DetectorGraph::Publisher<OverheatingState>
150 {
151 public:
152  OverheatingDetector(DetectorGraph::Graph* graph) : DetectorGraph::Detector(graph)
153  {
154  Subscribe<TemperatureSample>(this);
155  SetupPublishing<OverheatingState>(this);
156  }
157 
158  virtual void Evaluate(const TemperatureSample& sample)
159  {
160  if (sample.temperature > kThreshold)
161  {
162  Publish(OverheatingState(true));
163  }
164  else
165  {
166  Publish(OverheatingState(false));
167  }
168  }
169 
170  static const int kThreshold = 100;
171 };
Implements a graph of Topics & Detectors with Input/Output APIs.
Definition: graph.hpp:127
virtual void Evaluate(const T &)=0
Pure-virtual method that should Evaluate a piece of input data.
void Publish(const T &data)
Publish a new version of T to a Topic.
Definition: publisher.hpp:85
Base class that implements a Publisher behavior.
Definition: publisher.hpp:66
A unit of logic in a DetectorGraph.
Definition: detector.hpp:68
A Pure interface that declares the Subscriber behavior.

Graph

The final plumbing is to add our newly created Detector to a DetectorGraph::Graph. Depending on the situation this can be done in different ways but here's the simplest:

242  DetectorGraph::Graph graph;
243  OverheatingDetector detector(&graph);
Implements a graph of Topics & Detectors with Input/Output APIs.
Definition: graph.hpp:127

With that the Graph instance will internally create the following graph:

HelloWorldGraph

Topics are represented by rectangles, Detectors by the oval shapes and arrows follow the flow of data - this is the standard representation for DetectorGraph graphs. The numeric prefix to the names is each node's order in the Topological sort of the graph. Output topics are painted Lime Green and input ones Light Blue.

Usage

Finally, using the graph is done by Pushing data in, evaluating the graph and checking outputs:

247  graph.PushData(TemperatureSample(110));
248  graph.EvaluateGraph();
249 
250  const OverheatingState& output =
251  graph.ResolveTopic<OverheatingState>()->GetNewValue();
252  cout << "IsOverheating = " << ((output.isOverheating) ? "true" : "false") << endl;
void PushData(const TTopicState &aTopicState)
Push data to a specific topic in the graph.
Definition: graph.hpp:187
Topic< TTopicState > * ResolveTopic()
Find/add a topic in the detector graph.
Definition: graph.hpp:160
ErrorType EvaluateGraph()
Evaluate the whole graph.
Definition: graph.cpp:133

Running the program then gives:

DetectorGraph: Graph Initialized
IsOverheating = true

An alternative way to do things is to subclass the DetectorGraph::ProcessorContainer utility that streamlines the DetectorGraph::Graph::PushData, DetectorGraph::Graph::EvaluateGraph and subsequent inspection steps. For the example above, the DetectorGraph::ProcessorContainer implementation would be:

175 class HelloWorldGraph : public DetectorGraph::ProcessorContainer
176 {
177 public:
178  HelloWorldGraph()
179  : mOverheatingDetector(&mGraph)
180  {
181  }
182 
183  OverheatingDetector mOverheatingDetector;
184 
185  virtual void ProcessOutput()
186  {
187  DetectorGraph::Topic<OverheatingState>* overheatingStateTopic = mGraph.ResolveTopic<OverheatingState>();
188  if (overheatingStateTopic->HasNewValue())
189  {
190  const OverheatingState& overheatingState = overheatingStateTopic->GetNewValue();
191  cout << "OverheatingState.isOverheating = " << ((overheatingState.isOverheating) ? "true" : "false") << endl;
192  }
193  }
194 };
bool HasNewValue() const
Returns true if the new Data is available.
Definition: topic.hpp:166
A Base class for a basic Graph container.
Manage data and its handler.
Definition: topic.hpp:84
virtual void ProcessOutput()=0
Called after each Graph Evaluation.
const T & GetNewValue() const
Returns reference to the new/latest value in the topic.
Definition: topic.hpp:179

And then usage would be like:

256  HelloWorldGraph thermostat;
257  thermostat.ProcessData(TemperatureSample(70));
258  thermostat.ProcessData(TemperatureSample(90));
259  thermostat.ProcessData(TemperatureSample(100));
260  thermostat.ProcessData(TemperatureSample(110));
261  thermostat.ProcessData(TemperatureSample(120));
DetectorGraph: Graph Initialized
OverheatingState.isOverheating = false
OverheatingState.isOverheating = false
OverheatingState.isOverheating = false
OverheatingState.isOverheating = true
OverheatingState.isOverheating = true

This example can be built with:

g++ -std=c++11 -I./include/ -I./platform_standalone/ src/graph.cpp src/detector.cpp platform_standalone/dglogging.cpp examples/helloworld.cpp -o helloworld.out

Definition in file helloworld.cpp.