Tactility/Modules/mesh-module/source/mesh_airtime.cpp
Ken Van Hoeylandt 56ddd4b355
Mesh Chat apps, ESP-NOW mesh radio, and shared Wi-Fi radio ownership (#698)
Mesh gets contacts, channels, delivery receipts, QR sharing and an ESP-NOW radio. Mesh Chat is split into Mesh Contacts and Mesh Channels, `mesh inspect` replaces the Mesh Inspect app, and ESP-NOW and Wi-Fi now share the Wi-Fi radio safely.
2026-10-17 18:56:27 +02:00

45 lines
2.0 KiB
C++

// SPDX-License-Identifier: Apache-2.0
#include <mesh/mesh_airtime.h>
#include <algorithm>
#include <cmath>
uint32_t mesh_airtime_estimate_ms(const MeshRadioProfile& profile, size_t length) {
if (profile.modulation == RADIO_MODULATION_LORA && profile.bandwidth > 0) {
// Semtech AN1200.13, explicit header with CRC
const double symbolMs = std::pow(2.0, profile.spreading_factor) * 1000.0 / profile.bandwidth;
const int lowDataRateOptimize = (symbolMs > 16.0) ? 1 : 0;
const int codingRate = std::clamp<int>(profile.coding_rate - 4, 1, 4);
const double numerator = 8.0 * (double)length - 4.0 * profile.spreading_factor + 28.0 + 16.0;
const double denominator = 4.0 * (profile.spreading_factor - 2 * lowDataRateOptimize);
const double payloadSymbols = 8.0 + std::max(std::ceil(numerator / denominator) * (codingRate + 4), 0.0);
const double preambleMs = (profile.preamble_length + 4.25) * symbolMs;
return (uint32_t)std::ceil(preambleMs + payloadSymbols * symbolMs);
}
if (profile.modulation == RADIO_MODULATION_ESPNOW) {
// Wi-Fi long range runs at 0.5 Mbit/s, and a frame has about 100 bytes of headers
constexpr double BIT_RATE = 500000.0;
return (uint32_t)std::ceil((100.0 + length) * 8.0 * 1000.0 / BIT_RATE);
}
// FSK-family: preamble, sync word, length byte, payload and CRC. The data rate is not part of the
// profile, so a conservative 4.8 kbit/s is assumed.
constexpr double FALLBACK_BIT_RATE = 4800.0;
const double bits = profile.preamble_length + (4 + 1 + length + 2) * 8.0;
return (uint32_t)std::ceil(bits * 1000.0 / FALLBACK_BIT_RATE);
}
uint32_t mesh_airtime_duty_cycle_percent(RadioRegion region, int32_t frequency) {
switch (region) {
case RADIO_REGION_EU_868:
return (frequency >= 869400000 && frequency <= 869650000) ? 10 : 1;
case RADIO_REGION_EU_433:
return 10;
case RADIO_REGION_RU_868:
return 1;
default:
return 100;
}
}