FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
vita49_types.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 <cmath>
10#include <limits>
11#include <stdexcept>
12
13namespace serial::vita49
14{
16 {
17 const auto value = static_cast<std::uint8_t>(_next & 0x0Fu);
18 _next = static_cast<std::uint8_t>((_next + 1u) & 0x0Fu);
19 return value;
20 }
21
22 void PacketCountSequencer::setNext(const std::uint8_t packet_count) noexcept
23 {
24 _next = static_cast<std::uint8_t>(packet_count & 0x0Fu);
25 }
26
27 std::uint8_t PacketCountSequencer::peek() const noexcept { return static_cast<std::uint8_t>(_next & 0x0Fu); }
28
29 std::uint32_t makeHeader(const PacketType type, const bool class_id_present, const bool trailer_present,
31 const std::uint8_t packet_count, const std::uint16_t packet_size_words) noexcept
32 {
33 std::uint32_t header = static_cast<std::uint32_t>(type) << 28u;
35 {
36 header |= 1u << 27u;
37 }
39 {
40 header |= 1u << 26u;
41 }
42
43 header |= 1u << 25u; // VITA 49.2 format bit.
44 header |= static_cast<std::uint32_t>(tsi) << 22u;
45 header |= static_cast<std::uint32_t>(tsf) << 20u;
46 header |= static_cast<std::uint32_t>(packet_count & 0x0Fu) << 16u;
48 return header;
49 }
50
51 Timestamp timestampFromEpoch(const std::uint64_t epoch_unix_nanoseconds, const RealType sample_time_seconds)
52 {
53 if (!std::isfinite(sample_time_seconds))
54 {
55 throw std::invalid_argument("VITA timestamp sample time must be finite");
56 }
57
58 const auto epoch_seconds = static_cast<std::uint64_t>(epoch_unix_nanoseconds / 1'000'000'000ull);
59 const auto epoch_nanoseconds = static_cast<std::uint64_t>(epoch_unix_nanoseconds % 1'000'000'000ull);
60
61 const auto offset_seconds = static_cast<long double>(sample_time_seconds);
62 const long double offset_floor = std::floor(offset_seconds);
63 const auto whole_offset_seconds = static_cast<std::int64_t>(offset_floor);
64 long double fractional_seconds =
65 (static_cast<long double>(epoch_nanoseconds) / 1.0e9L) + (offset_seconds - offset_floor);
66
67 std::int64_t carry_seconds = 0;
68 while (fractional_seconds >= 1.0L)
69 {
70 fractional_seconds -= 1.0L;
72 }
73 while (fractional_seconds < 0.0L)
74 {
75 fractional_seconds += 1.0L;
77 }
78
79 const auto signed_seconds = static_cast<std::int64_t>(epoch_seconds) + whole_offset_seconds + carry_seconds;
80 if (signed_seconds < 0 || signed_seconds > static_cast<std::int64_t>(std::numeric_limits<std::uint32_t>::max()))
81 {
82 throw std::out_of_range("VITA UTC integer timestamp is outside 32-bit range");
83 }
84
85 auto fractional_picoseconds =
86 static_cast<std::uint64_t>(std::llround(fractional_seconds * 1'000'000'000'000.0L));
87 auto integer_seconds = static_cast<std::uint32_t>(signed_seconds);
88 if (fractional_picoseconds >= 1'000'000'000'000ull)
89 {
90 fractional_picoseconds -= 1'000'000'000'000ull;
91 if (integer_seconds == std::numeric_limits<std::uint32_t>::max())
92 {
93 throw std::out_of_range("VITA UTC integer timestamp overflow");
94 }
95 ++integer_seconds;
96 }
97
98 return Timestamp{.integer_seconds = integer_seconds, .fractional_picoseconds = fractional_picoseconds};
99 }
100
101 std::uint32_t makeTrailer(const bool valid_data, const bool calibrated_time, const bool reference_lock,
102 const bool over_range, const bool sample_loss) noexcept
103 {
106 if (valid_data)
107 {
108 trailer |= TrailerValidData;
109 }
110 if (calibrated_time)
111 {
112 trailer |= TrailerCalibratedTime;
113 }
114 if (reference_lock)
115 {
116 trailer |= TrailerReferenceLock;
117 }
118 if (over_range)
119 {
120 trailer |= TrailerOverRange;
121 }
122 if (sample_loss)
123 {
124 trailer |= TrailerSampleLoss;
125 }
126 return trailer;
127 }
128
129 std::uint32_t makeContextStateIndicators(const bool valid_data, const bool calibrated_time,
130 const bool reference_lock, const bool over_range,
131 const bool sample_loss) noexcept
132 {
133 return makeTrailer(valid_data, calibrated_time, reference_lock, over_range, sample_loss);
134 }
135
137 {
138 // Internal FERS profile payload-format word:
139 // [63:60] complex Cartesian, [59:56] two's-complement integer,
140 // [55:48] item bits, [47:40] packing bits, [39:32] vector size,
141 // [31:16] repeat count, [15:0] reserved/version.
142 constexpr std::uint64_t complex_cartesian = 0x2ull;
143 constexpr std::uint64_t twos_complement = 0x1ull;
144 constexpr std::uint64_t item_bits = 16ull;
145 constexpr std::uint64_t packing_bits = 16ull;
146 constexpr std::uint64_t vector_size = 2ull;
147 constexpr std::uint64_t repeat_count = 1ull;
148 constexpr std::uint64_t version = 1ull;
149 return (complex_cartesian << 60u) | (twos_complement << 56u) | (item_bits << 48u) | (packing_bits << 40u) |
150 (vector_size << 32u) | (repeat_count << 16u) | version;
151 }
152
154 {
155 if (max_udp_payload_bytes < kSignalDataFixedBytes + sizeof(std::int16_t) * 2u)
156 {
157 throw std::invalid_argument("VITA max UDP payload cannot fit one complex int16 sample");
158 }
159 return (max_udp_payload_bytes - kSignalDataFixedBytes) / (sizeof(std::int16_t) * 2u);
160 }
161}
void setNext(std::uint8_t packet_count) noexcept
std::uint8_t peek() const noexcept
double RealType
Type for real numbers.
Definition config.h:27
std::size_t maxComplexSamplesPerSignalPacket(const std::uint16_t max_udp_payload_bytes)
constexpr std::uint32_t kSignalDataFixedBytes
Timestamp timestampFromEpoch(const std::uint64_t epoch_unix_nanoseconds, const RealType sample_time_seconds)
std::uint32_t makeTrailer(const bool valid_data, const bool calibrated_time, const bool reference_lock, const bool over_range, const bool sample_loss) noexcept
@ TrailerEnableCalibratedTime
std::uint32_t makeContextStateIndicators(const bool valid_data, const bool calibrated_time, const bool reference_lock, const bool over_range, const bool sample_loss) noexcept
std::uint32_t makeHeader(const PacketType type, const bool class_id_present, const bool trailer_present, const IntegerTimestampMode tsi, const FractionalTimestampMode tsf, const std::uint8_t packet_count, const std::uint16_t packet_size_words) noexcept
std::uint64_t makeComplexInt16PayloadFormat() noexcept
math::Vec3 max
std::uint32_t integer_seconds