idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
duty_cycle.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
19#include <idfxx/radio/types.hpp>
20
21#include <chrono>
22#include <cstdint>
23#include <optional>
24#include <utility>
25
26namespace idfxx::radio {
27
32inline constexpr std::chrono::microseconds default_min_rx_sleep{1016};
33
80[[nodiscard]] constexpr std::optional<rx_duty_cycle> rx_duty_cycle_for(
81 const lora_modulation& mod,
82 uint16_t sender_preamble,
83 uint16_t min_symbols = 8,
84 std::chrono::microseconds min_sleep = default_min_rx_sleep
85) noexcept {
86 if (min_symbols == 0 || 2 * static_cast<uint32_t>(min_symbols) >= sender_preamble) {
87 return std::nullopt;
88 }
89
90 // Symbol duration Tsym = 2^SF / BW. Durations are computed as
91 // n·2^SF·1e6 / BW in integer arithmetic, rounding the sleep window down
92 // (wake early) and the listen window up (listen longer).
93 const int64_t bw = airtime_detail::bandwidth_hz(mod.bw);
94 const int64_t sym_x_1e6 = (int64_t{1} << std::to_underlying(mod.sf)) * 1'000'000;
95 const auto symbols_floor = [&](int64_t n) { return n * sym_x_1e6 / bw; };
96 const auto symbols_ceil = [&](int64_t n) { return (n * sym_x_1e6 + bw - 1) / bw; };
97
98 const int64_t sleep_us = symbols_floor(sender_preamble - 2 * min_symbols);
99 if (sleep_us < min_sleep.count()) {
100 return std::nullopt;
101 }
102
103 constexpr int64_t margin_us = 1'000;
104 const int64_t worst_case_us = (symbols_ceil(sender_preamble + 1) - (sleep_us - margin_us) + 1) / 2;
105 const int64_t detect_us = symbols_ceil(min_symbols + 1);
106 const int64_t rx_us = worst_case_us > detect_us ? worst_case_us : detect_us;
107
108 return rx_duty_cycle{std::chrono::microseconds{rx_us}, std::chrono::microseconds{sleep_us}};
109}
110
111} // namespace idfxx::radio
LoRa time-on-air (air-time) calculation.
Chip-agnostic LoRa modulation and packet types.
LoRa radio types and driver classes.
Definition airtime.hpp:26
constexpr std::chrono::microseconds default_min_rx_sleep
Default shortest sleep window worth duty-cycling for.
constexpr std::optional< rx_duty_cycle > rx_duty_cycle_for(const lora_modulation &mod, uint16_t sender_preamble, uint16_t min_symbols=8, std::chrono::microseconds min_sleep=default_min_rx_sleep) noexcept
Computes duty-cycle receive windows that cannot miss a packet.
LoRa modulation parameters.
Definition types.hpp:132
Listen/sleep windows for duty-cycled receive.
Definition types.hpp:194