GNU Radio's DVBS2RX Package
plsync_cc_impl.h
Go to the documentation of this file.
1/* -*- c++ -*- */
2/*
3 * Copyright (c) 2019-2023 Igor Freire.
4 *
5 * This file is part of gr-dvbs2rx.
6 *
7 * SPDX-License-Identifier: GPL-3.0-or-later
8 */
9
10#ifndef INCLUDED_DVBS2RX_PLSYNC_CC_IMPL_H
11#define INCLUDED_DVBS2RX_PLSYNC_CC_IMPL_H
12
13#include "pl_defs.h"
14#include "pl_descrambler.h"
15#include "pl_frame_sync.h"
16#include "pl_freq_sync.h"
17#include "pl_signaling.h"
19#include <volk/volk_alloc.hh>
20#include <array>
21#include <queue>
22
23namespace gr {
24namespace dvbs2rx {
25
26/* @brief Upstream rotator state confirmed by the incoming tags */
28 double freq = 0; /**< Rotating frequency */
29 uint64_t idx = 0; /**< Absolute sample index where the state started */
30};
31
32/* @brief Rotator phase increment adjustment request */
34 double phase_inc; // desired rotator phase increment
35 uint64_t sof_idx; // target SOF index for the update
36 rot_phase_adj_t(double p, uint64_t i) : phase_inc(p), sof_idx(i) {}
37};
38
39/* @brief Upstream rotator control */
40struct rot_ctrl_t {
41 int tag_delay = 0; /** Delay of rotator's rot_phase_inc tag */
42 uint64_t tag_search_start = 0; /** Starting index for the next tag search */
43 uint64_t last_tag_search_end = 0; /** Ending index from the previous tag search */
44 // NOTE: tag_search_start is used on the processing search (via calibrate_tag_delay),
45 // while last_tag_search_end is used on the tag-copying search (via handle_tags).
46 rot_state_t past; /** Frequency state at the past PLFRAME */
47 rot_state_t current; /** Frequency state at the current PLFRAME */
48 std::queue<tag_t> tag_queue; /** Queue of rot_phase_inc tags */
49 std::map<uint64_t, rot_phase_adj_t>
50 update_map; /** Map of scheduled phase increment updates */
51};
52
53/** @brief Index tracking for various segments of a PLFRAME */
55 uint16_t i_in_payload = 0; /** Symbol index in PLFRAME payload */
56 uint16_t i_pilot_blk = 0; /** Pilot block index */
57 uint16_t i_slot = 0; /** Slot index */
58 void step(uint16_t plframe_len, bool has_pilots);
59 void reset();
60};
61
62// Frame information cache
64 volk::vector<gr_complex> plheader;
67 bool coarse_corrected = false;
68 double coarse_foffset = 0;
69 double fine_foffset = 0;
70 uint64_t abs_sof_idx = 0;
72};
73
74// Payload processing state
75enum class payload_state_t {
76 searching, /**< payload not found yet - waiting lock and two SOFs */
77 pending, /**< found - waiting to be processed */
78 partial /**< partially processed but not fully output yet */
79};
80
82{
83private:
84 /* Parameters */
85 int d_debug_level; /** debug level */
86 const double d_sps; /** samples per symbol */
87 /* NOTE: the PLSYNC block requires a symbol-spaced stream at its
88 * input. Hence, sps does not refer to the input stream. Instead, it
89 * refers to the oversampling ratio that is adopted in the receiver
90 * flowgraph prior to the matched filter. This is so that this block
91 * can control the external rotator phase properly */
92 bool d_acm_vcm; /**< ACM/VCM mode */
93 std::array<uint8_t, n_plsc_codewords> d_pls_enabled; /** PLSs to process */
94 bool d_plsc_decoder_enabled; /**< Whether the PLSC decoder is enabled */
95
96 /* State */
97 bool d_locked; /**< Whether the frame timing is locked */
98 bool d_closed_loop; /**< Whether any freq. correction has been applied to the
99 external rotator. False while still waiting for the first
100 correction (i.e., while effectively in open loop) */
101 payload_state_t d_payload_state; /**< Payload processing state machine */
102 rot_ctrl_t d_rot_ctrl; /**< Upstream rotator control */
103 plframe_idx_t d_idx; /**< PLFRAME index state */
104 gr_complex d_phase_corr; /**< Phase correction */
105 double d_cum_freq_offset; /**< Cumulative frequency offset estimate */
106
107 /* Frame counts */
108 uint64_t d_sof_cnt; /**< Total detected SOFs (including false-positives) */
109 uint64_t d_frame_cnt; /**< Accepted/processed PLFRAMEs */
110 uint64_t d_rejected_cnt; /**< Rejected PLFRAMEs */
111 uint64_t d_dummy_cnt; /**< Dummy PLFRAMEs */
112
113 /* Frame metadata from the current PLFRAME (whose payload may be under processing if
114 * locked) and from the next PLFRAME (the PLHEADER ahead, processed in advance). */
115 plframe_info_t d_curr_frame_info; /**< PLFRAME under processing */
116 plframe_info_t d_next_frame_info; /**< Next PLFRAME */
117
118 // Constant PLS info used in CCM/SIS mode
119 pls_info_t d_ccm_sis_pls;
120
121 const pmt::pmt_t d_port_id = pmt::mp("rotator_phase_inc");
122
123 /* Objects */
124 frame_sync* d_frame_sync; /**< frame synchronizer */
125 freq_sync* d_freq_sync; /**< frequency synchronizer */
126 plsc_decoder* d_plsc_decoder; /**< PLSC decoder */
127 pl_descrambler* d_pl_descrambler; /**< PL descrambler */
128
129 /**
130 * @brief Save the tags in the current work range within the local queue
131 *
132 * The motivation is to avoid missing tags due to pruning. The PL sync block processes
133 * tags only when locked (via the `calibrate_tag_delay` function). Hence, when tags
134 * are placed while the block is unlocked, these tags can be occasionally lost due to
135 * GR runtime's block tag pruning. This function avoids the problem by saving all the
136 * desired tags ("rot_phase_inc" tags) locally on a queue to be processed later by the
137 * calibrate_tag_delay function.
138 *
139 * @param ninput_items (int) Number of samples available on the input buffer.
140 */
141 void handle_tags(int ninput_items);
142
143 /**
144 * @brief Send new frequency correction to the upstream rotator.
145 *
146 * The PL Sync block is designed to be used in conjunction with a rotator
147 * block for frequency correction. The processing chain is expected to be
148 * somewhat similar to the following:
149 *
150 * AGC --> Rotator --> Symbol Sync (MF/Decimator) --> DVB-S2 PL Sync
151 *
152 * That is, the rotator is upstream after an intermediate symbol sync block,
153 * which, in turn, implements symbol timing recovery, matched filtering, and
154 * decimation. As a result, the frequency correction applied by the rotator
155 * promotes better performance both on the symbol timing recovery and on the
156 * DVB-S2 PL synchronization.
157 *
158 * In this architecture, the PL Sync block is responsible for controlling
159 * the rotator frequency through a message mechanism. This function
160 * implements such control.
161 *
162 * More specifically, this function coordinates the moment when the
163 * frequency correction is supposed to change on the upstream rotator. If
164 * the frequency correction was allowed to change at any moment, it could
165 * change in the middle of a frame and degrade the decoding performance
166 * significantly. Hence, this function attempts to schedule every change at
167 * the start of a PLHEADER instead. To do so, it relies on the tag delay
168 * calibrated by function `calibrate_tag_delay()`.
169 *
170 * @param abs_sof_idx (uint64_t) Absolute index where the SOF starts.
171 * @param plframe_len (uint16_t) Corresponding PLFRAME length.
172 * @param rot_freq_adj (double) Frequency adjustment to be applied.
173 * @param ref_is_past_frame (bool) Whether the reference for the frequency
174 * adjustment is the previous frame (when true) or
175 * the frame corresponding to the most recently
176 * handled PLHEADER (when false).
177 *
178 * @note A relative index is relative to the start of the current work
179 * buffer. An absolute index is counted monotonically since the start of the
180 * flowgraph execution. The `abs_sof_idx` parameter is an absolute index.
181 *
182 * @note The current architecture only processes a PLFRAME payload when both
183 * the preceding and succeeding SOFs are detected. Hence, by the time the
184 * n-th PLHEADER is processed, the payload behind it (payload n-1) is yet to
185 * be processed. However, both the header and payload can trigger rotator
186 * frequency adjustments. The header can produce a coarse frequency offset
187 * update, whereas the payload can produce a fine estimate in case it has
188 * pilots. Hence, care should be taken when applying parameter
189 * `rot_freq_adj`.
190 *
191 * Regardless of which handler calls this function (header or payload), the
192 * frequency adjustment is always scheduled for the start of PLHEADER
193 * n+1. However, the adjustment itself can be summed to either the frequency
194 * offset state at frame n-1 or frame n. The coarse estimate produced by the
195 * PLHEADER handler must be added to the frequency state at frame n (at the
196 * most recently processed PLHEADER). Hence, for the PLHEADER,
197 * `ref_is_past_frame` must be false. In contrast, the pilot-mode fine
198 * estimate produced by the payload handler must be added to the frequency
199 * state of frame n-1 (i.e., the PLFRAME preceding the most recent
200 * PLHEADER). In this case, `ref_is_past_frame` must be true.
201 */
202 void control_rotator_freq(uint64_t abs_sof_idx,
203 uint16_t plframe_len,
204 double rot_freq_adj,
205 bool ref_is_past_frame);
206
207 /**
208 * @brief Calibrate the delay between the upstream rotator and this block.
209 *
210 * The rotator places a tag on the sample where the new phase increment
211 * starts to take effect. However, this sample typically traverses a matched
212 * filter and decimator block, which can alter the tag index. Hence, the tag
213 * may not come exactly where expected.
214 *
215 * This function calibrates the tag delay by comparing the index on which
216 * the tag came to where it was expected in the symbol-spaced stream.
217 * Ultimately, the measured tag delay can be used to pre-compensate for it
218 * when scheduling the next phase increment update.
219 *
220 * @param abs_sof_idx Absolute index where the SOF was detected.
221 * @param tolerance Tag delay tolerance. If exceeded, a warning is printed.
222 *
223 * @note This function should be called whenever a SOF is detected.
224 **/
225 void calibrate_tag_delay(uint64_t abs_sof_idx, int tolerance = 300);
226
227 /**
228 * @brief Process a PLHEADER.
229 * @param abs_sof_idx (uint64_t) Absolute index where the PLHEADER starts.
230 * @param p_plheader (const gr_complex*) Pointer to the PLHEADER buffer.
231 * @param frame_info (plframe_info&) Reference to the plframe_info_t object
232 * on which the frame information should be cached once
233 * the PLHEADER is decoded.
234 */
235 void handle_plheader(uint64_t abs_sof_idx,
236 const gr_complex* p_plheader,
237 plframe_info_t& frame_info);
238
239 /**
240 * @brief Process a PLFRAME payload (data and pilot symbols).
241 * @param noutput_items (int) Output buffer capacity.
242 * @param out (gr_complex*) Pointer to the output buffer.
243 * @param p_payload (gr_complex*) Pointer to the payload to be processed.
244 * @param frame_info (plframe_info_t&) Reference to the plframe_info_t
245 * object with the information corresponding to the
246 * payload being processed.
247 * @param next_frame_info (plframe_info_t&) Reference to the plframe_info_t
248 * object with the information corresponding to the
249 * frame ahead of the frame being processed. Used
250 * only to schedule rotator frequency updates.
251 * @return (int) Number of output symbols produced in this call.
252 */
253 int handle_payload(int noutput_items,
254 gr_complex* out,
255 const gr_complex* p_payload,
256 plframe_info_t& frame_info,
257 const plframe_info_t& next_frame_info);
258
259
260public:
261 plsync_cc_impl(int gold_code,
262 int freq_est_period,
263 double sps,
264 int debug_level,
265 bool acm_vcm,
266 bool multistream,
267 uint64_t pls_filter_lo,
268 uint64_t pls_filter_hi);
270
271 // Where all the action really happens
272 void forecast(int noutput_items, gr_vector_int& ninput_items_required);
273
274 int general_work(int noutput_items,
275 gr_vector_int& ninput_items,
276 gr_vector_const_void_star& input_items,
277 gr_vector_void_star& output_items);
278
279 /**
280 * @brief Get the cumulative frequency offset.
281 *
282 * When an external rotator is used to handle the frequency corrections,
283 * eventually the PL Sync block estimates low frequency offsets once the
284 * external frequency corrections start to take effect. This function
285 * returns not the last frequency offset estimate but the actual cumulative
286 * frequency offset configured on the external rotator.
287 *
288 * @return (float) Cumulative frequency offset.
289 */
290 float get_freq_offset() { return d_cum_freq_offset; }
291
292 /* Other externally readable stats */
293 bool get_coarse_freq_corr_state() { return d_freq_sync->is_coarse_corrected(); }
294 bool get_locked() { return d_locked; }
295 uint64_t get_sof_count() { return d_sof_cnt; }
296 uint64_t get_frame_count() { return d_frame_cnt; }
297 uint64_t get_rejected_count() { return d_rejected_cnt; }
298 uint64_t get_dummy_count() { return d_dummy_cnt; }
299 std::chrono::system_clock::time_point get_lock_time()
300 {
301 return d_frame_sync->get_lock_time();
302 };
303};
304
305} // namespace dvbs2rx
306} // namespace gr
307
308#endif /* INCLUDED_DVBS2RX_PLSYNC_CC_IMPL_H */
Frame Synchronizer.
Definition pl_frame_sync.h:128
std::chrono::system_clock::time_point get_lock_time()
Get the frame lock timestamp.
Definition pl_frame_sync.h:297
Frequency Synchronizer.
Definition pl_freq_sync.h:85
bool is_coarse_corrected()
Check whether the coarse frequency correction has been achieved.
Definition pl_freq_sync.h:334
PL Descrambler.
Definition pl_descrambler.h:32
PLSC Decoder.
Definition pl_signaling.h:89
Definition plsync_cc_impl.h:82
int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
float get_freq_offset()
Get the cumulative frequency offset.
Definition plsync_cc_impl.h:290
uint64_t get_frame_count()
Get the current count of processed (accepted) PLFRAMEs.
Definition plsync_cc_impl.h:296
uint64_t get_dummy_count()
Get the current count of received dummy PLFRAMEs.
Definition plsync_cc_impl.h:298
void forecast(int noutput_items, gr_vector_int &ninput_items_required)
uint64_t get_rejected_count()
Get the current count of rejected PLFRAMEs.
Definition plsync_cc_impl.h:297
bool get_coarse_freq_corr_state()
Get the coarse frequency offset correction state.
Definition plsync_cc_impl.h:293
plsync_cc_impl(int gold_code, int freq_est_period, double sps, int debug_level, bool acm_vcm, bool multistream, uint64_t pls_filter_lo, uint64_t pls_filter_hi)
uint64_t get_sof_count()
Get the current count of detected start-of-frame (SOF) instants.
Definition plsync_cc_impl.h:295
bool get_locked()
Get the current lock status.
Definition plsync_cc_impl.h:294
std::chrono::system_clock::time_point get_lock_time()
Get the timestamp of the last frame synchronization lock.
Definition plsync_cc_impl.h:299
DVB-S2 Physical Layer (PL) Synchronizer.
Definition plsync_cc.h:41
payload_state_t
Definition plsync_cc_impl.h:75
Fixed-length double-ended queue with contiguous volk-aligned elements.
Definition gr_bch.h:22
#define PLHEADER_LEN
Definition pl_defs.h:21
Index tracking for various segments of a PLFRAME.
Definition plsync_cc_impl.h:54
uint16_t i_slot
Definition plsync_cc_impl.h:57
uint16_t i_pilot_blk
Definition plsync_cc_impl.h:56
void step(uint16_t plframe_len, bool has_pilots)
uint16_t i_in_payload
Definition plsync_cc_impl.h:55
Definition plsync_cc_impl.h:63
pls_info_t pls
Definition plsync_cc_impl.h:66
float plheader_phase
Definition plsync_cc_impl.h:65
double coarse_foffset
Definition plsync_cc_impl.h:68
plframe_info_t()
Definition plsync_cc_impl.h:71
bool coarse_corrected
Definition plsync_cc_impl.h:67
volk::vector< gr_complex > plheader
Definition plsync_cc_impl.h:64
uint64_t abs_sof_idx
Definition plsync_cc_impl.h:70
double fine_foffset
Definition plsync_cc_impl.h:69
Definition pl_signaling.h:56
Definition plsync_cc_impl.h:40
std::queue< tag_t > tag_queue
Definition plsync_cc_impl.h:48
uint64_t last_tag_search_end
Definition plsync_cc_impl.h:43
rot_state_t past
Definition plsync_cc_impl.h:46
int tag_delay
Definition plsync_cc_impl.h:41
rot_state_t current
Definition plsync_cc_impl.h:47
std::map< uint64_t, rot_phase_adj_t > update_map
Definition plsync_cc_impl.h:50
uint64_t tag_search_start
Definition plsync_cc_impl.h:42
Definition plsync_cc_impl.h:33
uint64_t sof_idx
Definition plsync_cc_impl.h:35
rot_phase_adj_t(double p, uint64_t i)
Definition plsync_cc_impl.h:36
double phase_inc
Definition plsync_cc_impl.h:34
Definition plsync_cc_impl.h:27
uint64_t idx
Definition plsync_cc_impl.h:29
double freq
Definition plsync_cc_impl.h:28