ocpp 0.24.1
A C++ implementation of the Open Charge Point Protocol
aligned_timer.hpp
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
3
4#pragma once
5
6#include <everest/logging.hpp>
7#include <everest/timer.hpp>
8#include <ocpp/common/types.hpp>
9
10namespace ocpp {
11
12class ClockAlignedTimer : private Everest::Timer<std::chrono::system_clock> {
13public:
14 using system_time_point = std::chrono::time_point<std::chrono::system_clock>;
15
16private:
17 system_time_point start_point;
18 std::chrono::seconds call_interval;
19
20 std::function<void()> callback;
21
22 system_time_point get_next_timepoint() {
23 using namespace std::chrono_literals;
24
25 auto now = std::chrono::system_clock::now();
26 auto diff = now - this->start_point;
27 auto time_to_next = 0s;
28 // Only calculate next time if it is positive. Otherwise we would end up before the start point
29 if (diff > 0s) {
30 time_to_next = ((std::chrono::duration_cast<std::chrono::seconds>(diff) / this->call_interval) + 1) *
31 this->call_interval;
32 ;
33 }
34 auto next_time = this->start_point + time_to_next;
35 EVLOG_debug << "Clock aligned interval every " << this->call_interval.count() << " seconds, starting at "
36 << ocpp::DateTime(date::utc_clock::from_sys(this->start_point))
37 << ". Next one at: " << ocpp::DateTime(date::utc_clock::from_sys(next_time));
38 EVLOG_debug << "This amounts to "
39 << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(24)) / this->call_interval
40 << " samples per day";
41 return next_time;
42 }
43
44 system_time_point call_next() {
45 if (this->callback == nullptr) {
46 return system_time_point{};
47 }
48
49 auto wrapper = [this]() {
50 this->callback();
51 this->at(this->get_next_timepoint());
52 };
53
54 auto next_timepoint = this->get_next_timepoint();
55 this->at(wrapper, next_timepoint);
56 return next_timepoint;
57 }
58
59public:
60 ClockAlignedTimer() = default;
61
62 explicit ClockAlignedTimer(boost::asio::io_context* io_context) : Timer(io_context) {
63 }
64
65 explicit ClockAlignedTimer(boost::asio::io_context* io_context, const std::function<void()>& callback) :
66 Timer(io_context), callback(callback) {
67 }
68
69 template <class Rep, class Period>
70 system_time_point interval_starting_from(const std::function<void()>& callback,
71 const std::chrono::duration<Rep, Period> interval,
72 system_time_point start_point) {
73 this->callback = callback;
74 return this->interval_starting_from(interval, start_point);
75 }
76
77 template <class Rep, class Period>
78 system_time_point interval_starting_from(const std::chrono::duration<Rep, Period> interval,
79 system_time_point start_point) {
80 this->start_point = start_point;
81 this->call_interval = interval;
82
83 return this->call_next();
84 }
85
86 template <class Rep, class Period>
87 system_time_point set_interval(const std::chrono::duration<Rep, Period>& interval) {
88 this->call_interval = interval;
89 return this->call_next();
90 }
91
92 using Everest::Timer<std::chrono::system_clock>::stop;
93};
94
95} // namespace ocpp
Definition: aligned_timer.hpp:12
Contains a DateTime implementation that can parse and create RFC 3339 compatible strings.
Definition: types.hpp:109