virtualsensor_internal.h 6.66 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * virtualsensor_internal.h
 *
 *  Created on: Jan 18, 2016
 *      Author: Axel Auweter
 */

/**
 * @file
 * @brief This file contains internal classes for handling virtual sensors.
 */

#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

17
18
19
20
#include <cstdint>
#include <string>
#include <list>
#include <unordered_set>
21
22
#include <unordered_map>
#include <map>
23
24
25

#include "timestamp.h"
#include "sensorid.h"
26
#include "sensordatastore.h"
27
28
29

#include "virtualsensor.h"

30
31
32
33
34
#ifndef DCDB_VIRTUAL_SENSOR_INTERNAL_H
#define DCDB_VIRTUAL_SENSOR_INTERNAL_H

namespace DCDB {

35
36
37
38
39
40
41
42
43
44
45
46
47
/**
 * @brief Exception class for errors during Physical Sensor Evaluation
 *
 * Exceptions of this type are thrown whenever the the evaluation of
 * a physical sensor is impossible due to data being out of range.
 * What() returns a human readable error string.
 */
class PhysicalSensorEvaluatorException : public std::runtime_error
{
public:
  PhysicalSensorEvaluatorException(const std::string& msg) : runtime_error(msg) {}
};

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class PhysicalSensorCache {
protected:
  std::map<uint64_t, SensorDataStoreReading> cache;
  PublicSensor s;
  void populate(Connection* connection, SensorConfig& sc, uint64_t t);

public:
  void getBefore(Connection* connection, SensorConfig& sc, SensorDataStoreReading& r, uint64_t t);
  void getAfter(Connection* connection, SensorConfig& sc, SensorDataStoreReading& r, uint64_t t);

  PhysicalSensorCache(PublicSensor sensor);
  virtual ~PhysicalSensorCache();
};

typedef std::unordered_map<std::string, PhysicalSensorCache*> PhysicalSensorCacheContainer;

namespace VirtualSensor {

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

/**
 * @brief Definitions for objects in the Virtual Sensor expression's AST.
 */
namespace AST {

/**
 * @brief The NIL object.
 *
 * The NIL object represents a no-op or empty operand in the AST.
 */
struct Nil {};

/**
 * @brief The SIGNED object.
 *
 * The SIGNED object represents a positive or negative sign preceding an operand in the AST.
 */
struct Signd;

/**
 * @brief The OPSEQ object.
 *
 * The OPSEQ object represents a sequence of operations in the AST.
 */
struct Opseq;

/**
 * @brief The OP object.
 *
 * The OP object represents a simple operation in the AST.
 */
struct Op;

typedef boost::variant<
    Nil,
    unsigned int,
105
    std::string,
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
    boost::recursive_wrapper<Signd>,
    boost::recursive_wrapper<Opseq>
  > Operand;

struct Signd {
  char sgn;
  Operand oprnd;
};

struct Opseq {
  Operand frst;
  std::list<Op> rst;
};

struct Op {
  char oprtr;
  Operand oprnd;
};

} /* End of namespace AST */
} /* End of namespace VirtualSensor */
} /* End of namespace DCDB */

/*
 * Create Random Access Sequence for AST Objects.
 * These must be created at the top of namespaces but obviously after defining the structs.
 */
BOOST_FUSION_ADAPT_STRUCT (
    DCDB::VirtualSensor::AST::Signd,
    (char, sgn)
    (DCDB::VirtualSensor::AST::Operand, oprnd)
)

BOOST_FUSION_ADAPT_STRUCT (
    DCDB::VirtualSensor::AST::Opseq,
    (DCDB::VirtualSensor::AST::Operand, frst)
    (std::list<DCDB::VirtualSensor::AST::Op>, rst)
)

BOOST_FUSION_ADAPT_STRUCT (
    DCDB::VirtualSensor::AST::Op,
    (char, oprtr)
    (DCDB::VirtualSensor::AST::Operand, oprnd)
)

namespace DCDB {
namespace VirtualSensor {

/**
 * @brief The ExpressionGrammar struct holds the grammar definition for
 *        the arithmetic expressions that describe virtual sensors.
 *
 * Since we're using the Boost Spirit framework's Qi parser generator,
 * we define the grammar using the qi syntax and built-in qi parsers
 * (e.g. qi::uint_ or qi:hex).
 */
template <typename Iterator>
struct ExpressionGrammar : qi::grammar<Iterator, AST::Opseq(), ascii::space_type>
{
  ExpressionGrammar() : ExpressionGrammar::base_type(expression)
  {
    expression =
        term
        >> *(   (qi::char_('+') >> term)
            |   (qi::char_('-') >> term)
            )
        ;

    term =
        factor
        >> *(   (qi::char_('*') >> factor)
            |   (qi::char_('/') >> factor)
            )
        ;

    factor =
        ("0x" >> qi::hex)
        |   qi::uint_
        |   '(' >> expression >> ')'
        |   (qi::char_('-') >> factor)
        |   (qi::char_('+') >> factor)
187
        |   sensor
188
        ;
189

190
191
192
193
194
  }

  qi::rule<Iterator, AST::Opseq(), ascii::space_type> expression;
  qi::rule<Iterator, AST::Opseq(), ascii::space_type> term;
  qi::rule<Iterator, AST::Operand(), ascii::space_type> factor;
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  qi::symbols<char, std::string> sensor;

  /**
   * @brief Populates the parser grammar with a symbol table of available sensor names.
   *
   * Since it eases the implementation, references to sensors in the virtual sensor
   * expressions are parsed as symbols by the Qi parser. Therefore, we have to populate
   * the list of sensors from the public sensors table during runtime. This should be
   * done always after instantiating objects of the ExpressionGrammar.
   */
  void addSensorNames(std::list<std::string> sensorNames) {
    for (std::list<std::string>::iterator it = sensorNames.begin(); it != sensorNames.end(); it++) {
        sensor.add (it->c_str(), *it);
    }
  }
210
211
};

212
213
214
215
216
217
218
/**
 * @brief Private implementation class for evaluating Virtual Sensors expressions
 *
 * This class implements the expression parser and provides functions that create an
 * unordered set of inputs required to evaluate the expression.
 */
class VSensorExpressionImpl
219
220
{
protected:
221
  Connection* connection;
222
223
  VirtualSensor::AST::Opseq opseq;

224
  void generateAST(std::string expr);
225
226
  void dumpAST();

227
  static int64_t physicalSensorInterpolator(Connection* connection, SensorConfig& sc,  PhysicalSensorCacheContainer& pscc, PublicSensor& sensor, TimeStamp t);
228

229
public:
230
231
232
  void getInputs(std::unordered_set<std::string>& inputSet);
  void getInputsRecursive(std::unordered_set<std::string>& inputSet, bool virtualOnly);

233
  int64_t evaluateAt(TimeStamp time, PhysicalSensorCacheContainer& pscc);
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

  VSensorExpressionImpl(Connection* conn, std::string expr);
  virtual ~VSensorExpressionImpl();
};

/**
 * @brief Private implementation class for querying virtual sensors
 *
 * TODO: Implement this...
 */
class VSensorImpl
{
protected:
  Connection* connection;
  std::string name;
  VSensorExpressionImpl* expression;
  SensorId* vsensorid;
  TimeStamp tzero;
  uint64_t frequency;
253
  static PhysicalSensorCacheContainer physicalSensorCaches;
254
255
256
257
258
259

public:
  VSError query(std::list<SensorDataStoreReading>& result, TimeStamp& start, TimeStamp& end);

  VSensorImpl(Connection *conn, std::string name);
  VSensorImpl(Connection *conn, PublicSensor sensor);
260
261
262
263
264
265
266
  virtual ~VSensorImpl();
};

} /* End of namesapce VirtualSensor */
} /* End of namespace DCDB */

#endif /* DCDB_VIRTUAL_SENSOR_INTERNAL_H */