FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
vita49_packetizer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
8
9#include <algorithm>
10#include <cmath>
11#include <stdexcept>
12
14
15namespace serial::vita49
16{
17 Vita49Packetizer::Vita49Packetizer(const std::uint64_t epoch_unix_nanoseconds, const RealType adc_fullscale,
18 const std::uint16_t max_udp_payload_bytes) :
19 _epoch_unix_nanoseconds(epoch_unix_nanoseconds), _adc_fullscale(adc_fullscale),
20 _max_udp_payload_bytes(max_udp_payload_bytes),
21 _max_complex_samples_per_packet(maxComplexSamplesPerSignalPacket(max_udp_payload_bytes))
22 {
23 if (!std::isfinite(adc_fullscale) || adc_fullscale <= 0.0)
24 {
25 throw std::invalid_argument("VITA ADC full-scale must be positive");
26 }
27 }
28
29 std::uint64_t Vita49Packetizer::epochUnixNanoseconds() const noexcept { return _epoch_unix_nanoseconds; }
30
32
33 std::uint16_t Vita49Packetizer::maxUdpPayloadBytes() const noexcept { return _max_udp_payload_bytes; }
34
36 {
37 return _max_complex_samples_per_packet;
38 }
39
41 PacketCountSequencer& packet_counts,
42 const bool sample_loss_pending) const
43 {
45 if (block.samples.empty())
46 {
47 return result;
48 }
49
50 const RealType sample_rate = block.sample_rate > 0.0 ? block.sample_rate : block.stream.sample_rate;
51 if (!std::isfinite(sample_rate) || sample_rate <= 0.0)
52 {
53 throw std::invalid_argument("VITA sample block must have positive sample rate");
54 }
55
56 std::size_t offset = 0;
57 bool loss_flag_for_next_packet = sample_loss_pending;
58 result.packets.reserve((block.samples.size() + _max_complex_samples_per_packet - 1u) /
59 _max_complex_samples_per_packet);
60 while (offset < block.samples.size())
61 {
62 const auto count = std::min(_max_complex_samples_per_packet, block.samples.size() - offset);
64 block.first_sample_time + static_cast<RealType>(offset) / sample_rate;
65 const auto timestamp = timestampFromEpoch(_epoch_unix_nanoseconds, packet_first_sample_time);
66
69 .class_id = kFersVrtIqClassId,
70 .timestamp = timestamp,
71 .packet_count = packet_counts.next(),
72 .valid_data = block.valid_data,
73 .calibrated_time = block.calibrated_time,
74 .reference_lock = block.reference_lock,
75 .sample_loss = loss_flag_for_next_packet,
76 .samples = block.samples.subspan(offset, count),
77 .fullscale = _adc_fullscale});
78 const bool packet_over_range = serialized.clipped_sample_count > 0;
79 result.over_range_count += serialized.clipped_sample_count;
80
81 auto& bytes = serialized.bytes;
82 if (bytes.size() > _max_udp_payload_bytes)
83 {
84 throw std::logic_error("VITA signal packet exceeded max UDP payload");
85 }
86
87 result.packets.push_back(SerializedPacket{.bytes = std::move(bytes),
88 .stream_id = stream_id,
89 .sample_count = count,
90 .first_sample_time = packet_first_sample_time,
91 .data_packet = true,
92 .context_packet = false,
93 .over_range = packet_over_range,
94 .sample_loss = loss_flag_for_next_packet,
95 .timestamp = timestamp});
96 result.samples_emitted += count;
97 offset += count;
99 }
100
101 return result;
102 }
103
105 {
106 auto bytes = Vita49Serializer::serializeContext(context);
107 if (bytes.size() > _max_udp_payload_bytes)
108 {
109 throw std::logic_error("VITA context packet exceeded max UDP payload");
110 }
111 return SerializedPacket{.bytes = std::move(bytes),
112 .stream_id = context.stream_id,
113 .sample_count = 0,
114 .first_sample_time = 0.0,
115 .data_packet = false,
116 .context_packet = true,
117 .over_range = false,
118 .sample_loss = (context.context_flags & ContextFlagSampleLoss) != 0u,
119 .timestamp = context.timestamp};
120 }
121
122}
PacketizerResult packetize(const core::ReceiverSampleBlock &block, std::uint32_t stream_id, PacketCountSequencer &packet_counts, bool sample_loss_pending) const
Vita49Packetizer(std::uint64_t epoch_unix_nanoseconds, RealType adc_fullscale, std::uint16_t max_udp_payload_bytes=kDefaultMaxUdpPayloadBytes)
SerializedPacket makeContextPacket(const ContextPacket &context) const
RealType adcFullscale() const noexcept
std::uint16_t maxUdpPayloadBytes() const noexcept
std::size_t maxComplexSamplesPerPacket() const noexcept
std::uint64_t epochUnixNanoseconds() const noexcept
static std::vector< std::uint8_t > serializeContext(const ContextPacket &packet)
static SignalDataSerializationResult serializeSignalDataFixedFullscale(const FixedFullscaleSignalDataPacket &packet)
double RealType
Type for real numbers.
Definition config.h:27
std::size_t maxComplexSamplesPerSignalPacket(const std::uint16_t max_udp_payload_bytes)
Timestamp timestampFromEpoch(const std::uint64_t epoch_unix_nanoseconds, const RealType sample_time_seconds)
constexpr std::uint64_t kFersVrtIqClassId
math::Vec3 max
std::vector< std::uint8_t > bytes