Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/dcc/limeric_budget.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

83 lines
2.5 KiB
C++

#include "duty_cycle_permit.hpp"
#include "limeric_budget.hpp"
#include <vanetza/common/runtime.hpp>
#include <chrono>
#include <cmath>
namespace vanetza
{
namespace dcc
{
namespace
{
constexpr Clock::duration min_interval = std::chrono::milliseconds(25);
constexpr Clock::duration max_interval = std::chrono::seconds(1);
} // namespace
LimericBudget::LimericBudget(const DutyCyclePermit& dcp, const Runtime& rt) :
m_duty_cycle_permit(dcp), m_runtime(rt),
m_interval(min_interval), m_tx_start(Clock::time_point::min()),
m_tx_on(Clock::duration::zero())
{
update();
}
Clock::duration LimericBudget::delay()
{
Clock::duration delay = Clock::duration::max();
if (m_runtime.now() >= m_tx_start + m_interval) {
delay = Clock::duration::zero();
} else {
delay = m_tx_start + m_interval - m_runtime.now();
}
return delay;
}
Clock::duration LimericBudget::interval()
{
return m_interval;
}
void LimericBudget::notify(Clock::duration tx_on)
{
m_tx_start = m_runtime.now();
m_tx_on = tx_on;
using std::chrono::duration_cast;
const auto duty_cycle = m_duty_cycle_permit.permitted_duty_cycle();
const auto interval = duration_cast<Clock::duration>(tx_on / duty_cycle.value());
m_interval = clamp_interval(interval);
}
void LimericBudget::update()
{
using std::chrono::duration_cast;
using FloatingPointDuration = std::chrono::duration<double, Clock::period>;
const FloatingPointDuration delay = m_tx_start + m_interval - m_runtime.now();
const double duty_cycle = m_duty_cycle_permit.permitted_duty_cycle().value();
if (duty_cycle > 0.0) {
if (delay.count() > 0.0) {
// Apply equation B.2 of TS 102 687 v1.2.1 if gate is closed at the moment
const FloatingPointDuration interval = (m_tx_on / duty_cycle) * (delay / m_interval);
m_interval = clamp_interval(duration_cast<Clock::duration>(interval) + m_runtime.now() - m_tx_start);
} else {
// use equation B.1 otherwise
const FloatingPointDuration interval = m_tx_on / duty_cycle;
m_interval = clamp_interval(duration_cast<Clock::duration>(interval));
}
} else {
// bail out with maximum interval if duty cycle is not positive
m_interval = max_interval;
}
}
Clock::duration LimericBudget::clamp_interval(Clock::duration interval) const
{
return std::min(std::max(interval, min_interval), max_interval);
}
} // namespace dcc
} // namespace vanetza