Skip to content

File utilities.h

File List > utilities.h

Go to the documentation of this file

#pragma once

#include <array> // std::array
#include <chrono>
#include <functional>
#include <string>
#include <string_view>
#include <utility> // std::index_sequence

#include "fpm_adapter.hpp"

// Clocks and clock management

template <typename Rep, typename Period>
class DynamicTimeInterval;

using DefaultClock = std::chrono::high_resolution_clock;
using TimePoint = DefaultClock::time_point;
using Duration = DefaultClock::duration;

using TimeInterval = DynamicTimeInterval<uint64_t, std::ratio<1>>;

template <typename T>
concept ChronoDuration = requires(T obj) {
    requires std::same_as<DynamicTimeInterval<typename T::rep, typename T::period>, T>;
};

template <typename T>
concept ChronoPoint = std::is_base_of_v<std::chrono::time_point<typename T::Clock, typename T::Duration>, T>;

template <class C>
    requires requires(C obj) {
        { obj() } -> std::convertible_to<TimePoint>;
    }
class Clock_t {
private:
    inline static C s_clock = DefaultClock::now;

public:
    static void setClock(C clock) { s_clock = clock; }

    static C getClock() { return s_clock; }

    static TimePoint now() { return s_clock(); }
};

using Clock = Clock_t<std::function<TimePoint(void)>>;

template <typename Rep, typename Period = std::ratio<1>>
class DynamicTimeInterval {
public:
    using DurationType = std::chrono::duration<Rep, Period>;
    using rep = DurationType::rep;
    using period = DurationType::period;

    template <typename ORep, typename OPeriod>
    friend class DynamicTimeInterval;

    DynamicTimeInterval(const DynamicTimeInterval& other) = default;

    constexpr DynamicTimeInterval(DurationType d): m_duration(d) {}

    constexpr DynamicTimeInterval(Rep count): m_duration(count) {}

    template <typename Orep, typename Operiod>
    constexpr DynamicTimeInterval(std::chrono::duration<Orep, Operiod> d):
        m_duration(std::chrono::duration_cast<DurationType>(d)) {}

    constexpr DurationType get_duration() const { return m_duration; }

    constexpr Rep count() const { return m_duration.count(); }

    constexpr uint64_t microseconds() const {
        return std::chrono::duration_cast<std::chrono::duration<uint64_t, std::micro>>(m_duration).count();
    }

    template <typename TargetRep, typename TargetPeriod>
    constexpr DynamicTimeInterval<TargetRep, TargetPeriod> as() const {
        return DynamicTimeInterval<TargetRep, TargetPeriod>(
            std::chrono::duration_cast<std::chrono::duration<TargetRep, TargetPeriod>>(m_duration)
        );
    }

    template <typename T, typename P>
    constexpr DynamicTimeInterval operator+(const DynamicTimeInterval<T, P>& other) {
        return DynamicTimeInterval(
            m_duration + std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(other.m_duration)
        );
    }

    template <typename T, typename P>
    constexpr bool operator>(const DynamicTimeInterval<T, P>& other) {
        return m_duration > other.m_duration;
    }

private:
    const DurationType m_duration;
};

template <typename T, typename P>
constexpr DynamicTimeInterval<uint64_t, std::milli>
milliseconds(const uint64_t millis, const DynamicTimeInterval<T, P> offset) {
    return DynamicTimeInterval<uint64_t, std::milli>(millis) +
        DynamicTimeInterval<uint64_t, std::milli>(offset.get_duration());
}

constexpr DynamicTimeInterval<uint64_t, std::milli> milliseconds(const uint64_t millis) {
    return std::chrono::duration<uint64_t, std::milli>(millis);
}

constexpr DynamicTimeInterval<uint64_t, std::micro> microseconds(const uint64_t micros) {
    return std::chrono::duration<uint64_t, std::micro>(micros);
}

template <typename T, typename P>
constexpr DynamicTimeInterval<uint64_t> seconds(uint64_t seconds, DynamicTimeInterval<T, P> offset) {
    return DynamicTimeInterval<uint64_t>(seconds) + DynamicTimeInterval<uint64_t>(offset.get_duration());
}

constexpr DynamicTimeInterval<uint64_t> seconds(uint64_t seconds) {
    return std::chrono::duration<uint64_t, std::ratio<1>>(seconds);
}

template <typename T>
inline T unitSinceEpoch() {
    auto now = std::chrono::time_point_cast<T>(Clock::now());
    auto duration_since_epoch = now.time_since_epoch();
    return std::chrono::duration_cast<T>(duration_since_epoch);
}

inline uint64_t milliSinceEpoch() {
    auto duration = unitSinceEpoch<std::chrono::milliseconds>();
    return static_cast<uint64_t>(duration.count());
}

inline uint64_t microSinceEpoch() {
    auto duration = unitSinceEpoch<std::chrono::microseconds>();
    return static_cast<uint64_t>(duration.count());
}

inline uint64_t nanoSinceEpoch() {
    auto duration = unitSinceEpoch<std::chrono::nanoseconds>();
    return static_cast<uint64_t>(duration.count());
}

// System-wide constants
const int                    motorInterfaceType = 1;                     
const int                    maxSpeed = 1000;                            
const int                    acceleration = 3000;                        
constexpr static fixed_16_16 rad2DegFactor = fixed_16_16(57.2957795131); 
constexpr static fixed_16_16 deg2RadFactor = fixed_16_16(0.01745329251); 
const fixed_16_16            Gz = -9.80665;                              
const int                    altitude = 1320;                            
const fixed_16_16            projectileSpeed = 20;                       

const auto fireActionInterval = seconds(3);

template <typename T>
consteval std::string_view type_name() {
    using namespace std::literals; // required for ""sv
// Format is usually: "constexpr std::string_view type_name() [with T = Name]"
// We need to slice it. This logic is compiler specific.
#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
    #if defined(__clang__) || defined(__GNUC__)

    std::string_view name = __PRETTY_FUNCTION__;
    std::string_view prefix = "T = ";
    std::string_view suffix = "; ";

    #elif defined(_MSC_VER)

    std::string_view prefix = "type_name<";
    std::string_view suffix = ", ";
    std::string_view name = __FUNCSIG__;

    #endif

    auto start = name.find(prefix);
    auto end = name.find(suffix, start);
    if (end == std::string_view::npos) {
        end = name.rfind(">(void)"sv, start);
    }
    if (start != std::string_view::npos && end != std::string_view::npos) {
        start += prefix.size();
        return name.substr(start, end - start);
    }
    return name;

#else
    return "UnknownType";
#endif
}