Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
244
tools/EVerest-main/lib/everest/timer/include/everest/timer.hpp
Normal file
244
tools/EVerest-main/lib/everest/timer/include/everest/timer.hpp
Normal file
@@ -0,0 +1,244 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef EVEREST_TIMER_HPP
|
||||
#define EVEREST_TIMER_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
|
||||
namespace Everest {
|
||||
template <typename TimerClock = date::utc_clock> class Timer {
|
||||
private:
|
||||
std::unique_ptr<boost::asio::basic_waitable_timer<TimerClock>> timer = nullptr;
|
||||
std::function<void()> timer_callback;
|
||||
std::function<void(const boost::system::error_code& error)> callback_wrapper;
|
||||
std::chrono::nanoseconds interval_nanoseconds = std::chrono::nanoseconds(0);
|
||||
std::atomic<bool> running = false;
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
|
||||
std::unique_ptr<std::thread> timer_thread = nullptr;
|
||||
|
||||
std::mutex mutex;
|
||||
|
||||
public:
|
||||
/// This timer will initialize a boost::asio::io_context
|
||||
Timer() :
|
||||
work(boost::asio::make_work_guard(this->io_context)),
|
||||
timer_thread(std::make_unique<std::thread>([this]() { this->io_context.run(); })) {
|
||||
this->timer = std::make_unique<boost::asio::basic_waitable_timer<TimerClock>>(this->io_context);
|
||||
}
|
||||
|
||||
explicit Timer(const std::function<void()>& callback) :
|
||||
timer_callback(callback),
|
||||
work(boost::asio::make_work_guard(this->io_context)),
|
||||
timer_thread(std::make_unique<std::thread>([this]() { this->io_context.run(); })) {
|
||||
this->timer = std::make_unique<boost::asio::basic_waitable_timer<TimerClock>>(this->io_context);
|
||||
}
|
||||
|
||||
explicit Timer(boost::asio::io_context* io_context) :
|
||||
timer(std::make_unique<boost::asio::basic_waitable_timer<TimerClock>>(*io_context)),
|
||||
work(boost::asio::make_work_guard(*io_context)) {
|
||||
}
|
||||
|
||||
Timer(boost::asio::io_context* io_context, const std::function<void()>& callback) :
|
||||
timer(std::make_unique<boost::asio::basic_waitable_timer<TimerClock>>(*io_context)),
|
||||
timer_callback(callback),
|
||||
work(boost::asio::make_work_guard(*io_context)) {
|
||||
}
|
||||
|
||||
/// \brief Cancel the asio timer and join the io_context thread.
|
||||
///
|
||||
/// The mutex is released BEFORE joining the io_context thread. A timer callback running on
|
||||
/// that thread may re-enter \ref at, \ref timeout, \ref interval, or \ref stop — each of which
|
||||
/// takes the mutex; if the destructor still held it, \c join would deadlock waiting for the
|
||||
/// callback to exit while the callback waited for the mutex.
|
||||
~Timer() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
if (this->timer) {
|
||||
this->timer->cancel();
|
||||
}
|
||||
}
|
||||
if (this->timer_thread) {
|
||||
this->io_context.stop();
|
||||
this->timer_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes the given callback at the given timepoint
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
void at(const std::function<void()>& callback, const std::chrono::time_point<Clock, Duration>& time_point) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->timer_callback = callback;
|
||||
|
||||
this->at_internal(time_point);
|
||||
}
|
||||
|
||||
/// Executes a previously configured callback at the given timepoint
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
void at(const std::chrono::time_point<Clock, Duration>& time_point) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->at_internal<Clock, Duration>(time_point);
|
||||
}
|
||||
|
||||
/// Executes the given callback periodically from now in the given interval
|
||||
template <class Rep, class Period>
|
||||
void interval(const std::function<void()>& callback, const std::chrono::duration<Rep, Period>& interval) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->timer_callback = callback;
|
||||
|
||||
this->interval_internal(interval);
|
||||
}
|
||||
|
||||
/// Executes a previously configured callback periodically from now in the given interval
|
||||
template <class Rep, class Period> void interval(const std::chrono::duration<Rep, Period>& interval) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->interval_internal(interval);
|
||||
}
|
||||
|
||||
/// Executes the given callback once after the given interval
|
||||
template <class Rep, class Period>
|
||||
void timeout(const std::function<void()>& callback, const std::chrono::duration<Rep, Period>& interval) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->timer_callback = callback;
|
||||
|
||||
this->timeout_internal(interval);
|
||||
}
|
||||
|
||||
/// Executes a previously configured callback once after the given interval
|
||||
template <class Rep, class Period> void timeout(const std::chrono::duration<Rep, Period>& interval) {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
this->stop_internal();
|
||||
this->timeout_internal(interval);
|
||||
}
|
||||
|
||||
/// Stops timer from executing its callback
|
||||
void stop() {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
stop_internal();
|
||||
}
|
||||
|
||||
/// Indicates if the timer is running
|
||||
bool is_running() {
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
void at_internal(const std::chrono::time_point<Clock, Duration>& time_point) {
|
||||
if (this->timer_callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timer) {
|
||||
running = true;
|
||||
|
||||
// use asio timer
|
||||
this->timer->expires_at(time_point);
|
||||
this->timer->async_wait([this](const boost::system::error_code& e) {
|
||||
if (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->timer_callback();
|
||||
running = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <class Rep, class Period> void interval_internal(const std::chrono::duration<Rep, Period>& interval) {
|
||||
this->interval_nanoseconds = interval;
|
||||
if (interval_nanoseconds == std::chrono::nanoseconds(0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timer_callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timer) {
|
||||
running = true;
|
||||
|
||||
// use asio timer
|
||||
this->callback_wrapper = [this](const boost::system::error_code& error) {
|
||||
if (error) {
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex);
|
||||
this->timer->expires_after(
|
||||
std::chrono::duration_cast<typename TimerClock::duration>(this->interval_nanoseconds));
|
||||
this->timer->async_wait(this->callback_wrapper);
|
||||
}
|
||||
|
||||
this->timer_callback();
|
||||
};
|
||||
|
||||
this->timer->expires_after(
|
||||
std::chrono::duration_cast<typename TimerClock::duration>(this->interval_nanoseconds));
|
||||
this->timer->async_wait(this->callback_wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Rep, class Period> void timeout_internal(const std::chrono::duration<Rep, Period>& interval) {
|
||||
if (this->timer_callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timer) {
|
||||
running = true;
|
||||
|
||||
// use asio timer
|
||||
this->timer->expires_after(interval);
|
||||
this->timer->async_wait([this](const boost::system::error_code& error) {
|
||||
if (error) {
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this->timer_callback();
|
||||
running = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void stop_internal() {
|
||||
if (this->timer) {
|
||||
// asio based timer
|
||||
this->timer->cancel();
|
||||
}
|
||||
|
||||
running = false;
|
||||
}
|
||||
};
|
||||
|
||||
using SteadyTimer = Timer<date::utc_clock>;
|
||||
using SystemTimer = Timer<date::utc_clock>;
|
||||
} // namespace Everest
|
||||
|
||||
#endif // EVEREST_TIMER_HPP
|
||||
Reference in New Issue
Block a user