Motorcortex Core  version: 2.7.6
sg_monitor.h
1 /*
2  * Developer : Alexey Zakharov (alexey.zakharov@vectioneer.com)
3  * All rights reserved. Copyright (c) 2016 VECTIONEER.
4  */
5 
6 #ifndef SG_MONITOR_H
7 #define SG_MONITOR_H
8 
9 #include "sg_monitorbase.h"
10 #include "sg_signalidgroup.h"
11 #include "utl_log.h"
12 
13 #include <functional>
14 #include <algorithm>
15 #include <limits>
16 #include <vector>
17 #include <queue>
18 
19 namespace mcx {
20 
21 namespace signal_monitor {
22 
23 template<typename t>
24 struct bool_stub { // bug in stl, containers treat bool as bit field
25  using type = t;
26 };
27 
28 template<>
29 struct bool_stub<bool> {
30  using type = char;
31 };
32 
33 template<typename T, typename CompareFunctor = std::equal_to<T>>
35 
36  struct signal_data {
37  bool enabled;
38  TriggerType trigger_type;
39  bool changed;
40  double start_time_s;
41  double actual_time_s;
42  double stop_time_s;
43  CompareFunctor cmp;
44  bool input_ref_is_local;
45  std::reference_wrapper<T> input_ref;
46  T objective;
47  std::function<bool(void)> clb;
48  };
49 
50  T dummy;
51 
52  class SignalDataFactory {
53  public:
54 
55  static signal_data make(const SignalId& signal_id, T& input_ref,
56  T objective_val, std::function<bool()> callback,
57  TriggerType trigger_type, double start_time_s,
58  double stop_time_s, bool input_ref_is_local) {
59 
60  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
61  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
62  .stop_time_s = stop_time_s, .cmp =
63  {},
64  .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
65  .objective = objective_val, .clb = callback};
66 
67  return sd;
68  }
69 
70  static signal_data make(const SignalId& signal_id, T& input_ref,
71  T objective_val, std::function<bool(const SignalId&)> callback,
72  TriggerType trigger_type, double start_time_s,
73  double stop_time_s, bool input_ref_is_local) {
74 
75  auto clb = std::bind(callback, signal_id);
76  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
77  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
78  .stop_time_s = stop_time_s, .cmp =
79  {},
80  .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
81  .objective = objective_val, .clb = clb};
82 
83  return sd;
84  }
85 
86  static signal_data make(const SignalId& signal_id, T& input_ref,
87  T objective_val, std::function<bool(const SignalId&, T)> callback,
88  TriggerType trigger_type, double start_time_s, double stop_time_s,
89  bool input_ref_is_local) {
90 
91  auto clb = std::bind(callback, signal_id, std::ref(input_ref));
92  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
93  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
94  .stop_time_s = stop_time_s, .cmp =
95  {}, .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
96  .objective = objective_val, .clb = clb};
97 
98  return sd;
99  }
100 
101  template<typename U>
102  static signal_data make(const SignalId& signal_id, T& input_ref,
103  T objective_val, std::pair<std::function<bool(U*)>, U*
104 
105  > callback,
106  TriggerType trigger_type,
107  double start_time_s,
108  double stop_time_s,
109  bool input_ref_is_local
110  ) {
111 
112  auto clb = std::bind(callback.first, callback.second);
113  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
114  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
115  .stop_time_s = stop_time_s, .cmp =
116  {}, .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
117  .objective = objective_val, .clb = clb};
118 
119  return sd;
120  }
121 
122  template<typename U>
123  static signal_data make(const SignalId& signal_id, T& input_ref,
124  T objective_val,
125  std::pair<std::function<bool(U*, const SignalId& signal_id)>, U*> callback,
126  TriggerType trigger_type, double start_time_s, double stop_time_s,
127  bool input_ref_is_local) {
128 
129  auto clb = std::bind(callback.first, callback.second, signal_id);
130  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
131  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
132  .stop_time_s = stop_time_s, .cmp =
133  {}, .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
134  .objective = objective_val, .clb = clb};
135 
136  return sd;
137  }
138 
139  template<typename U>
140  static signal_data make(const SignalId& signal_id, T& input_ref,
141  T objective_val, std::pair<std::function<bool(U*, const SignalId&, T)>, U*> callback,
142  TriggerType trigger_type, double start_time_s, double stop_time_s,
143  bool input_ref_is_local) {
144 
145  auto clb = std::bind(callback.first, callback.second, signal_id,
146  std::ref(input_ref));
147  signal_data sd = {.enabled = true, .trigger_type = trigger_type,
148  .changed = true, .start_time_s = start_time_s, .actual_time_s = 0,
149  .stop_time_s = stop_time_s, .cmp =
150  {}, .input_ref_is_local = input_ref_is_local, .input_ref = input_ref,
151  .objective = objective_val, .clb = clb};
152 
153  return sd;
154  }
155  };
156 
157  std::queue<typename bool_stub<T>::type> values_storage_;
158  using callback_data = std::pair<SignalId, signal_data>;
159  std::vector<callback_data> callback_vector_;
160 
161  void addToVector(const SignalId& signal_id, signal_data&& clb_data) {
162  // always keep array sorted, to optimize number of iterations for search
163  typename std::vector<callback_data>::iterator itr =
164  std::find_if(callback_vector_.begin(), callback_vector_.end(),
165  [&](const auto& obj) {
166  return obj.first >= signal_id;
167  });
168  callback_vector_.emplace(itr, std::make_pair(signal_id, clb_data));
169  }
170 
171  bool isInRange(const signal_data& data) const {
172  return (data.start_time_s <= data.actual_time_s) &&
173  (data.actual_time_s < data.stop_time_s);
174  }
175 
176  template<typename Action>
177  void seekAndDestroy(const SignalIdGroup& signal_id_group, const Action& action) {
178  auto new_err_itr = signal_id_group.begin();
179  auto new_err_end = signal_id_group.end();
180 
181  auto err_itr = callback_vector_.begin();
182  auto prev_itr = err_itr;
183  auto err_end = callback_vector_.end();
184 
185  // signal_id_group is sorted and callback vector is sorted
186  // callback might have multiple instances of a searched key
187  for (; new_err_itr != new_err_end; ++new_err_itr) {
188  if (err_itr == err_end) {
189  err_itr = prev_itr;
190  }
191  while ((err_itr != err_end) && (err_itr->first <= *new_err_itr)) {
192  err_itr = std::find_if(err_itr, err_end, [&](const auto& obj) {
193  return obj.first == *new_err_itr;
194  });
195  if (err_itr != err_end) {
196  action(err_itr->second);
197  ++err_itr;
198  prev_itr = err_itr;
199  }
200  }
201  }
202  }
203 
204 public:
205  // adding base class methods, otherwise they are not visible to a compiler
206  using SignalMonitorBase::set;
207  using SignalMonitorBase::reset;
208  using SignalMonitorBase::enable;
209  using SignalMonitorBase::disable;
210 
211  SignalMonitor(void) : callback_vector_() {
212  }
213 
214  virtual ~SignalMonitor(void) {
215 
216  }
217 
218  void add(const SignalId& signal_id, T& input_ref, T objective_val,
219  std::function<bool()> callback, TriggerType trigger_type = TRIGGER_ALWAYS,
220  double start_time_s = 0,
221  double stop_time_s = std::numeric_limits<double>::max()) {
222 
223  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
224  objective_val, callback, trigger_type, start_time_s, stop_time_s,
225  false));
226 
227  }
228 
229  void add(const SignalId& signal_id, T& input_ref, T objective_val,
230  std::function<bool(const SignalId& signal_id)> callback,
231  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
232  double stop_time_s = std::numeric_limits<double>::max()) {
233 
234  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
235  objective_val, callback, trigger_type, start_time_s, stop_time_s,
236  false));
237 
238  }
239 
240  void add(const SignalId& signal_id, T& input_ref, T objective_val,
241  std::function<bool(const SignalId& signal_id, T)> callback,
242  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
243  double stop_time_s = std::numeric_limits<double>::max()) {
244 
245  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
246  objective_val, callback, trigger_type, start_time_s, stop_time_s,
247  false));
248 
249  }
250 
251  template<typename U>
252  void add(const SignalId& signal_id, T& input_ref, T objective_val,
253  std::pair<std::function<bool(U*)>, U*> callback,
254  TriggerType trigger_type = TRIGGER_ALWAYS,
255  double start_time_s = 0,
256  double stop_time_s = std::numeric_limits<double>::max()
257  ) {
258 
259  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
260  objective_val, callback, trigger_type, start_time_s, stop_time_s,
261  false));
262 
263  }
264 
265  template<typename U>
266  void add(const SignalId& signal_id, T& input_ref, T objective_val,
267  std::pair<std::function<bool(U*, const SignalId& signal_id)>, U*> callback,
268  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
269  double stop_time_s = std::numeric_limits<double>::max()) {
270 
271  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
272  objective_val, callback, trigger_type, start_time_s, stop_time_s,
273  false));
274 
275  }
276 
277  template<typename U>
278  void add(const SignalId& signal_id, T& input_ref, T objective_val,
279  std::pair<std::function<bool(U*, const SignalId& signal_id, T)>, U*> callback,
280  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
281  double stop_time_s = std::numeric_limits<double>::max()) {
282 
283  addToVector(signal_id, SignalDataFactory::make(signal_id, input_ref,
284  objective_val, callback, trigger_type, start_time_s, stop_time_s,
285  false));
286 
287  }
288 
289  //
290 
291  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
292  std::function<bool()> callback, TriggerType trigger_type = TRIGGER_ALWAYS,
293  double start_time_s = 0,
294  double stop_time_s = std::numeric_limits<double>::max()) {
295 
296  values_storage_.push(std::move(input_val));
297  addToVector(signal_id, SignalDataFactory::make(signal_id,
298  reinterpret_cast<T&> (values_storage_.back()), objective_val,
299  callback,
300  trigger_type, start_time_s, stop_time_s, true));
301 
302  }
303 
304  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
305  std::function<bool(const SignalId& signal_id)> callback,
306  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
307  double stop_time_s = std::numeric_limits<double>::max()) {
308 
309  values_storage_.push(std::move(input_val));
310  addToVector(signal_id, SignalDataFactory::make(signal_id,
311  reinterpret_cast<T&> (values_storage_.back()), objective_val,
312  callback,
313  trigger_type, start_time_s, stop_time_s, true));
314 
315  }
316 
317  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
318  std::function<bool(const SignalId& signal_id, T)> callback,
319  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
320  double stop_time_s = std::numeric_limits<double>::max()) {
321 
322  values_storage_.push(std::move(input_val));
323  addToVector(signal_id, SignalDataFactory::make(signal_id,
324  reinterpret_cast<T&> (values_storage_.back()), objective_val,
325  callback,
326  trigger_type = TRIGGER_ALWAYS, start_time_s, stop_time_s, true));
327 
328  }
329 
330  template<typename U>
331  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
332  std::pair<std::function<bool(U*)>, U*> callback,
333  TriggerType trigger_type = TRIGGER_ALWAYS,
334  double start_time_s = 0,
335  double stop_time_s = std::numeric_limits<double>::max()
336  ) {
337 
338  values_storage_.push(std::move(input_val));
339  addToVector(signal_id, SignalDataFactory::make(signal_id,
340  reinterpret_cast<T&> (values_storage_.back()), objective_val,
341  callback,
342  trigger_type, start_time_s, stop_time_s, true));
343 
344  }
345 
346  template<typename U>
347  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
348  std::pair<std::function<bool(U*, const SignalId& signal_id)>, U*> callback,
349  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
350  double stop_time_s = std::numeric_limits<double>::max()) {
351 
352  values_storage_.push(std::move(input_val));
353  addToVector(signal_id, SignalDataFactory::make(signal_id,
354  reinterpret_cast<T&> (values_storage_.back()), objective_val,
355  callback,
356  trigger_type, start_time_s, stop_time_s, true));
357 
358  }
359 
360  template<typename U>
361  void add(const SignalId& signal_id, const T&& input_val, T objective_val,
362  std::pair<std::function<bool(U*, const SignalId& signal_id, T)>, U*> callback,
363  TriggerType trigger_type = TRIGGER_ALWAYS, double start_time_s = 0,
364  double stop_time_s = std::numeric_limits<double>::max()) {
365 
366  values_storage_.push(std::move(input_val));
367  addToVector(signal_id, SignalDataFactory::make(signal_id,
368  reinterpret_cast<T&> (values_storage_.back()), objective_val,
369  callback,
370  trigger_type, start_time_s, stop_time_s, true));
371 
372  }
373 
374  void iterate(double dt_sec);
375 
376  void set(const SignalId& signal_id);
377 
378  void set(const SignalId& signal_id, const T& value);
379 
380  void setObjective(const SignalId& signal_id, const T& value);
381 
382  void reset(const SignalId& signal_id);
383 
384  void enable(const SignalId& signal_id);
385 
386  void disable(const SignalId& signal_id);
387 
388  void set(const SignalIdGroup& signal_id_group);
389 
390  void reset(const SignalIdGroup& signal_id_group);
391 
392  void enable(const SignalIdGroup& signal_id_group);
393 
394  void disable(const SignalIdGroup& signal_id_group);
395 
396  void reset(void);
397 
398  void enable(void);
399 
400  void disable(void);
401 
402 };
403 
404 template<typename T, typename CompareFunctor>
405 void SignalMonitor<T, CompareFunctor>::iterate(double dt_sec) {
406  for (auto& a : callback_vector_) {
407  auto& signal_data = a.second;
408  if (signal_data.enabled) {
409  bool signal_cmp = signal_data.cmp(signal_data.input_ref, signal_data.objective);
410  if (isInRange(signal_data) && signal_cmp) {
411  switch (signal_data.trigger_type) {
412  case TriggerType::TRIGGER_ONCE:
413  if (signal_data.changed) {
414  signal_data.changed = !signal_data.clb();
415  }
416  break;
417  case TriggerType::TRIGGER_TOGGLE:
418  if (signal_data.clb()) {
419  signal_data.objective = !signal_data.input_ref;
420  }
421  break;
422  case TriggerType::TRIGGER_ALWAYS:
423  signal_data.clb();
424  break;
425  default:
426  log_assert(0, "TriggerType has unknown value!");
427  }
428  }
429  if (signal_cmp) {
430  signal_data.actual_time_s += dt_sec;
431  } else {
432  signal_data.changed = true;
433  signal_data.actual_time_s = 0;
434  }
435  }
436  }
437 }
438 
439 template<typename T, typename CompareFunctor>
440 void SignalMonitor<T, CompareFunctor>::set(const SignalId& signal_id) {
441  for (auto& itr : callback_vector_) {
442  if (itr.first == signal_id) {
443  itr.second.input_ref.get() = itr.second.objective;
444  }
445  }
446 }
447 
448 template<typename T, typename CompareFunctor>
449 void SignalMonitor<T, CompareFunctor>::set(const SignalId& signal_id, const T& value) {
450  for (auto& itr : callback_vector_) {
451  if (itr.first == signal_id) {
452  itr.second.input_ref.get() = value;
453  }
454  }
455 }
456 
457 template<typename T, typename CompareFunctor>
458 void SignalMonitor<T, CompareFunctor>::setObjective(const SignalId& signal_id, const T& value) {
459  for (auto& itr : callback_vector_) {
460  if (itr.first == signal_id) {
461  itr.second.objective = value;
462  }
463  }
464 }
465 
466 template<typename T, typename CompareFunctor>
467 void SignalMonitor<T, CompareFunctor>::reset(const SignalId& signal_id) {
468  for (auto& itr : callback_vector_) {
469  if (itr.first == signal_id) {
470  itr.second.changed = true;
471  itr.second.actual_time_s = 0;
472  if (itr.second.input_ref_is_local) {
473  itr.second.input_ref.get() = !itr.second.objective;
474  }
475  }
476  }
477 }
478 
479 template<typename T, typename CompareFunctor>
480 void SignalMonitor<T, CompareFunctor>::enable(const SignalId& signal_id) {
481  for (auto& itr : callback_vector_) {
482  if (itr.first == signal_id) {
483  itr.second.enabled = true;
484  }
485  }
486 }
487 
488 template<typename T, typename CompareFunctor>
489 void SignalMonitor<T, CompareFunctor>::disable(const SignalId& signal_id) {
490  for (auto& itr : callback_vector_) {
491  if (itr.first == signal_id) {
492  itr.second.enabled = false;
493  }
494  }
495 }
496 
497 template<typename T, typename CompareFunctor>
498 void SignalMonitor<T, CompareFunctor>::set(const SignalIdGroup& signal_id_group) {
499  auto action = [](auto& signal) {
500  signal.input_ref.get() = signal.objective;
501  };
502  seekAndDestroy(signal_id_group, action);
503 }
504 
505 template<typename T, typename CompareFunctor>
506 void SignalMonitor<T, CompareFunctor>::reset(const SignalIdGroup& signal_id_group) {
507  auto action = [](auto& signal) {
508  signal.changed = true;
509  signal.actual_time_s = 0;
510  if (signal.input_ref_is_local) {
511  signal.input_ref.get() = !signal.objective;
512  }
513  };
514  seekAndDestroy(signal_id_group, action);
515 }
516 
517 template<typename T, typename CompareFunctor>
518 void SignalMonitor<T, CompareFunctor>::enable(const SignalIdGroup& signal_id_group) {
519  auto action = [](auto& signal) {
520  signal.enabled = true;
521  };
522  seekAndDestroy(signal_id_group, action);
523 }
524 
525 template<typename T, typename CompareFunctor>
526 void SignalMonitor<T, CompareFunctor>::disable(const SignalIdGroup& signal_id_group) {
527  auto action = [](auto& signal) -> void {
528  signal.enabled = false;
529  };
530  seekAndDestroy(signal_id_group, action);
531 }
532 
533 template<typename T, typename CompareFunctor>
534 void SignalMonitor<T, CompareFunctor>::reset(void) {
535  for (auto& itr : callback_vector_) {
536  itr.second.changed = true;
537  itr.second.actual_time_s = 0;
538  if (itr.second.input_ref_is_local) {
539  itr.second.input_ref.get() = !itr.second.objective;
540  }
541  }
542 }
543 
544 template<typename T, typename CompareFunctor>
545 void SignalMonitor<T, CompareFunctor>::enable(void) {
546  for (auto& itr : callback_vector_) {
547  itr.second.enabled = true;
548  }
549 }
550 
551 template<typename T, typename CompareFunctor>
552 void SignalMonitor<T, CompareFunctor>::disable(void) {
553  for (auto& itr : callback_vector_) {
554  itr.second.enabled = false;
555  }
556 }
557 
558 } // namespace signal_monitor
559 
560 } // namespace mcx
561 
562 #endif /* SG_MONITOR_H */
563 
mcx::signal_monitor::SignalMonitor
Definition: sg_monitor.h:34
mcx::signal_monitor::SignalMonitorBase
Definition: sg_monitorbase.h:31
mcx::signal_monitor::bool_stub
Definition: sg_monitor.h:24
mcx::signal_monitor::SignalId
Definition: sg_signalid.h:25
mcx::signal_monitor::SignalIdGroup
Definition: sg_signalidgroup.h:20