SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
dvbs2.h
Go to the documentation of this file.
1 // This file is part of LeanSDR Copyright (C) 2016-2019 <pabr@pabr.org>.
2 // See the toplevel README for more information.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef LEANSDR_DVBS2_H
18 #define LEANSDR_DVBS2_H
19 
20 /*
21 #include "leansdr/bch.h"
22 #include "leansdr/crc.h"
23 #include "leansdr/dvb.h"
24 #include "leansdr/ldpc.h"
25 #include "leansdr/sdr.h"
26 #include "leansdr/softword.h"
27 */
28 
29 #include "bch.h"
30 
31 #include "crc.h"
32 
33 #include "dvb.h"
34 #include "softword.h"
35 #include "ldpc.h"
36 #include "sdr.h"
37 
38 namespace leansdr
39 {
40 
41 // S2 THRESHOLDS (for comparing demodulators)
42 
43 static const int S2_MAX_ERR_SOF_INITIAL = 1; // 26 bits
44 static const int S2_MAX_ERR_SOF = 13; // 26 bits
45 static const int S2_MAX_ERR_PLSCODE = 8; // 64 bits, dmin=32
46 static const int S2_MAX_ERR_PILOT = 10; // 36 bits
47 
48 static const int pilot_length = 36;
49 
50 // S2 SOF
51 // EN 302 307-1 section 5.5.2.1 SOF field
52 
53 template <typename T>
54 struct s2_sof
55 {
56  static const uint32_t VALUE = 0x18d2e82;
57  static const uint32_t MASK = 0x3ffffff;
58  static const int LENGTH = 26;
61  {
62  for (int s = 0; s < LENGTH; ++s)
63  {
64  int angle = ((VALUE >> (LENGTH - 1 - s)) & 1) * 2 + (s & 1); // pi/2-BPSK
65  symbols[s].re = cstln_amp * cosf(M_PI / 4 + 2 * M_PI * angle / 4);
66  symbols[s].im = cstln_amp * sinf(M_PI / 4 + 2 * M_PI * angle / 4);
67  }
68  }
69 }; // s2_sof
70 
71 // S2 PLS CODES
72 // Precomputes the PLS code sequences.
73 // EN 302 307-1 section 5.5.2.4 PLS code
74 
75 template <typename T>
77 {
78  // PLS index format MODCOD[4:0]|SHORTFRAME|PILOTS
79  static const int COUNT = 128;
80  static const int LENGTH = 64;
81  uint64_t codewords[COUNT];
84  {
85  uint32_t G[6] = {0x55555555,
86  0x33333333,
87  0x0f0f0f0f,
88  0x00ff00ff,
89  0x0000ffff,
90  0xffffffff};
91  for (int index = 0; index < COUNT; ++index)
92  {
93  uint32_t y = 0;
94  for (int row = 0; row < 6; ++row)
95  if ((index >> (6 - row)) & 1)
96  y ^= G[row];
97  uint64_t code = 0;
98  for (int bit = 31; bit >= 0; --bit)
99  {
100  int yi = (y >> bit) & 1;
101  if (index & 1)
102  code = (code << 2) | (yi << 1) | (yi ^ 1);
103  else
104  code = (code << 2) | (yi << 1) | yi;
105  }
106  // Scrambling
107  code ^= SCRAMBLING;
108  // Store precomputed codeword.
109  codewords[index] = code;
110  // Also store as symbols.
111  for (int i = 0; i < LENGTH; ++i)
112  {
113  int yi = (code >> (LENGTH - 1 - i)) & 1;
114  int nyi = yi ^ (i & 1);
115  symbols[index][i].re = cstln_amp * (1 - 2 * nyi) / sqrtf(2);
116  symbols[index][i].im = cstln_amp * (1 - 2 * yi) / sqrtf(2);
117  }
118  }
119  }
120  static const uint64_t SCRAMBLING = 0x719d83c953422dfa;
121 }; // s2_plscodes
122 
123 // S2 SCRAMBLING
124 // Precomputes the symbol rotations for PL scrambling.
125 // EN 302 307-1 section 5.5.4 Physical layer scrambling
126 
128 {
129  uint8_t Rn[131072]; // 0..3 (* 2pi/4)
130  s2_scrambling(int codenum = 0)
131  {
132  uint32_t stx = 0x00001, sty = 0x3ffff;
133  // x starts at codenum, wraps at index 2^18-1 by design
134  for (int i = 0; i < codenum; ++i)
135  stx = lfsr_x(stx);
136  // First half of sequence is LSB of scrambling angle
137  for (int i = 0; i < 131072; ++i)
138  {
139  int zn = (stx ^ sty) & 1;
140  Rn[i] = zn;
141  stx = lfsr_x(stx);
142  sty = lfsr_y(sty);
143  }
144  // Second half is MSB
145  for (int i = 0; i < 131072; ++i)
146  {
147  int zn = (stx ^ sty) & 1;
148  Rn[i] |= zn << 1;
149  stx = lfsr_x(stx);
150  sty = lfsr_y(sty);
151  }
152  }
154  {
155  int bit = ((X >> 7) ^ X) & 1;
156  return ((bit << 18) | X) >> 1;
157  }
159  {
160  int bit = ((Y >> 10) ^ (Y >> 7) ^ (Y >> 5) ^ Y) & 1;
161  return ((bit << 18) | Y) >> 1;
162  }
163 }; // s2_scrambling
164 
165 // S2 BBSCRAMBLING
166 // Precomputes the xor pattern for baseband scrambling.
167 // EN 302 307-1 section 5.2.2 BB scrambling
168 
170 {
172  {
173  uint16_t st = 0x00a9; // 000 0000 1010 1001 (Fig 5 reversed)
174  for (int i = 0; i < sizeof(pattern); ++i)
175  {
176  uint8_t out = 0;
177  for (int n = 8; n--;)
178  {
179  int bit = ((st >> 13) ^ (st >> 14)) & 1; // Taps
180  out = (out << 1) | bit; // MSB first
181  st = (st << 1) | bit; // Feedback
182  }
183  pattern[i] = out;
184  }
185  }
186  void transform(const uint8_t *in, int bbsize, uint8_t *out)
187  {
188  for (int i = 0; i < bbsize; ++i)
189  out[i] = in[i] ^ pattern[i];
190  }
191 
192  private:
193  uint8_t pattern[58192]; // Values 0..3
194 }; // s2_bbscrambling
195 
196 // S2 PHYSICAL LAYER SIGNALLING
197 
198 struct s2_pls
199 {
200  int modcod; // 0..31
201  bool sf;
202  bool pilots;
203  int framebits() const { return sf ? 16200 : 64800; }
204 };
205 
206 template <typename SOFTSYMB>
207 struct plslot
208 {
209  static const int LENGTH = 90;
210  bool is_pls;
211  union {
213  SOFTSYMB symbols[LENGTH];
214  };
215 };
216 
217 // EN 302 307-1 section 5.5.2.2 MODCOD field
218 // EN 302 307-1 section 6 Error performance
219 
220 const struct modcod_info
221 {
222  static const int MAX_SLOTS_PER_FRAME = 360;
223  static const int MAX_SYMBOLS_PER_FRAME =
224  (1 + MAX_SLOTS_PER_FRAME) * plslot<uint8_t>::LENGTH +
225  ((MAX_SLOTS_PER_FRAME - 1) / 16) * pilot_length;
226  int nslots_nf; // Number of 90-symbol slots per normal frame
227  int nsymbols; // Symbols in the constellation
230  // Ideal Es/N0 for normal frames
231  // EN 302 307 section 6 Error performance
232  float esn0_nf;
233  // Radii for APSK
234  // EN 302 307, section 5.4.3, Table 9
235  // EN 302 307, section 5.4.4, Table 10
236  float g1, g2, g3;
237 } modcod_infos[32] = {
238  {
239  0,
240  },
241  // 1 - 11
242  {360, 4, cstln_base::QPSK, FEC14, -2.35},
243  {360, 4, cstln_base::QPSK, FEC13, -1.24},
244  {360, 4, cstln_base::QPSK, FEC25, -0.30},
245  {360, 4, cstln_base::QPSK, FEC12, 1.00},
246  {360, 4, cstln_base::QPSK, FEC35, 2.23},
247  {360, 4, cstln_base::QPSK, FEC23, 3.10},
248  {360, 4, cstln_base::QPSK, FEC34, 4.03},
249  {360, 4, cstln_base::QPSK, FEC45, 4.68},
250  {360, 4, cstln_base::QPSK, FEC56, 5.18},
251  {360, 4, cstln_base::QPSK, FEC89, 6.20},
252  {360, 4, cstln_base::QPSK, FEC910, 6.42},
253  // 12 - 17
254  {240, 8, cstln_base::PSK8, FEC35, 5.50},
255  {240, 8, cstln_base::PSK8, FEC23, 6.62},
256  {240, 8, cstln_base::PSK8, FEC34, 7.91},
257  {240, 8, cstln_base::PSK8, FEC56, 9.35},
258  {240, 8, cstln_base::PSK8, FEC89, 10.69},
259  {240, 8, cstln_base::PSK8, FEC910, 10.98},
260  // 18 - 23
261  {180, 16, cstln_base::APSK16, FEC23, 8.97, 3.15},
262  {180, 16, cstln_base::APSK16, FEC34, 10.21, 2.85},
263  {180, 16, cstln_base::APSK16, FEC45, 11.03, 2.75},
264  {180, 16, cstln_base::APSK16, FEC56, 11.61, 2.70},
265  {180, 16, cstln_base::APSK16, FEC89, 12.89, 2.60},
266  {180, 16, cstln_base::APSK16, FEC910, 13.13, 2.57},
267  // 24 - 28
268  {144, 32, cstln_base::APSK32, FEC34, 12.73, 2.84, 5.27},
269  {144, 32, cstln_base::APSK32, FEC45, 13.64, 2.72, 4.87},
270  {144, 32, cstln_base::APSK32, FEC56, 14.28, 2.64, 4.64},
271  {144, 32, cstln_base::APSK32, FEC89, 15.69, 2.54, 4.33},
272  {144, 32, cstln_base::APSK32, FEC910, 16.05, 2.53, 4.30},
273  // 29 - 31
274  {
275  0,
276  },
277  {
278  0,
279  },
280  {
281  0,
282  }};
283 
284 // Assert that a MODCOD number is valid
286 {
287  if (m < 0 || m > 31)
288  fail("Invalid MODCOD number");
289  const modcod_info *r = &modcod_infos[m];
290  if (!r->nslots_nf)
291  fail("Unsupported MODCOD");
292  return r;
293 }
294 
295 // S2 FRAME TRANSMITTER
296 
297 template <typename T>
299 {
301  pipebuf<plslot<hard_ss>> &_in,
302  pipebuf<complex<T>> &_out)
303  : runnable(sch, "S2 frame transmitter"),
304  in(_in), out(_out, modcod_info::MAX_SYMBOLS_PER_FRAME)
305  {
306  float amp = cstln_amp / sqrtf(2);
307  qsymbols[0].re = +amp;
308  qsymbols[0].im = +amp;
309  qsymbols[1].re = +amp;
310  qsymbols[1].im = -amp;
311  qsymbols[2].re = -amp;
312  qsymbols[2].im = +amp;
313  qsymbols[3].re = -amp;
314  qsymbols[3].im = -amp;
315  }
316  void run()
317  {
318  while (in.readable() >= 1)
319  {
320  plslot<hard_ss> *pin = in.rd();
321  if (!pin->is_pls)
322  fail("Expected PLS pseudo-slot");
323  s2_pls *pls = &pin->pls;
324  const modcod_info *mcinfo = check_modcod(pls->modcod);
325  int nslots = (pls->sf ? mcinfo->nslots_nf / 4 : mcinfo->nslots_nf);
326  if (in.readable() < 1 + nslots)
327  break;
328  // Require room for BBHEADER + slots + optional pilots.
329  int nsymbols = ((1 + nslots) * plslot<hard_ss>::LENGTH +
330  (pls->pilots ? ((nslots - 1) / 16) * pilot_length : 0));
331  if (out.writable() < nsymbols)
332  break;
333  update_cstln(mcinfo);
334  int nw = run_frame(pls, mcinfo, pin + 1, nslots, out.wr());
335  if (nw != nsymbols)
336  fail("Bug: s2_frame_transmitter overflow");
337  in.read(1 + nslots);
338  out.written(nsymbols);
339  }
340  }
341  int run_frame(s2_pls *pls, const modcod_info *mcinfo,
342  const plslot<hard_ss> *pin, int nslots,
343  complex<T> *pout)
344  {
345  complex<T> *pout0 = pout; // For sanity check
346  // PLHEADER: SOF AND PLSCODE
347  // EN 302 307-1 section 5.5.2 PL signalling
348  memcpy(pout, sof.symbols, sof.LENGTH * sizeof(*pout));
349  pout += sof.LENGTH;
350  int pls_index = (pls->modcod << 2) | (pls->sf << 1) | pls->pilots;
351  memcpy(pout, plscodes.symbols[pls_index], plscodes.LENGTH * sizeof(*pout));
352  pout += plscodes.LENGTH;
353  // Slots and pilots
354  int till_next_pilot = pls->pilots ? 16 : nslots;
355  uint8_t *scr = &scrambling.Rn[0];
356  for (int S = 0; S < nslots; ++S, ++pin, --till_next_pilot)
357  {
358  if (till_next_pilot == 0)
359  {
360  // Send pilot
361  for (int s = 0; s < pilot_length; ++s, ++scr, ++pout)
362  scramble(&qsymbols[0], *scr, pout);
363  till_next_pilot = 16;
364  }
365  // Send slot
366  if (pin->is_pls)
367  fail("s2_frame_transmitter: bad input sequence");
368  const hard_ss *ps = pin->symbols;
369  for (int s = 0; s < pin->LENGTH; ++s, ++ps, ++scr, ++pout)
370  scramble(&csymbols[*ps], *scr, pout);
371  }
372  return pout - pout0;
373  }
374  inline void scramble(const complex<T> *src, uint8_t r, complex<T> *dst)
375  {
376  switch (r)
377  {
378  case 3:
379  dst->re = src->im;
380  dst->im = -src->re;
381  break;
382  case 2:
383  dst->re = -src->re;
384  dst->im = -src->im;
385  break;
386  case 1:
387  dst->re = -src->im;
388  dst->im = src->re;
389  break;
390  default:
391  *dst = *src;
392  }
393  }
394 
395  private:
398  cstln_lut<hard_ss, 256> *cstln; // NULL initially
399  complex<T> *csymbols; // Valid iff cstln is valid. RMS cstln_amp.
400  void update_cstln(const modcod_info *mcinfo)
401  {
402  if (!cstln || cstln->nsymbols != mcinfo->nsymbols)
403  {
404  if (cstln)
405  {
406  fprintf(stderr, "Warning: Variable MODCOD is inefficient\n");
407  delete cstln;
408  delete csymbols;
409  }
410  if (sch->debug)
411  fprintf(stderr, "Building constellation %d\n", mcinfo->nsymbols);
412  // TBD Different Es/N0 for short frames ?
413  cstln = new cstln_lut<hard_ss, 256>(mcinfo->c, mcinfo->esn0_nf,
414  mcinfo->g1, mcinfo->g2, mcinfo->g3);
415  csymbols = new complex<T>[cstln->nsymbols];
416  for (int s = 0; s < cstln->nsymbols; ++s)
417  {
418  csymbols[s].re = cstln->symbols[s].re;
419  csymbols[s].im = cstln->symbols[s].im;
420  }
421  }
422  }
423  complex<T> qsymbols[4]; // RMS cstln_amp
427 }; // s2_frame_transmitter
428 
429 // S2 FRAME RECEIVER
430 
431 static int pl_errors = 0, pl_symbols = 0;
432 
433 #define TEST_DIVERSITY 0
434 
435 template <typename T, typename SOFTSYMB>
437 {
440  float Ftune; // Tuning bias in cycles per symbol
441  float Fm; // Baud rate in Hz, for debug messages only. TBD remove.
442  bool strongpls;
443  static const int MAX_SYMBOLS_PER_FRAME =
445  ((modcod_info::MAX_SLOTS_PER_FRAME - 1) / 16) * pilot_length;
447  sampler_interface<T> *_sampler,
448  pipebuf<complex<T>> &_in,
449  pipebuf<plslot<SOFTSYMB>> &_out,
450  pipebuf<float> *_freq_out = NULL,
451  pipebuf<float> *_ss_out = NULL,
452  pipebuf<float> *_mer_out = NULL,
453  pipebuf<complex<float>> *_cstln_out = NULL,
454  pipebuf<complex<float>> *_cstln_pls_out = NULL,
455  pipebuf<complex<float>> *_symbols_out = NULL,
456  pipebuf<int> *_state_out = NULL)
457  : runnable(sch, "S2 frame receiver"),
458  sampler(_sampler),
459  meas_decimation(1048576),
460  Ftune(0), Fm(0),
461  strongpls(false),
462  in_power(0), ev_power(0), agc_gain(1), agc_bw(1e-3),
463  nsyncs(0),
464  cstln(NULL),
465  in(_in), out(_out, 1 + modcod_info::MAX_SLOTS_PER_FRAME),
466  meas_count(0),
467  freq_out(opt_writer(_freq_out)),
468  ss_out(opt_writer(_ss_out)),
469  mer_out(opt_writer(_mer_out)),
470  cstln_out(opt_writer(_cstln_out, 1024)),
471  cstln_pls_out(opt_writer(_cstln_pls_out, 1024)),
472  symbols_out(opt_writer(_symbols_out, MAX_SYMBOLS_PER_FRAME)),
473  state_out(opt_writer(_state_out)),
474  report_state(false),
475  scrambling(0),
476  m_modcodType(-1),
477  m_modcodRate(-1)
478  {
479  // Constellation for PLS
481  add_syncs(qpsk);
482 
483  init_coarse_freq();
484 
485 #if TEST_DIVERSITY
486  fprintf(stderr, "** DEBUG: Diversity test mode (slower)\n");
487 #endif
488  }
489 
490  enum
491  {
495  } state;
496 
497  float min_freqw16, max_freqw16;
498 
499  // State during COARSE_FREQ
502 
503  // State during FRAME_SEARCH and FRAME_LOCKED
504  float freqw16; // Carrier frequency initialized by COARSE_FREQ
505  float phase16; // Estimated phase of carrier at next symbol
506 
507  float mu; // Time to next symbol, in samples
508  float omega; // Samples per symbol
509 
510  void run()
511  {
512  // Require enough samples to detect one plheader,
513  // TBD margin ?
514  int min_samples = (1 + MAX_SYMBOLS_PER_FRAME +
516  omega * 2;
517  while (in.readable() >= min_samples + sampler->readahead() &&
518  out.writable() >= 1 + modcod_info::MAX_SLOTS_PER_FRAME &&
519  opt_writable(freq_out, 1) &&
520  opt_writable(ss_out, 1) &&
521  opt_writable(mer_out, 1) &&
522  opt_writable(symbols_out, MAX_SYMBOLS_PER_FRAME) &&
523  opt_writable(state_out, 1))
524  {
525  if (report_state)
526  {
527  // Report unlocked state on first invocation.
528  opt_write(state_out, 0);
529  report_state = false;
530  }
531  switch (state)
532  {
533  case COARSE_FREQ:
534  run_frame_coarse();
535  break;
536  case FRAME_SEARCH:
537  run_frame_search();
538  break;
539  case FRAME_LOCKED:
540  run_frame_locked();
541  break;
542  }
543  }
544  }
545 
546  // Initial state
548  {
549  diffcorr = 0;
550  coarse_count = 0;
551  memset(hist, 0, sizeof(hist));
552  state = COARSE_FREQ;
553  }
554 
555  // State transtion
557  {
558  opt_write(state_out, 0);
559  init_coarse_freq();
560  }
561 
563  {
564  freqw16 = 65536 * Ftune;
565  min_freqw16 = freqw16 - 65536.0 / 9;
566  max_freqw16 = freqw16 + 65536.0 / 9;
567 
568  complex<T> *pin = in.rd();
569  complex<T> p = *pin++;
570  int nsamples = MAX_SYMBOLS_PER_FRAME * omega;
571  for (int s = nsamples; s--; ++pin)
572  {
573  complex<T> n = *pin;
574  diffcorr.re += p.re * n.re + p.im * n.im;
575  diffcorr.im += p.re * n.im - p.im * n.re;
576  p = n;
577  }
578  in.read(nsamples);
579  ++coarse_count;
580  if (coarse_count == 50)
581  {
582  float freqw = atan2f(diffcorr.im, diffcorr.re) * omega;
583  fprintf(stderr, "COARSE(%d): %f rad/symb (%.0f Hz at %.0f baud)\n",
584  coarse_count, freqw, freqw * Fm / (2 * M_PI), Fm);
585 #if 0
586  freqw16 = freqw * 65536 / (2*M_PI);
587 #else
588  fprintf(stderr, "Ignoring coarse det, using %f\n", freqw16 * Fm / 65536);
589 #endif
590  enter_frame_search();
591  }
592  }
593 
594  // State transtion
596  {
597  opt_write(state_out, 0);
598  mu = 0;
599  phase16 = 0;
600  if (sch->debug)
601  fprintf(stderr, "ACQ\n");
602  state = FRAME_SEARCH;
603  }
604 
606  {
607  complex<float> *psampled;
608  if (cstln_out && cstln_out->writable() >= 1024)
609  psampled = cstln_out->wr();
610  else
611  psampled = NULL;
612 
613  // Preserve float precision
614  phase16 -= 65536 * floor(phase16 / 65536);
615 
616  int nsymbols = MAX_SYMBOLS_PER_FRAME; // TBD Adjust after PLS decoding
617 
618  sampler_state ss = {in.rd(), mu, phase16, freqw16};
619  sampler->update_freq(ss.fw16 / omega);
620 
621  if (!in_power)
622  init_agc(ss.p, 64);
623  update_agc();
624 
625  for (int s = 0; s < nsymbols; ++s)
626  {
627  complex<float> p0 = interp_next(&ss);
628  track_agc(p0);
629  complex<float> p = p0 * agc_gain;
630 
631  // Constellation plot
632  if (psampled && s < 1024)
633  *psampled++ = p;
634 
635  // Demodulate everything as QPSK.
636  // Occasionally it locks onto 8PSK at offet 2pi/16.
637  uint8_t symb = track_symbol(&ss, p, qpsk, 1);
638 
639  // Feed symbol into all synchronizers.
640  for (sync *ps = syncs; ps < syncs + nsyncs; ++ps)
641  {
642  ps->hist = (ps->hist << 1) | ((ps->tobpsk >> symb) & 1);
643  int errors = hamming_weight((ps->hist & sof.MASK) ^ sof.VALUE);
644  if (errors <= S2_MAX_ERR_SOF_INITIAL)
645  {
646  if (sch->debug2)
647  fprintf(stderr, "Found SOF+%d at %d offset %f\n",
648  errors, s, ps->offset16);
649  ss.ph16 += ps->offset16;
650  in.read(ss.p - in.rd());
651  mu = ss.mu;
652  phase16 = ss.ph16;
653  freqw16 = ss.fw16;
654  if (psampled)
655  cstln_out->written(psampled - cstln_out->wr());
656  enter_frame_locked();
657  return;
658  }
659  }
660  ss.normalize();
661  }
662 
663  // Write back sampler progress
664  in.read(ss.p - in.rd());
665  mu = ss.mu;
666  phase16 = ss.ph16;
667  freqw16 = ss.fw16;
668  if (psampled)
669  cstln_out->written(psampled - cstln_out->wr());
670  }
671 
672  // State transtion
674  {
675  opt_write(state_out, 1);
676  if (sch->debug)
677  fprintf(stderr, "LOCKED\n");
678  state = FRAME_LOCKED;
679  }
680 
681  // Note: Starts after SOF
682 
684  {
685  complex<T> *p; // Pointer to samples
686  float mu; // Time of next symbol, counted from p
687  float ph16; // Carrier phase at next symbol, cycles*65536
688  float fw16; // Carrier frequency, cycles per symbol * 65536
689  uint8_t *scr; // Position in scrambling sequeence
690  void skip_symbols(int ns, float omega)
691  {
692  mu += omega * ns;
693  ph16 += fw16 * ns;
694  scr += ns;
695  }
696  void normalize()
697  {
698  ph16 = fmodf(ph16, 65536.0f); // Rounding direction irrelevant
699  }
700  };
701 
702 #define xfprintf(...) \
703  { \
704  }
705  //#define xfprintf fprintf
706 
708  {
709  complex<float> *psampled;
710  if (cstln_out && cstln_out->writable() >= 1024)
711  psampled = cstln_out->wr();
712  else
713  psampled = NULL;
714  complex<float> *psampled_pls;
715  if (cstln_pls_out && cstln_pls_out->writable() >= 1024)
716  psampled_pls = cstln_pls_out->wr();
717  else
718  psampled_pls = NULL;
719 
720 #if TEST_DIVERSITY
721  complex<float> *psymbols = symbols_out ? symbols_out->wr() : NULL;
722  float scale_symbols = 1.0 / cstln_amp;
723 #endif
724 
725  xfprintf(stderr, "lock0step fw= %f (%.0f Hz) mu=%f\n",
726  freqw16, freqw16 * Fm / 65536, mu);
727 
728  sampler_state ss = {in.rd(), mu, phase16, freqw16, scrambling.Rn};
729  sampler->update_freq(ss.fw16 / omega);
730 
731  update_agc();
732 
733  // Read PLSCODE
734 
735  uint64_t plscode = 0;
736  complex<float> pls_symbols[plscodes.LENGTH];
737  for (int s = 0; s < plscodes.LENGTH; ++s)
738  {
739  complex<float> p = interp_next(&ss) * agc_gain;
740 #if TEST_DIVERSITY
741  if (psymbols)
742  *psymbols++ = p * scale_symbols;
743 #endif
744  pls_symbols[s] = p;
745  if (psampled_pls)
746  *psampled_pls++ = p;
747  int bit = (p.im < 1); // TBD suboptimal
748  plscode = (plscode << 1) | bit;
749  }
750  int pls_index = -1;
751  int pls_errors = S2_MAX_ERR_PLSCODE + 1; // dmin=32
752  // TBD: Optimiser
753  for (int i = 0; i < plscodes.COUNT; ++i)
754  {
755  int e = hamming_weight(plscode ^ plscodes.codewords[i]);
756  if (e < pls_errors)
757  {
758  pls_errors = e;
759  pls_index = i;
760  }
761  }
762  if (pls_index < 0)
763  {
764  if (sch->debug2)
765  fprintf(stderr, "Too many errors in plheader (%d)\n", pls_errors);
766  in.read(ss.p - in.rd());
767  enter_frame_search();
768  return;
769  }
770 
771  // Adjust phase with PLS
772  complex<float> pls_corr = conjprod(plscodes.symbols[pls_index],
773  pls_symbols, plscodes.LENGTH);
774  ss.normalize();
775  align_phase(&ss, pls_corr);
776 
777  s2_pls pls;
778  pls.modcod = pls_index >> 2; // Guaranteed 0..31
779  pls.sf = pls_index & 2;
780  pls.pilots = pls_index & 1;
781  xfprintf(stderr, "PLS: modcod %d, short=%d, pilots=%d (%d errors)\n",
782  pls.modcod, pls.sf, pls.pilots, pls_errors);
783  const modcod_info *mcinfo = &modcod_infos[pls.modcod];
784  if (!mcinfo->nslots_nf)
785  {
786  fprintf(stderr, "Unsupported or corrupted MODCOD\n");
787  in.read(ss.p - in.rd());
788  enter_frame_search();
789  return;
790  }
791 #if 1 // TBD use fec_infos
792  if (pls.sf && mcinfo->rate == FEC910)
793  {
794  fprintf(stderr, "Unsupported or corrupted FEC\n");
795  in.read(ss.p - in.rd());
796  enter_frame_search();
797  return;
798  }
799 #endif
800  // Store current MODCOD info
801  if (mcinfo->c != m_modcodType) {
802  m_modcodType = mcinfo->c;
803  }
804  if (mcinfo->rate != m_modcodRate) {
805  m_modcodRate = mcinfo->rate;
806  }
807 
808  // TBD Comparison of nsymbols is insufficient for DVB-S2X.
809  if (!cstln || cstln->nsymbols != mcinfo->nsymbols)
810  {
811  if (cstln)
812  {
813  fprintf(stderr, "Warning: Variable MODCOD is inefficient\n");
814  delete cstln;
815  }
816  fprintf(stderr, "Creating LUT for %s ratecode %d\n",
817  cstln_base::names[mcinfo->c], mcinfo->rate);
818  cstln = new cstln_lut<SOFTSYMB, 256>(mcinfo->c, mcinfo->esn0_nf,
819  mcinfo->g1, mcinfo->g2, mcinfo->g3);
820  cstln->m_rateCode = (int) mcinfo->rate;
821  cstln->m_typeCode = (int) mcinfo->c;
822  cstln->m_setByModcod = true;
823 #if 0
824  fprintf(stderr, "Dumping constellation LUT to stdout.\n");
825  cstln->dump(stdout);
826 #endif
827  }
828 
829  int S = pls.sf ? mcinfo->nslots_nf / 4 : mcinfo->nslots_nf;
830 
831  plslot<SOFTSYMB> *pout = out.wr(), *pout0 = pout;
832 
833  // Output special slot with PLS information
834  pout->is_pls = true;
835  pout->pls = pls;
836  ++pout;
837 
838  // Read slots and pilots
839 
840  int pilot_errors = 0;
841 
842  // Slots to skip until next PL slot (pilot or sof)
843  int till_next_pls = pls.pilots ? 16 : S;
844 
845  for (int leansdr_slots = S; leansdr_slots--; ++pout, --till_next_pls)
846  {
847  if (till_next_pls == 0)
848  {
849  // Read pilot
850  int errors = 0;
851  complex<float> corr = 0;
852  for (int s = 0; s < pilot_length; ++s)
853  {
854  complex<float> p0 = interp_next(&ss);
855  track_agc(p0);
856  complex<float> p = p0 * agc_gain;
857 #if TEST_DIVERSITY
858  if (psymbols)
859  *psymbols++ = p * scale_symbols;
860 #endif
861  (void)track_symbol(&ss, p, qpsk, 1);
862  if (psampled_pls)
863  *psampled_pls++ = p;
864  complex<float> d = descramble(&ss, p);
865  if (d.im < 0 || d.re < 0)
866  ++errors;
867  corr.re += d.re + d.im;
868  corr.im += d.im - d.re;
869  }
870  if (errors > S2_MAX_ERR_PILOT)
871  {
872  if (sch->debug2)
873  fprintf(stderr, "Too many errors in pilot (%d/36)\n", errors);
874  in.read(ss.p - in.rd());
875  enter_frame_search();
876  return;
877  }
878  pilot_errors += errors;
879  ss.normalize();
880  align_phase(&ss, corr);
881  till_next_pls = 16;
882  }
883  // Read slot
884  pout->is_pls = false;
885  complex<float> p; // Export last symbols for cstln_out
886  for (int s = 0; s < pout->LENGTH; ++s)
887  {
888  p = interp_next(&ss) * agc_gain;
889 #if TEST_DIVERSITY
890  if (psymbols)
891  *psymbols++ = p * scale_symbols;
892 #endif
893 #if 1 || TEST_DIVERSITY
894  (void)track_symbol(&ss, p, cstln, 0); // SLOW
895 #endif
896  complex<float> d = descramble(&ss, p);
897 #if 0 // Slow
898  SOFTSYMB *symb = &cstln->lookup(d.re, d.im)->ss;
899 #else // Avoid scaling floats. May wrap at very low SNR.
900  SOFTSYMB *symb = &cstln->lookup((int)d.re, (int)d.im)->ss;
901 #endif
902  pout->symbols[s] = *symb;
903  }
904  if (psampled)
905  *psampled++ = p;
906  } // slots
907 
908  // Read SOF
909 
910  memset(hist, 0, sizeof(hist));
911  complex<float> sof_corr = 0;
912  uint32_t sofbits = 0;
913  for (int s = 0; s < sof.LENGTH; ++s)
914  {
915  complex<float> p0 = interp_next(&ss);
916  track_agc(p0);
917  complex<float> p = p0 * agc_gain;
918 #if TEST_DIVERSITY
919  if (psymbols)
920  *psymbols++ = p * scale_symbols;
921 #endif
922  uint8_t symb = track_symbol(&ss, p, qpsk, 1);
923  if (psampled_pls)
924  *psampled_pls++ = p;
925  int bit = (p.im < 0); // suboptimal
926  sofbits = (sofbits << 1) | bit;
927  sof_corr += conjprod(sof.symbols[s], p);
928  }
929  int sof_errors = hamming_weight(sofbits ^ sof.VALUE);
930  if (sof_errors >= S2_MAX_ERR_SOF)
931  {
932  if (sch->debug2)
933  fprintf(stderr, "Too many errors in SOF (%d/26)\n", sof_errors);
934  in.read(ss.p - in.rd());
935  enter_coarse_freq();
936  return;
937  }
938  ss.normalize();
939  align_phase(&ss, sof_corr);
940 
941  // Commit whole frame after final SOF.
942  out.written(pout - pout0);
943 
944  // Write back sampler progress
945  meas_count += ss.p - in.rd();
946  in.read(ss.p - in.rd());
947  mu = ss.mu;
948  phase16 = ss.ph16;
949  freqw16 = ss.fw16;
950 
951  // Measurements
952  if (psampled)
953  cstln_out->written(psampled - cstln_out->wr());
954  if (psampled_pls)
955  cstln_pls_out->written(psampled_pls - cstln_pls_out->wr());
956 #if TEST_DIVERSITY
957  if (psymbols)
958  symbols_out->written(psymbols - symbols_out->wr());
959 #endif
960  if (meas_count >= meas_decimation)
961  {
962  opt_write(freq_out, freqw16 / 65536 / omega);
963  opt_write(ss_out, in_power);
964  // TBD Adjust if cfg.strongpls
965  float mer = ev_power ? (float)cstln_amp * cstln_amp / ev_power : 1;
966  opt_write(mer_out, 10 * logf(mer) / logf(10));
967  meas_count -= meas_decimation;
968  }
969 
970  int all_errors = pls_errors + pilot_errors + sof_errors;
971  int max_errors = plscodes.LENGTH + sof.LENGTH;
972  if (pls.pilots)
973  max_errors += ((S - 1) / 16) * pilot_length;
974 
975  xfprintf(stderr, "success fw= %f (%.0f Hz) mu= %f "
976  "errors=%d/64+%d+%d/26 = %2d/%d\n",
977  freqw16, freqw16 * Fm / 65536, mu,
978  pls_errors, pilot_errors, sof_errors, all_errors, max_errors);
979  pl_errors += all_errors;
980  pl_symbols += max_errors;
981  }
982 
983  void shutdown()
984  {
985  fprintf(stderr, "PL SER: %f ppm\n", pl_errors / (pl_symbols + 1e-6) * 1e6);
986  }
987 
988  void init_agc(const complex<T> *buf, int n)
989  {
990  in_power = 0;
991  for (int i = 0; i < n; ++i)
992  in_power += cnorm2(buf[i]);
993  in_power /= n;
994  }
995  void track_agc(const complex<float> &p)
996  {
997  float in_p = p.re * p.re + p.im * p.im;
998  in_power = in_p * agc_bw + in_power * (1.0f - agc_bw);
999  }
1000 
1001  void update_agc()
1002  {
1003  float in_amp = gen_sqrt(in_power);
1004  if (!in_amp)
1005  return;
1006  if (!strongpls || !cstln)
1007  {
1008  // Match RMS amplitude
1009  agc_gain = cstln_amp / in_amp;
1010  }
1011  else
1012  {
1013  // Match peak amplitude
1014  agc_gain = cstln_amp / cstln->amp_max / in_amp;
1015  }
1016  }
1017 
1019  {
1020  int r = *ss->scr++;
1021  complex<float> res;
1022  switch (r)
1023  {
1024  case 3:
1025  res.re = -p.im;
1026  res.im = p.re;
1027  break;
1028  case 2:
1029  res.re = -p.re;
1030  res.im = -p.im;
1031  break;
1032  case 1:
1033  res.re = p.im;
1034  res.im = -p.re;
1035  break;
1036  default:
1037  res = p;
1038  }
1039  return res;
1040  }
1041 
1042  // Interpolator
1043 
1045  {
1046  // Skip to next sample
1047  while (ss->mu >= 1)
1048  {
1049  ++ss->p;
1050  ss->mu -= 1.0f;
1051  }
1052  // Interpolate
1053 #if 0
1054  // Interpolate linearly then derotate.
1055  // This will fail with large carrier offsets (e.g. --tune).
1056  float cmu = 1.0f - ss->mu;
1057  complex<float> s(ss->p[0].re*cmu + ss->p[1].re*ss->mu,
1058  ss->p[0].im*cmu + ss->p[1].im*ss->mu);
1059  ss->mu += omega;
1060  // Derotate
1061  const complex<float> &rot = trig.expi(-ss->ph16);
1062  ss->ph16 += ss->fw16;
1063  return rot * s;
1064 #else
1065  // Use generic interpolator
1066  complex<float> s = sampler->interp(ss->p, ss->mu, ss->ph16);
1067  ss->mu += omega;
1068  ss->ph16 += ss->fw16;
1069  return s;
1070 #endif
1071  }
1072 
1074  {
1075 #if 0
1076  // Reference implementation
1077  float err = atan2f(c.im,c.re) * (65536/(2*M_PI));
1078 #else
1079  // Same performance as atan2f, faster
1080  if (!c.re)
1081  return;
1082  float err = c.im / c.re * (65536 / (2 * M_PI));
1083 #endif
1084  ss->ph16 += err;
1085  }
1086 
1088  cstln_lut<SOFTSYMB, 256> *c, int mode)
1089  {
1090  static struct
1091  {
1092  float kph, kfw, kmu;
1093  } gains[2] = {
1094  {4e-2, 1e-4, 0.001 / (cstln_amp * cstln_amp)},
1095  {4e-2, 1e-4, 0.001 / (cstln_amp * cstln_amp)}};
1096  // Decision
1097  typename cstln_lut<SOFTSYMB, 256>::result *cr = c->lookup(p.re, p.im);
1098  // Carrier tracking
1099  ss->ph16 += cr->phase_error * gains[mode].kph;
1100  ss->fw16 += cr->phase_error * gains[mode].kfw;
1101  if (ss->fw16 < min_freqw16)
1102  ss->fw16 = min_freqw16;
1103  if (ss->fw16 > max_freqw16)
1104  ss->fw16 = max_freqw16;
1105  // Phase tracking
1106  hist[2] = hist[1];
1107  hist[1] = hist[0];
1108  hist[0].p = p;
1109  complex<int8_t> *cp = &c->symbols[cr->symbol];
1110  hist[0].c.re = cp->re;
1111  hist[0].c.im = cp->im;
1112  float muerr =
1113  ((hist[0].p.re - hist[2].p.re) * hist[1].c.re +
1114  (hist[0].p.im - hist[2].p.im) * hist[1].c.im) -
1115  ((hist[0].c.re - hist[2].c.re) * hist[1].p.re +
1116  (hist[0].c.im - hist[2].c.im) * hist[1].p.im);
1117  float mucorr = muerr * gains[mode].kmu;
1118  const float max_mucorr = 0.1;
1119  // TBD Optimize out statically
1120  if (mucorr < -max_mucorr)
1121  mucorr = -max_mucorr;
1122  if (mucorr > max_mucorr)
1123  mucorr = max_mucorr;
1124  ss->mu += mucorr;
1125  // Error vector for MER
1126  complex<float> ev(p.re - cp->re, p.im - cp->im);
1127  float ev_p = ev.re * ev.re + ev.im * ev.im;
1128  ev_power = ev_p * agc_bw + ev_power * (1.0f - agc_bw);
1129  return cr->symbol;
1130  }
1131 
1132  struct
1133  {
1134  complex<float> p; // Received symbol
1135  complex<float> c; // Matched constellation point
1136  } hist[3];
1137 
1138  public:
1139  float in_power, ev_power;
1140  float agc_gain;
1141  float agc_bw;
1143  static const int MAXSYNCS = 8;
1144  struct sync
1145  {
1146  uint16_t nsmask; // bitmask of cstln orders for which this sync is used
1147  uint64_t tobpsk; // Bitmask from cstln symbols to pi/2-BPSK bits
1148  float offset16; // Phase offset 0..65536
1149  uint32_t hist; // For SOF detection
1150  } syncs[MAXSYNCS], *current_sync;
1151  int nsyncs;
1154  // Initialize synchronizers for an arbitrary constellation.
1156  {
1157  int random_decision = 0;
1158  int nrot = c->nrotations;
1159 #if 0
1160  if ( nrot == 4 ) {
1161  fprintf(stderr, "Special case for 8PSK locking as QPSK pi/8\n");
1162  nrot = 8;
1163  }
1164 #endif
1165  for (int r = 0; r < nrot; ++r)
1166  {
1167  if (nsyncs == MAXSYNCS)
1168  fail("Bug: too many syncs");
1169  sync *s = &syncs[nsyncs++];
1170  s->offset16 = 65536.0 * r / nrot;
1171  float angle = -2 * M_PI * r / nrot;
1172  s->tobpsk = 0;
1173  for (int i = c->nsymbols; i--;)
1174  {
1175  complex<int8_t> p = c->symbols[i];
1176  float re = p.re * cosf(angle) - p.im * sinf(angle);
1177  float im = p.re * sinf(angle) + p.im * cosf(angle);
1178  int bit;
1179  if (im > 1)
1180  bit = 0;
1181  else if (im < -1)
1182  bit = 1;
1183  else
1184  {
1185  bit = random_decision;
1186  random_decision ^= 1;
1187  } // Near 0
1188  s->tobpsk = (s->tobpsk << 1) | bit;
1189  }
1190  s->hist = 0;
1191  }
1192  }
1193 
1199  pipewriter<float> *freq_out, *ss_out, *mer_out;
1205  // S2 constants
1210  // Max size of one frame
1211  // static const int MAX_SLOTS = 360;
1212  static const int MAX_SLOTS = 240; // DEBUG match test signal
1213  static const int MAX_SYMBOLS =
1214  (1 + MAX_SLOTS) * plslot<SOFTSYMB>::LENGTH + ((MAX_SLOTS - 1) / 16) * pilot_length;
1215 }; // s2_frame_receiver
1216 
1217 template <typename SOFTBYTE>
1218 struct fecframe
1219 {
1221  SOFTBYTE bytes[64800 / 8]; // Contains 16200/8 or 64800/8 bytes.
1222 };
1223 
1224 // S2 INTERLEAVER
1225 // EN 302 307-1 section 5.3.3 Bit Interleaver
1226 
1228 {
1230  pipebuf<fecframe<hard_sb>> &_in,
1231  pipebuf<plslot<hard_ss>> &_out)
1232  : runnable(sch, "S2 interleaver"),
1233  in(_in), out(_out, 1 + 360)
1234  {
1235  }
1236  void run()
1237  {
1238  while (in.readable() >= 1)
1239  {
1240  const s2_pls *pls = &in.rd()->pls;
1241  const modcod_info *mcinfo = check_modcod(pls->modcod);
1242  int nslots = pls->sf ? mcinfo->nslots_nf / 4 : mcinfo->nslots_nf;
1243  if (out.writable() < 1 + nslots)
1244  return;
1245  const hard_sb *pbytes = in.rd()->bytes;
1246  // Output pseudo slot with PLS.
1247  plslot<hard_ss> *ppls = out.wr();
1248  ppls->is_pls = true;
1249  ppls->pls = *pls;
1250  out.written(1);
1251  // Interleave
1252  plslot<hard_ss> *pout = out.wr();
1253  if (mcinfo->nsymbols == 4)
1254  serialize_qpsk(pbytes, nslots, pout);
1255  else
1256  {
1257  int bps = log2(mcinfo->nsymbols);
1258  int rows = pls->framebits() / bps;
1259  if (mcinfo->nsymbols == 8 && mcinfo->rate == FEC35)
1260  interleave(bps, rows, pbytes, nslots, false, pout);
1261  else
1262  interleave(bps, rows, pbytes, nslots, true, pout);
1263  }
1264  in.read(1);
1265  out.written(nslots);
1266  }
1267  }
1268 
1269  private:
1270  // Fill slots with serialized QPSK symbols, MSB first.
1271  static void serialize_qpsk(const hard_sb *pin, int nslots,
1272  plslot<hard_ss> *pout)
1273  {
1274 #if 0 // For reference
1275  hard_sb acc;
1276  int nacc = 0;
1277  for ( ; nslots; --nslots,++pout ) {
1278  pout->is_pls = false;
1279  hard_ss *ps = pout->symbols;
1280  for ( int ns=pout->LENGTH; ns--; ++ps ) {
1281  if ( nacc < 2 ) { acc=*pin++; nacc=8; }
1282  *ps = acc>>6;
1283  acc <<= 2;
1284  nacc -= 2;
1285  }
1286  }
1287  if ( nacc ) fail("Bug: s2_interleaver");
1288 #else
1289  if (nslots % 2)
1290  fatal("Bug: Truncated byte");
1291  for (; nslots; nslots -= 2)
1292  {
1293  hard_sb b;
1294  hard_ss *ps;
1295  // Slot 0 (mod 2)
1296  pout->is_pls = false;
1297  ps = pout->symbols;
1298  for (int i = 0; i < 22; ++i)
1299  {
1300  b = *pin++;
1301  *ps++ = (b >> 6);
1302  *ps++ = (b >> 4) & 3;
1303  *ps++ = (b >> 2) & 3;
1304  *ps++ = (b)&3;
1305  }
1306  b = *pin++;
1307  *ps++ = (b >> 6);
1308  *ps++ = (b >> 4) & 3;
1309  // Slot 1 (mod 2)
1310  ++pout;
1311  pout->is_pls = false;
1312  ps = pout->symbols;
1313  *ps++ = (b >> 2) & 3;
1314  *ps++ = (b)&3;
1315  for (int i = 0; i < 22; ++i)
1316  {
1317  b = *pin++;
1318  *ps++ = (b >> 6);
1319  *ps++ = (b >> 4) & 3;
1320  *ps++ = (b >> 2) & 3;
1321  *ps++ = (b)&3;
1322  }
1323  ++pout;
1324  }
1325 #endif
1326  }
1327 
1328  // Fill slots with interleaved symbols.
1329  // EN 302 307-1 figures 7 and 8
1330 #if 0 // For reference
1331  static void interleave(int bps, int rows,
1332  const hard_sb *pin, int nslots,
1333  bool msb_first, plslot<hard_ss> *pout) {
1334  if ( bps==4 && rows==4050 && msb_first )
1335  return interleave4050(pin, nslots, pout);
1336  if ( rows % 8 ) fatal("modcod/framesize combination not supported\n");
1337  int stride = rows/8; // Offset to next column, in bytes
1338  hard_sb accs[bps]; // One accumulator per column
1339  int nacc = 0; // Bits in each column accumulator
1340  for ( ; nslots; --nslots,++pout ) {
1341  pout->is_pls = false;
1342  hard_ss *ps = pout->symbols;
1343  for ( int ns=pout->LENGTH; ns--; ++ps ) {
1344  if ( ! nacc ) {
1345  const hard_sb *pi = pin;
1346  for ( int b=0; b<bps; ++b,pi+=stride ) accs[b] = *pi;
1347  ++pin;
1348  nacc = 8;
1349  }
1350  hard_ss symb = 0;
1351  if ( msb_first )
1352  for ( int b=0; b<bps; ++b ) {
1353  symb = (symb<<1) | (accs[b]>>7);
1354  accs[b] <<= 1;
1355  }
1356  else
1357  for ( int b=bps; b--; ) {
1358  symb = (symb<<1) | (accs[b]>>7);
1359  accs[b] <<= 1;
1360  }
1361  --nacc;
1362  *ps = symb;
1363  }
1364  }
1365  if ( nacc ) fail("Bug: s2_interleaver");
1366  }
1367 #else // reference
1368  static void interleave(int bps, int rows,
1369  const hard_sb *pin, int nslots,
1370  bool msb_first, plslot<hard_ss> *pout)
1371  {
1372  void (*func)(int rows, const hard_sb *pin, int nslots,
1373  plslot<hard_ss> *pout) = 0;
1374  if (msb_first)
1375  switch (bps)
1376  {
1377  case 2:
1378  func = interleave<1, 2>;
1379  break;
1380  case 3:
1381  func = interleave<1, 3>;
1382  break;
1383  case 4:
1384  func = interleave<1, 4>;
1385  break;
1386  case 5:
1387  func = interleave<1, 5>;
1388  break;
1389  default:
1390  fail("Bad bps");
1391  }
1392  else
1393  switch (bps)
1394  {
1395  case 2:
1396  func = interleave<0, 2>;
1397  break;
1398  case 3:
1399  func = interleave<0, 3>;
1400  break;
1401  case 4:
1402  func = interleave<0, 4>;
1403  break;
1404  case 5:
1405  func = interleave<0, 5>;
1406  break;
1407  default:
1408  fail("Bad bps");
1409  }
1410  (*func)(rows, pin, nslots, pout);
1411  }
1412  template <int MSB_FIRST, int BPS>
1413  static void interleave(int rows, const hard_sb *pin, int nslots,
1414  plslot<hard_ss> *pout)
1415  {
1416  if (BPS == 4 && rows == 4050 && MSB_FIRST)
1417  return interleave4050(pin, nslots, pout);
1418  if (rows % 8)
1419  fatal("modcod/framesize combination not supported\n");
1420  int stride = rows / 8; // Offset to next column, in bytes
1421  if (nslots % 4)
1422  fatal("Bug: Truncated byte");
1423  // plslot::symbols[] are not packed across slots,
1424  // so we need tos split bytes at boundaries.
1425  for (; nslots; nslots -= 4)
1426  {
1427  const hard_sb *pi;
1428  hard_sb accs[BPS]; // One accumulator per column
1429  hard_ss *ps;
1430  // Slot 0 (mod 4): 88+2
1431  pout->is_pls = false;
1432  ps = pout->symbols;
1433  for (int i = 0; i < 11; ++i)
1434  {
1435  split_byte<BPS>(pin++, stride, accs);
1436  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 8);
1437  }
1438  split_byte<BPS>(pin++, stride, accs);
1439  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 2);
1440  ++pout;
1441  // Slot 1 (mod 4): 6+80+4
1442  pout->is_pls = false;
1443  ps = pout->symbols;
1444  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 6);
1445  for (int i = 0; i < 10; ++i)
1446  {
1447  split_byte<BPS>(pin++, stride, accs);
1448  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 8);
1449  }
1450  split_byte<BPS>(pin++, stride, accs);
1451  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 4);
1452  ++pout;
1453  // Slot 2 (mod 4): 4+80+6
1454  pout->is_pls = false;
1455  ps = pout->symbols;
1456  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 4);
1457  for (int i = 0; i < 10; ++i)
1458  {
1459  split_byte<BPS>(pin++, stride, accs);
1460  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 8);
1461  }
1462  split_byte<BPS>(pin++, stride, accs);
1463  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 6);
1464  ++pout;
1465  // Slot 3 (mod 4): 2+88
1466  pout->is_pls = false;
1467  ps = pout->symbols;
1468  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 2);
1469  for (int i = 0; i < 11; ++i)
1470  {
1471  split_byte<BPS>(pin++, stride, accs);
1472  pop_symbols<MSB_FIRST, BPS>(accs, &ps, 8);
1473  }
1474  ++pout;
1475  }
1476  }
1477  template <int BPS>
1478  static inline void split_byte(const hard_sb *pi, int stride,
1479  hard_sb accs[BPS])
1480  {
1481  // TBD Pass stride as template parameter.
1482  for (int b = 0; b < BPS; ++b, pi += stride)
1483  accs[b] = *pi;
1484  }
1485  template <int MSB_FIRST, int BPS>
1486  static void pop_symbols(hard_sb accs[BPS], hard_ss **ps, int ns)
1487  {
1488  for (int i = 0; i < ns; ++i)
1489  {
1490  hard_ss symb = 0;
1491  // Check unrolling and constant propagation.
1492  for (int b = 0; b < BPS; ++b)
1493  if (MSB_FIRST)
1494  symb = (symb << 1) | (accs[b] >> 7);
1495  else
1496  symb = (symb << 1) | (accs[BPS - 1 - b] >> 7);
1497  for (int b = 0; b < BPS; ++b)
1498  accs[b] <<= 1;
1499  *(*ps)++ = symb;
1500  }
1501  }
1502 #endif // reference
1503 
1504  // Special case for 16APSK short frames.
1505  // 4050 rows is not a multiple of 8.
1506  static void interleave4050(const hard_sb *pin, int nslots,
1507  plslot<hard_ss> *pout)
1508  {
1509  const hard_sb *pin0 = pin;
1510  int rows = 4050;
1511  hard_sb accs[4]; // One accumulator per column
1512  int nacc = 0; // Bits in each column accumulator
1513  for (; nslots; --nslots, ++pout)
1514  {
1515  pout->is_pls = false;
1516  hard_ss *ps = pout->symbols;
1517  for (int ns = pout->LENGTH; ns--; ++ps)
1518  {
1519  if (!nacc)
1520  {
1521  if (nslots == 1 && ns == 1)
1522  {
1523  // Special case just to avoid reading beyond end of buffer
1524  accs[0] = pin[0];
1525  accs[1] = (pin[506] << 2) | (pin[507] >> 6);
1526  accs[2] = (pin[1012] << 4) | (pin[1013] >> 4);
1527  accs[3] = (pin[1518] << 6);
1528  }
1529  else
1530  {
1531  accs[0] = pin[0];
1532  accs[1] = (pin[506] << 2) | (pin[507] >> 6);
1533  accs[2] = (pin[1012] << 4) | (pin[1013] >> 4);
1534  accs[3] = (pin[1518] << 6) | (pin[1519] >> 2);
1535  }
1536  ++pin;
1537  nacc = 8;
1538  }
1539  hard_ss symb = 0;
1540  for (int b = 0; b < 4; ++b)
1541  {
1542  symb = (symb << 1) | (accs[b] >> 7);
1543  accs[b] <<= 1;
1544  }
1545  --nacc;
1546  *ps = symb;
1547  }
1548  }
1549  }
1550 
1553 }; // s2_interleaver
1554 
1555 // S2 DEINTERLEAVER
1556 // EN 302 307-1 section 5.3.3 Bit Interleaver
1557 
1558 template <typename SOFTSYMB, typename SOFTBYTE>
1560 {
1562  pipebuf<plslot<SOFTSYMB>> &_in,
1563  pipebuf<fecframe<SOFTBYTE>> &_out)
1564  : runnable(sch, "S2 deinterleaver"),
1565  in(_in), out(_out)
1566  {
1567  }
1568  void run()
1569  {
1570  while (in.readable() >= 1 && out.writable() >= 1)
1571  {
1572  plslot<SOFTSYMB> *pin = in.rd();
1573  if (!pin->is_pls)
1574  fail("s2_deinterleaver: bad input sequence");
1575  s2_pls *pls = &pin->pls;
1576  const modcod_info *mcinfo = check_modcod(pls->modcod);
1577  int nslots = pls->sf ? mcinfo->nslots_nf / 4 : mcinfo->nslots_nf;
1578  if (in.readable() < 1 + nslots)
1579  return;
1580  fecframe<SOFTBYTE> *pout = out.wr();
1581  pout->pls = *pls;
1582  SOFTBYTE *pbytes = pout->bytes;
1583  if (mcinfo->nsymbols == 4)
1584  deserialize_qpsk(pin + 1, nslots, pbytes);
1585  else
1586  {
1587  int bps = log2(mcinfo->nsymbols);
1588  int rows = pls->framebits() / bps;
1589  if (mcinfo->nsymbols == 8 && mcinfo->rate == FEC35)
1590  deinterleave(bps, rows, pin + 1, nslots, false, pbytes);
1591  else
1592  deinterleave(bps, rows, pin + 1, nslots, true, pbytes);
1593  }
1594  in.read(1 + nslots);
1595  out.written(1);
1596  }
1597  }
1598 
1599  private:
1600  // Deserialize slots of QPSK symbols, MSB first.
1601  static void deserialize_qpsk(plslot<SOFTSYMB> *pin, int nslots,
1602  SOFTBYTE *pout)
1603  {
1604  SOFTBYTE acc;
1605  softword_clear(&acc); // gcc warning
1606  int nacc = 0;
1607  for (; nslots; --nslots, ++pin)
1608  {
1609  SOFTSYMB *ps = pin->symbols;
1610  for (int ns = pin->LENGTH; ns--; ++ps)
1611  {
1612  pack_qpsk_symbol(*ps, &acc, nacc);
1613  nacc += 2;
1614  if (nacc == 8)
1615  { // TBD unroll
1616  *pout++ = acc;
1617  nacc = 0;
1618  }
1619  }
1620  }
1621  }
1622 
1623  // Deinterleave slots of symbols.
1624  // EN 302 307-1 figures 7 and 8
1625 #if 0 // For reference
1626  static void deinterleave(int bps, int rows,
1627  const plslot<SOFTSYMB> *pin, int nslots,
1628  bool msb_first, SOFTBYTE *pout) {
1629  if ( bps==4 && rows==4050 && msb_first )
1630  return deinterleave4050(pin, nslots, pout);
1631  if ( rows % 8 ) fatal("modcod/framesize combination not supported\n");
1632  int stride = rows/8; // Offset to next column, in bytes
1633  SOFTBYTE accs[bps];
1634  for ( int b=0; b<bps; ++b ) softword_clear(&accs[b]); // gcc warning
1635  int nacc = 0;
1636  for ( ; nslots; --nslots,++pin ) {
1637  const SOFTSYMB *ps = pin->symbols;
1638  for ( int ns=pin->LENGTH; ns--; ++ps ) {
1639  split_symbol(*ps, bps, accs, nacc, msb_first);
1640  ++nacc;
1641  if ( nacc == 8 ) {
1642  SOFTBYTE *po = pout;
1643  for ( int b=0; b<bps; ++b,po+=stride ) *po = accs[b];
1644  ++pout;
1645  nacc = 0;
1646  }
1647  }
1648  }
1649  if ( nacc ) fail("Bug: s2_deinterleaver");
1650  }
1651 #else // reference
1652  static void deinterleave(int bps, int rows,
1653  const plslot<SOFTSYMB> *pin, int nslots,
1654  bool msb_first, SOFTBYTE *pout)
1655  {
1656  void (*func)(int rows, const plslot<SOFTSYMB> *pin, int nslots,
1657  SOFTBYTE *pout) = 0;
1658  if (msb_first)
1659  switch (bps)
1660  {
1661  case 2:
1662  func = deinterleave<1, 2>;
1663  break;
1664  case 3:
1665  func = deinterleave<1, 3>;
1666  break;
1667  case 4:
1668  func = deinterleave<1, 4>;
1669  break;
1670  case 5:
1671  func = deinterleave<1, 5>;
1672  break;
1673  default:
1674  fail("Bad bps");
1675  }
1676  else
1677  switch (bps)
1678  {
1679  case 2:
1680  func = deinterleave<0, 2>;
1681  break;
1682  case 3:
1683  func = deinterleave<0, 3>;
1684  break;
1685  case 4:
1686  func = deinterleave<0, 4>;
1687  break;
1688  case 5:
1689  func = deinterleave<0, 5>;
1690  break;
1691  default:
1692  fail("Bad bps");
1693  }
1694  (*func)(rows, pin, nslots, pout);
1695  }
1696 
1697  template <int MSB_FIRST, int BPS>
1698  static void deinterleave(int rows, const plslot<SOFTSYMB> *pin, int nslots,
1699  SOFTBYTE *pout)
1700  {
1701  if (BPS == 4 && rows == 4050 && MSB_FIRST)
1702  return deinterleave4050(pin, nslots, pout);
1703  if (rows % 8)
1704  fatal("modcod/framesize combination not supported\n");
1705  int stride = rows / 8; // Offset to next column, in bytes
1706  SOFTBYTE accs[BPS];
1707  for (int b = 0; b < BPS; ++b)
1708  softword_clear(&accs[b]); // gcc warning
1709  int nacc = 0;
1710  for (; nslots; --nslots, ++pin)
1711  {
1712  const SOFTSYMB *ps = pin->symbols;
1713  for (int ns = pin->LENGTH; ns--; ++ps)
1714  {
1715  split_symbol(*ps, BPS, accs, nacc, MSB_FIRST);
1716  ++nacc;
1717  if (nacc == 8)
1718  { // TBD Unroll, same as interleave()
1719  SOFTBYTE *po = pout;
1720  // TBD Pass stride as template parameter.
1721  for (int b = 0; b < BPS; ++b, po += stride)
1722  *po = accs[b];
1723  ++pout;
1724  nacc = 0;
1725  }
1726  }
1727  }
1728  if (nacc)
1729  fail("Bug: s2_deinterleaver");
1730  }
1731 #endif // reference
1732 
1733  // Special case for 16APSK short frames.
1734  // 4050 rows is not a multiple of 8
1735  // so we process rows one at a time rather than in chunks of 8.
1736  static void deinterleave4050(const plslot<SOFTSYMB> *pin, int nslots,
1737  SOFTBYTE *pout)
1738  {
1739  const int rows = 4050;
1740  SOFTBYTE accs[4];
1741  for (int b = 0; b < 4; ++b)
1742  softword_clear(&accs[b]); // gcc warning
1743  int nacc = 0;
1744  for (; nslots; --nslots, ++pin)
1745  {
1746  const SOFTSYMB *ps = pin->symbols;
1747  for (int ns = pin->LENGTH; ns--; ++ps)
1748  {
1749  split_symbol(*ps, 4, accs, nacc, true);
1750  ++nacc;
1751  if (nacc == 8)
1752  {
1753  for (int b = 0; b < 8; ++b)
1754  {
1755  softwords_set(pout, rows * 0 + b, softword_get(accs[0], b));
1756  softwords_set(pout, rows * 1 + b, softword_get(accs[1], b));
1757  softwords_set(pout, rows * 2 + b, softword_get(accs[2], b));
1758  softwords_set(pout, rows * 3 + b, softword_get(accs[3], b));
1759  }
1760  ++pout;
1761  nacc = 0;
1762  }
1763  }
1764  }
1765  if (nacc != 2)
1766  fatal("Bug: Expected 2 leftover rows\n");
1767  // Pad with random symbol so that we can use accs[].
1768  for (int b = nacc; b < 8; ++b)
1769  split_symbol(pin->symbols[0], 4, accs, b, true);
1770  for (int b = 0; b < nacc; ++b)
1771  {
1772  softwords_set(pout, rows * 0 + b, softword_get(accs[0], b));
1773  softwords_set(pout, rows * 1 + b, softword_get(accs[1], b));
1774  softwords_set(pout, rows * 2 + b, softword_get(accs[2], b));
1775  softwords_set(pout, rows * 3 + b, softword_get(accs[3], b));
1776  }
1777  }
1778 
1779  // Spread LLR symbol across hard columns.
1780  // Must call 8 times before using result because we use bit shifts.
1781  static inline void split_symbol(const llr_ss &ps, int bps,
1782  hard_sb accs[/*bps*/], int nacc,
1783  bool msb_first)
1784  {
1785  if (msb_first)
1786  {
1787  for (int b = 0; b < bps; ++b)
1788  accs[b] = (accs[b] << 1) | llr_harden(ps.bits[bps - 1 - b]);
1789  }
1790  else
1791  {
1792  for (int b = 0; b < bps; ++b)
1793  accs[b] = (accs[b] << 1) | llr_harden(ps.bits[b]);
1794  }
1795  }
1796  // Fast variant
1797  template <int MSB_FIRST, int BPS>
1798  static inline void split_symbol(const llr_ss &ps,
1799  hard_sb accs[/*bps*/], int nacc)
1800  {
1801  if (MSB_FIRST)
1802  {
1803  for (int b = 0; b < BPS; ++b)
1804  accs[b] = (accs[b] << 1) | llr_harden(ps.bits[BPS - 1 - b]);
1805  }
1806  else
1807  {
1808  for (int b = 0; b < BPS; ++b)
1809  accs[b] = (accs[b] << 1) | llr_harden(ps.bits[b]);
1810  }
1811  }
1812 
1813  // Spread LLR symbol across LLR columns.
1814  static inline void split_symbol(const llr_ss &ps, int bps,
1815  llr_sb accs[/*bps*/], int nacc,
1816  bool msb_first)
1817  {
1818  if (msb_first)
1819  {
1820  for (int b = 0; b < bps; ++b)
1821  accs[b].bits[nacc] = ps.bits[bps - 1 - b];
1822  }
1823  else
1824  {
1825  for (int b = 0; b < bps; ++b)
1826  accs[b].bits[nacc] = ps.bits[b];
1827  }
1828  }
1829  // Fast variant
1830  template <int MSB_FIRST, int BPS>
1831  static inline void split_symbol(const llr_ss &ps,
1832  llr_sb accs[/*bps*/], int nacc)
1833  {
1834  if (MSB_FIRST)
1835  {
1836  for (int b = 0; b < BPS; ++b)
1837  accs[b].bits[nacc] = ps.bits[BPS - 1 - b];
1838  }
1839  else
1840  {
1841  for (int b = 0; b < BPS; ++b)
1842  accs[b].bits[nacc] = ps.bits[b];
1843  }
1844  }
1845 
1846  // Merge QPSK LLR symbol into hard byte.
1847  static inline void pack_qpsk_symbol(const llr_ss &ps,
1848  hard_sb *acc, int nacc)
1849  {
1850  // TBD Must match LLR law, see softsymb_harden.
1851  uint8_t s = llr_harden(ps.bits[0]) | (llr_harden(ps.bits[1]) << 1);
1852  *acc = (*acc << 2) | s;
1853  }
1854 
1855  // Merge QPSK LLR symbol into LLR byte.
1856  static inline void pack_qpsk_symbol(const llr_ss &ps,
1857  llr_sb *acc, int nacc)
1858  {
1859  acc->bits[nacc] = ps.bits[1];
1860  acc->bits[nacc + 1] = ps.bits[0];
1861  }
1862 
1865 }; // s2_deinterleaver
1866 
1869 
1870 #include "dvbs2_data.h"
1871 
1872 static const struct fec_info
1873 {
1874  static const int KBCH_MAX = 58192;
1875  int Kbch; // BCH message size (bits)
1876  int kldpc; // LDPC message size (= BCH codeword size) (bits)
1877  int t; // BCH error correction
1878  const s2_ldpc_table *ldpc;
1879 } fec_infos[2][FEC_COUNT] = {
1880  {
1881  // Normal frames - must respect enum code_rate order
1882  {32208, 32400, 12, &ldpc_nf_fec12}, // FEC12 (was [FEC12] = {...} and so on. Does not compile with MSVC)
1883  {43040, 43200, 10, &ldpc_nf_fec23}, // FEC23
1884  {0}, // FEC46
1885  {48408, 48600, 12, &ldpc_nf_fec34}, // FEC34
1886  {53840, 54000, 10, &ldpc_nf_fec56}, // FEC56
1887  {0}, // FEC78
1888  {51648, 51840, 12, &ldpc_nf_fec45}, // FEC45
1889  {57472, 57600, 8, &ldpc_nf_fec89}, // FEC89
1890  {58192, 58320, 8, &ldpc_nf_fec910}, // FEC910
1891  {16008, 16200, 12, &ldpc_nf_fec14}, // FEC14
1892  {21408, 21600, 12, &ldpc_nf_fec13}, // FEC13
1893  {25728, 25920, 12, &ldpc_nf_fec25}, // FEC25
1894  {38688, 38880, 12, &ldpc_nf_fec35}, // FEC35
1895  },
1896  {
1897  // Short frames - must respect enum code_rate order
1898  {7032, 7200, 12, &ldpc_sf_fec12}, // FEC12 (was [FEC12] = {...} and so on. Does not compile with MSVC)
1899  {10632, 10800, 12, &ldpc_sf_fec23}, // FEC23
1900  {}, // FEC46
1901  {11712, 11880, 12, &ldpc_sf_fec34}, // FEC34
1902  {13152, 13320, 12, &ldpc_sf_fec56}, // FEC56
1903  {}, // FEC78
1904  {12432, 12600, 12, &ldpc_sf_fec45}, // FEC45
1905  {14232, 14400, 12, &ldpc_sf_fec89}, // FEC89
1906  {}, // FEC910
1907  {3072, 3240, 12, &ldpc_sf_fec14}, // FEC14
1908  {5232, 5400, 12, &ldpc_sf_fec13}, // FEC13
1909  {6312, 6480, 12, &ldpc_sf_fec25}, // FEC25
1910  {9552, 9720, 12, &ldpc_sf_fec35}, // FEC35
1911  },
1912 };
1913 
1914 struct bbframe
1915 {
1917  uint8_t bytes[58192 / 8]; // Kbch/8 max
1918 };
1919 
1920 // S2_LDPC_ENGINES
1921 // Initializes LDPC engines for all DVB-S2 FEC settings.
1922 
1923 template <typename SOFTBIT, typename SOFTBYTE>
1925 {
1927  s2_ldpc_engine *ldpcs[2][FEC_COUNT]; // [shortframes][fec]
1929  {
1930  memset(ldpcs, 0, sizeof(ldpcs));
1931  for (int sf = 0; sf <= 1; ++sf)
1932  {
1933  for (int fec = 0; fec < FEC_COUNT; ++fec)
1934  {
1935  const fec_info *fi = &fec_infos[sf][fec];
1936  if (!fi->ldpc)
1937  {
1938  ldpcs[sf][fec] = NULL;
1939  }
1940  else
1941  {
1942  int n = (sf ? 64800 / 4 : 64800);
1943  int k = fi->kldpc;
1944  ldpcs[sf][fec] = new s2_ldpc_engine(fi->ldpc, k, n);
1945  }
1946  }
1947  }
1948  }
1950  {
1951  for (int sf = 0; sf <= 1; ++sf)
1952  for (int fec = 0; fec < FEC_COUNT; ++fec)
1953  {
1954  s2_ldpc_engine *ldpc = ldpcs[sf][fec];
1955  if (ldpc)
1956  ldpc->print_node_stats();
1957  }
1958  }
1959 }; // s2_ldpc_engines
1960 
1961 // S2_BCH_ENGINES
1962 // Initializes BCH engines for all DVB-S2 FEC settings.
1963 
1965 {
1967  // N=t*m
1968  // The generator of GF(2^m) is always g1.
1969  // Normal frames with 8, 10 or 12 polynomials.
1973  // Short frames with 12 polynomials.
1976  {
1977  bitvect<uint32_t, 17> bch_polys[2][12]; // [shortframes][polyindex]
1978  // EN 302 307-1 5.3.1 Table 6a (polynomials for normal frames)
1979  bch_polys[0][0] = bitvect<uint32_t, 17>(0x1002d); // g1
1980  bch_polys[0][1] = bitvect<uint32_t, 17>(0x10173); // g2
1981  bch_polys[0][2] = bitvect<uint32_t, 17>(0x10fbd); // g3
1982  bch_polys[0][3] = bitvect<uint32_t, 17>(0x15a55); // g4
1983  bch_polys[0][4] = bitvect<uint32_t, 17>(0x11f2f); // g5
1984  bch_polys[0][5] = bitvect<uint32_t, 17>(0x1f7b5); // g6
1985  bch_polys[0][6] = bitvect<uint32_t, 17>(0x1af65); // g7
1986  bch_polys[0][7] = bitvect<uint32_t, 17>(0x17367); // g8
1987  bch_polys[0][8] = bitvect<uint32_t, 17>(0x10ea1); // g9
1988  bch_polys[0][9] = bitvect<uint32_t, 17>(0x175a7); // g10
1989  bch_polys[0][10] = bitvect<uint32_t, 17>(0x13a2d); // g11
1990  bch_polys[0][11] = bitvect<uint32_t, 17>(0x11ae3); // g12
1991  // EN 302 307-1 5.3.1 Table 6b (polynomials for short frames)
1992  bch_polys[1][0] = bitvect<uint32_t, 17>(0x402b); // g1
1993  bch_polys[1][1] = bitvect<uint32_t, 17>(0x4941); // g2
1994  bch_polys[1][2] = bitvect<uint32_t, 17>(0x4647); // g3
1995  bch_polys[1][3] = bitvect<uint32_t, 17>(0x5591); // g4
1996  bch_polys[1][4] = bitvect<uint32_t, 17>(0x6b55); // g5
1997  bch_polys[1][5] = bitvect<uint32_t, 17>(0x6389); // g6
1998  bch_polys[1][6] = bitvect<uint32_t, 17>(0x6ce5); // g7
1999  bch_polys[1][7] = bitvect<uint32_t, 17>(0x4f21); // g8
2000  bch_polys[1][8] = bitvect<uint32_t, 17>(0x460f); // g9
2001  bch_polys[1][9] = bitvect<uint32_t, 17>(0x5a49); // g10
2002  bch_polys[1][10] = bitvect<uint32_t, 17>(0x5811); // g11
2003  bch_polys[1][11] = bitvect<uint32_t, 17>(0x65ef); // g12
2004  // Redundant with fec_infos[], but needs static template argument.
2005  memset(bchs, 0, sizeof(bchs));
2006  bchs[0][FEC12] = new s2_bch_engine_nf12(bch_polys[0], 12);
2007  bchs[0][FEC23] = new s2_bch_engine_nf10(bch_polys[0], 10);
2008  bchs[0][FEC34] = new s2_bch_engine_nf12(bch_polys[0], 12);
2009  bchs[0][FEC56] = new s2_bch_engine_nf10(bch_polys[0], 10);
2010  bchs[0][FEC45] = new s2_bch_engine_nf12(bch_polys[0], 12);
2011  bchs[0][FEC89] = new s2_bch_engine_nf8(bch_polys[0], 8);
2012  bchs[0][FEC910] = new s2_bch_engine_nf8(bch_polys[0], 8);
2013  bchs[0][FEC14] = new s2_bch_engine_nf12(bch_polys[0], 12);
2014  bchs[0][FEC13] = new s2_bch_engine_nf12(bch_polys[0], 12);
2015  bchs[0][FEC25] = new s2_bch_engine_nf12(bch_polys[0], 12);
2016  bchs[0][FEC35] = new s2_bch_engine_nf12(bch_polys[0], 12);
2017  bchs[1][FEC12] = new s2_bch_engine_sf12(bch_polys[1], 12);
2018  bchs[1][FEC23] = new s2_bch_engine_sf12(bch_polys[1], 12);
2019  bchs[1][FEC34] = new s2_bch_engine_sf12(bch_polys[1], 12);
2020  bchs[1][FEC56] = new s2_bch_engine_sf12(bch_polys[1], 12);
2021  bchs[1][FEC45] = new s2_bch_engine_sf12(bch_polys[1], 12);
2022  bchs[1][FEC89] = new s2_bch_engine_sf12(bch_polys[1], 12);
2023  bchs[1][FEC14] = new s2_bch_engine_sf12(bch_polys[1], 12);
2024  bchs[1][FEC13] = new s2_bch_engine_sf12(bch_polys[1], 12);
2025  bchs[1][FEC25] = new s2_bch_engine_sf12(bch_polys[1], 12);
2026  bchs[1][FEC35] = new s2_bch_engine_sf12(bch_polys[1], 12);
2027  }
2028 }; // s2_bch_engines
2029 
2030 // S2 BASEBAND DESCRAMBLER AND FEC ENCODER
2031 // EN 302 307-1 section 5.2.2
2032 // EN 302 307-1 section 5.3
2033 
2035 {
2039  : runnable(sch, "S2 fecenc"),
2040  in(_in), out(_out)
2041  {
2042  if (sch->debug)
2043  s2ldpc.print_node_stats();
2044  }
2045  void run()
2046  {
2047  while (in.readable() >= 1 && out.writable() >= 1)
2048  {
2049  bbframe *pin = in.rd();
2050  fecframe<hard_sb> *pout = out.wr();
2051  run_frame(in.rd(), out.wr());
2052  in.read(1);
2053  out.written(1);
2054  }
2055  }
2056 
2057  private:
2058  void run_frame(const bbframe *pin, fecframe<hard_sb> *pout)
2059  {
2060  const modcod_info *mcinfo = check_modcod(pin->pls.modcod);
2061  const fec_info *fi = &fec_infos[pin->pls.sf][mcinfo->rate];
2062  pout->pls = pin->pls;
2063  hard_sb *pbytes = pout->bytes;
2064  bbscrambling.transform(pin->bytes, fi->Kbch / 8, pbytes);
2065  { // BCH
2066  size_t msgbytes = fi->Kbch / 8;
2067  size_t cwbytes = fi->kldpc / 8;
2068  bch_interface *bch = s2bch.bchs[pin->pls.sf][mcinfo->rate];
2069  bch->encode(pbytes, msgbytes, pbytes + msgbytes);
2070  }
2071  { // LDPC
2072  size_t msgbits = fi->kldpc;
2073  size_t cwbits = pin->pls.framebits();
2074  s2_ldpc_engine *ldpc = s2ldpc.ldpcs[pin->pls.sf][mcinfo->rate];
2075  ldpc->encode(fi->ldpc, pbytes, msgbits, cwbits, pbytes + msgbits / 8);
2076  }
2077  }
2083 }; // s2_fecenc
2084 
2085 // S2 FEC DECODER AND BASEBAND DESCRAMBLER
2086 // EN 302 307-1 section 5.3
2087 // EN 302 307-1 section 5.2.2
2088 
2089 template <typename SOFTBIT, typename SOFTBYTE>
2091 {
2095  pipebuf<int> *_bitcount = NULL,
2096  pipebuf<int> *_errcount = NULL)
2097  : runnable(sch, "S2 fecdec"),
2098  bitflips(0),
2099  in(_in), out(_out),
2100  bitcount(opt_writer(_bitcount, 1)),
2101  errcount(opt_writer(_errcount, 1))
2102  {
2103  if (sch->debug)
2104  s2ldpc.print_node_stats();
2105  }
2106  void run()
2107  {
2108  while (in.readable() >= 1 && out.writable() >= 1 &&
2109  opt_writable(bitcount, 1) && opt_writable(errcount, 1))
2110  {
2111  fecframe<SOFTBYTE> *pin = in.rd();
2112  const modcod_info *mcinfo = check_modcod(pin->pls.modcod);
2113  const fec_info *fi = &fec_infos[pin->pls.sf][mcinfo->rate];
2114  bool corrupted = false;
2115  bool residual_errors;
2116  if (true)
2117  {
2118  // LDPC decode
2119  size_t cwbits = pin->pls.framebits();
2120  size_t msgbits = fi->kldpc;
2121  size_t chkbits = cwbits - msgbits;
2122  s2_ldpc_engine *ldpc = s2ldpc.ldpcs[pin->pls.sf][mcinfo->rate];
2123  int ncorr = ldpc->decode_bitflip(fi->ldpc, pin->bytes, msgbits, cwbits, bitflips);
2124  if (sch->debug2)
2125  fprintf(stderr, "LDPCCORR = %d\n", ncorr);
2126  }
2127  uint8_t *hardbytes = softbytes_harden(pin->bytes, fi->kldpc / 8, bch_buf);
2128  if (true)
2129  {
2130  // BCH decode
2131  size_t cwbytes = fi->kldpc / 8;
2132  size_t msgbytes = fi->Kbch / 8;
2133  size_t chkbytes = cwbytes - msgbytes;
2134  // Decode with suitable BCH decoder for this MODCOD
2135  bch_interface *bch = s2bch.bchs[pin->pls.sf][mcinfo->rate];
2136  int ncorr = bch->decode(hardbytes, cwbytes);
2137  if (sch->debug2)
2138  fprintf(stderr, "BCHCORR = %d\n", ncorr);
2139  corrupted = (ncorr < 0);
2140  residual_errors = (ncorr != 0);
2141  // Report VER
2142  opt_write(bitcount, fi->Kbch);
2143  opt_write(errcount, (ncorr >= 0) ? ncorr : fi->Kbch);
2144  }
2145  int bbsize = fi->Kbch / 8;
2146  // TBD Some decoders want the bad packets.
2147 #if 0
2148  if ( corrupted ) {
2149  fprintf(stderr, "Passing bad frame\n");
2150  corrupted = false;
2151  }
2152 #endif
2153  if (!corrupted)
2154  {
2155  // Descramble and output
2156  bbframe *pout = out.wr();
2157  pout->pls = pin->pls;
2158  bbscrambling.transform(hardbytes, bbsize, pout->bytes);
2159  out.written(1);
2160  }
2161  if (sch->debug)
2162  fprintf(stderr, "%c", corrupted ? ':' : residual_errors ? '.' : '_');
2163  in.read(1);
2164  }
2165  }
2166 
2167  private:
2169  uint8_t bch_buf[64800 / 8]; // Temp storage for hardening before BCH
2175 }; // s2_fecdec
2176 
2177 // External LDPC decoder
2178 // Spawns a user-specified command, FEC frames on stdin/stdout.
2179 
2180 template <typename T, int _SIZE>
2182 {
2183  static const int SIZE = _SIZE;
2184  simplequeue() { rd = wr = count = 0; }
2185  bool full() { return count == SIZE; }
2186  T *put()
2187  {
2188  T *res = &q[wr];
2189  wr = (wr + 1) % SIZE;
2190  ++count;
2191  return res;
2192  }
2193  bool empty() { return count == 0; }
2194  const T *peek() { return &q[rd]; }
2195  const T *get()
2196  {
2197  const T *res = &q[rd];
2198  rd = (rd + 1) % SIZE;
2199  --count;
2200  return res;
2201  }
2202  // private:
2203  int rd, wr, count;
2204  T q[SIZE];
2205 };
2206 
2207 template <typename SOFTBIT, typename SOFTBYTE>
2209 {
2215  pipebuf<bbframe> &_out,
2216  const char *_command,
2217  pipebuf<int> *_bitcount = NULL,
2218  pipebuf<int> *_errcount = NULL)
2219  : runnable(sch, "S2 fecdec io"),
2220  batch_size(32),
2221  nhelpers(1),
2222  must_buffer(false),
2223  in(_in), out(_out),
2224  command(_command),
2225  bitcount(opt_writer(_bitcount, 1)),
2226  errcount(opt_writer(_errcount, 1))
2227  {
2228  for (int mc = 0; mc < 32; ++mc)
2229  for (int sf = 0; sf < 2; ++sf)
2230  pools[mc][sf].procs = NULL;
2231  }
2232  void run()
2233  {
2234  bool work_done = false;
2235  // Send work until all helpers block.
2236  bool all_blocked = false;
2237  while (in.readable() >= 1 && !jobs.full())
2238  {
2239  if (!send_frame(in.rd()))
2240  {
2241  all_blocked = true;
2242  break;
2243  }
2244  in.read(1);
2245  work_done = true;
2246  }
2247  // Risk blocking on read() only when we have nothing else to do
2248  // and we know a result is coming.
2249  while ((all_blocked || !work_done || jobs.full()) &&
2250  !jobs.empty() &&
2251  jobs.peek()->h->b_out &&
2252  out.writable() >= 1 &&
2253  opt_writable(bitcount, 1) && opt_writable(errcount, 1))
2254  {
2255  receive_frame(jobs.get());
2256  }
2257  }
2258 
2259  private:
2261  {
2262  int fd_tx; // To helper
2263  int fd_rx; // From helper
2264  int batch_size; // Latency
2265  int b_in; // Jobs in input queue
2266  int b_out; // Jobs in output queue
2267  };
2268  struct pool
2269  {
2270  helper_instance *procs; // NULL or [nprocs]
2271  int nprocs;
2272  } pools[32][2]; // [modcod][sf]
2273  struct helper_job
2274  {
2277  };
2279  // Try to send a frame. Return false if helper was busy.
2281  {
2282  pool *p = get_pool(&pin->pls);
2283  for (int i = 0; i < p->nprocs; ++i)
2284  {
2285  helper_instance *h = &p->procs[i];
2286  size_t iosize = (pin->pls.framebits() / 8) * sizeof(SOFTBYTE);
2287  // fprintf(stderr, "Writing %lu to fd %d\n", iosize, h->fd_tx);
2288  int nw = write(h->fd_tx, pin->bytes, iosize);
2289  if (nw < 0 && errno == EWOULDBLOCK)
2290  continue;
2291  if (nw < 0)
2292  fatal("write(LDPC helper");
2293  if (nw != iosize)
2294  fatal("partial write(LDPC helper)");
2295  helper_job *job = jobs.put();
2296  job->pls = pin->pls;
2297  job->h = h;
2298  ++h->b_in;
2299  if (h->b_in >= h->batch_size)
2300  {
2301  h->b_in -= h->batch_size;
2302  h->b_out += h->batch_size;
2303  }
2304  return true;
2305  }
2306  return false;
2307  }
2308  // Return a pool of running helpers for a given modcod.
2309  pool *get_pool(const s2_pls *pls)
2310  {
2311  pool *p = &pools[pls->modcod][pls->sf];
2312  if (!p->procs)
2313  {
2314  p->procs = new helper_instance[nhelpers];
2315  for (int i = 0; i < nhelpers; ++i)
2316  spawn_helper(&p->procs[i], pls);
2317  p->nprocs = nhelpers;
2318  }
2319  return p;
2320  }
2321  // Spawn a helper process.
2322  void spawn_helper(helper_instance *h, const s2_pls *pls)
2323  {
2324  if (sch->debug)
2325  fprintf(stderr, "Spawning LDPC helper: modcod=%d sf=%d\n",
2326  pls->modcod, pls->sf);
2327  int tx[2], rx[2];
2328  if (pipe(tx) || pipe(rx))
2329  fatal("pipe");
2330  // Size the pipes so that the helper never runs out of work to do.
2331  int pipesize = 64800 * batch_size;
2332  if (fcntl(tx[0], F_SETPIPE_SZ, pipesize) < 0 ||
2333  fcntl(rx[0], F_SETPIPE_SZ, pipesize) < 0 ||
2334  fcntl(tx[1], F_SETPIPE_SZ, pipesize) < 0 ||
2335  fcntl(rx[1], F_SETPIPE_SZ, pipesize) < 0)
2336  {
2337  fprintf(stderr,
2338  "*** Failed to increase pipe size.\n"
2339  "*** Try echo %d > /proc/sys/fs/pipe-max-size\n",
2340  pipesize);
2341  if (must_buffer)
2342  fatal("F_SETPIPE_SZ");
2343  else
2344  fprintf(stderr, "*** Throughput will be suboptimal.\n");
2345  }
2346  int child = vfork();
2347  if (!child)
2348  {
2349  // Child process
2350  close(tx[1]);
2351  dup2(tx[0], 0);
2352  close(rx[0]);
2353  dup2(rx[1], 1);
2354  char mc_arg[16];
2355  sprintf(mc_arg, "%d", pls->modcod);
2356  const char *sf_arg = pls->sf ? "--shortframes" : NULL;
2357  const char *argv[] = {command, "--modcod", mc_arg, sf_arg, NULL};
2358  execve(command, (char *const *)argv, NULL);
2359  fatal(command);
2360  }
2361  h->fd_tx = tx[1];
2362  close(tx[0]);
2363  h->fd_rx = rx[0];
2364  close(rx[1]);
2365  h->batch_size = 32; // TBD
2366  h->b_in = h->b_out = 0;
2367  int flags = fcntl(h->fd_tx, F_GETFL);
2368  if (fcntl(h->fd_tx, F_SETFL, flags | O_NONBLOCK))
2369  fatal("fcntl(helper)");
2370  }
2371 
2372  // Receive a finished job.
2373  void receive_frame(const helper_job *job)
2374  {
2375  // Read corrected frame from helper
2376  const s2_pls *pls = &job->pls;
2377  size_t iosize = (pls->framebits() / 8) * sizeof(ldpc_buf[0]);
2378  int nr = read(job->h->fd_rx, ldpc_buf, iosize);
2379  if (nr < 0)
2380  fatal("read(LDPC helper)");
2381  if (nr != iosize)
2382  fatal("partial read(LDPC helper)");
2383  --job->h->b_out;
2384  // Decode BCH.
2385  const modcod_info *mcinfo = check_modcod(job->pls.modcod);
2386  const fec_info *fi = &fec_infos[job->pls.sf][mcinfo->rate];
2387  uint8_t *hardbytes = softbytes_harden(ldpc_buf, fi->kldpc / 8, bch_buf);
2388  size_t cwbytes = fi->kldpc / 8;
2389  size_t msgbytes = fi->Kbch / 8;
2390  size_t chkbytes = cwbytes - msgbytes;
2391  bch_interface *bch = s2bch.bchs[job->pls.sf][mcinfo->rate];
2392  int ncorr = bch->decode(hardbytes, cwbytes);
2393  if (sch->debug2)
2394  fprintf(stderr, "BCHCORR = %d\n", ncorr);
2395  bool corrupted = (ncorr < 0);
2396  // Report VBER
2397  opt_write(bitcount, fi->Kbch);
2398  opt_write(errcount, (ncorr >= 0) ? ncorr : fi->Kbch);
2399 #if 0
2400  // TBD Some decoders want the bad packets.
2401  if ( corrupted ) {
2402  fprintf(stderr, "Passing bad frame\n");
2403  corrupted = false;
2404  }
2405 #endif
2406  if (!corrupted)
2407  {
2408  // Descramble and output
2409  bbframe *pout = out.wr();
2410  pout->pls = job->pls;
2411  bbscrambling.transform(hardbytes, fi->Kbch / 8, pout->bytes);
2412  out.written(1);
2413  }
2414  if (sch->debug)
2415  fprintf(stderr, "%c", corrupted ? '!' : ncorr ? '.' : '_');
2416  }
2419  const char *command;
2420  SOFTBYTE ldpc_buf[64800 / 8];
2421  uint8_t bch_buf[64800 / 8]; // Temp storage for hardening before BCH
2425 }; // s2_fecdec_helper
2426 
2427 // S2 FRAMER
2428 // EN 302 307-1 section 5.1 Mode adaptation
2429 
2431 {
2432  uint8_t rolloff_code; // 0=0.35, 1=0.25, 2=0.20, 3=reserved
2435  : runnable(sch, "S2 framer"),
2436  in(_in), out(_out)
2437  {
2438  pls.modcod = 4;
2439  pls.sf = false;
2440  pls.pilots = true;
2441  nremain = 0;
2442  remcrc = 0; // CRC for nonexistent previous packet
2443  }
2444  void run()
2445  {
2446  while (out.writable() >= 1)
2447  {
2448  const modcod_info *mcinfo = check_modcod(pls.modcod);
2449  const fec_info *fi = &fec_infos[pls.sf][mcinfo->rate];
2450  int framebytes = fi->Kbch / 8;
2451  if (!framebytes)
2452  fail("MODCOD/framesize combination not allowed");
2453  if (10 + nremain + 188 * in.readable() < framebytes)
2454  break; // Not enough data to fill a frame
2455  bbframe *pout = out.wr();
2456  pout->pls = pls;
2457  uint8_t *buf = pout->bytes;
2458  uint8_t *end = buf + framebytes;
2459  // EN 302 307-1 section 5.1.6 Base-Band Header insertion
2460  uint8_t *bbheader = buf;
2461  *buf++ = 0x30 | rolloff_code; // MATYPE-1: SIS, CCM
2462  *buf++ = 0; // MATYPE-2
2463  uint16_t upl = 188 * 8;
2464  *buf++ = upl >> 8; // UPL MSB
2465  *buf++ = upl; // UPL LSB
2466  uint16_t dfl = (framebytes - 10) * 8;
2467  *buf++ = dfl >> 8; // DFL MSB
2468  *buf++ = dfl; // DFL LSB
2469  *buf++ = 0x47; // SYNC
2470  uint16_t syncd = nremain * 8;
2471  *buf++ = syncd >> 8; // SYNCD MSB
2472  *buf++ = syncd; // SYNCD LSB
2473  *buf++ = crc8.compute(bbheader, 9);
2474  // Data field
2475  memcpy(buf, rembuf, nremain); // Leftover from previous runs
2476  buf += nremain;
2477  while (buf < end)
2478  {
2479  tspacket *tsp = in.rd();
2480  if (tsp->data[0] != MPEG_SYNC)
2481  fail("Invalid TS");
2482  *buf++ = remcrc; // Replace SYNC with CRC of previous.
2483  remcrc = crc8.compute(tsp->data + 1, tspacket::SIZE - 1);
2484  int nused = end - buf;
2485  if (nused > tspacket::SIZE - 1)
2486  nused = tspacket::SIZE - 1;
2487  memcpy(buf, tsp->data + 1, nused);
2488  buf += nused;
2489  if (buf == end)
2490  {
2491  nremain = (tspacket::SIZE - 1) - nused;
2492  memcpy(rembuf, tsp->data + 1 + nused, nremain);
2493  }
2494  in.read(1);
2495  }
2496  if (buf != end)
2497  fail("Bug: s2_framer");
2498  out.written(1);
2499  }
2500  }
2501 
2502  private:
2506  int nremain;
2509 }; // s2_framer
2510 
2511 // S2 DEFRAMER
2512 // EN 302 307-1 section 5.1 Mode adaptation
2513 
2515 {
2517  pipebuf<int> *_state_out = NULL,
2518  pipebuf<unsigned long> *_locktime_out = NULL)
2519  : runnable(sch, "S2 deframer"),
2520  missing(-1),
2521  in(_in), out(_out, MAX_TS_PER_BBFRAME),
2522  current_state(false),
2523  state_out(opt_writer(_state_out, 2)),
2524  report_state(true),
2525  locktime(0),
2526  locktime_out(opt_writer(_locktime_out, MAX_TS_PER_BBFRAME))
2527  {
2528  }
2529  void run()
2530  {
2531  while (in.readable() >= 1 && out.writable() >= MAX_TS_PER_BBFRAME &&
2532  opt_writable(state_out, 2) &&
2533  opt_writable(locktime_out, MAX_TS_PER_BBFRAME))
2534  {
2535  if (report_state)
2536  {
2537  // Report unlocked state on first invocation.
2538  opt_write(state_out, 0);
2539  report_state = false;
2540  }
2541  run_bbframe(in.rd());
2542  in.read(1);
2543  }
2544  }
2545 
2546  private:
2548  {
2549  uint8_t *bbh = pin->bytes;
2550  uint16_t upl = (bbh[2] << 8) | bbh[3];
2551  uint16_t dfl = (bbh[4] << 8) | bbh[5];
2552  uint8_t sync = bbh[6];
2553  uint16_t syncd = (bbh[7] << 8) | bbh[8];
2554  uint8_t crcexp = crc8.compute(bbh, 9);
2555  uint8_t crc = bbh[9];
2556  uint8_t *data = bbh + 10;
2557  int ro_code = bbh[0] & 3;
2558  if (sch->debug2)
2559  {
2560  static float ro_values[] = {0.35, 0.25, 0.20, 0};
2561  fprintf(stderr, "BBH: crc %02x/%02x %s ma=%02x%02x ro=%.2f"
2562  " upl=%d dfl=%d sync=%02x syncd=%d\n",
2563  crc, crcexp, (crc == crcexp) ? "OK" : "KO",
2564  bbh[0], bbh[1], ro_values[ro_code], upl, dfl, sync, syncd);
2565  }
2566  if (crc != crcexp || upl != 188 * 8 || sync != 0x47 || dfl > fec_info::KBCH_MAX ||
2567  syncd > dfl || (dfl & 7) || (syncd & 7))
2568  {
2569  // Note: Maybe accept syncd=65535
2570  fprintf(stderr, "Bad bbframe\n");
2571  missing = -1;
2572  info_unlocked();
2573  return;
2574  }
2575  // TBD Handle packets as payload+finalCRC and do crc8 before pout
2576  int pos; // Start of useful data in this bbframe
2577  if (missing < 0)
2578  {
2579  // Skip unusable data at beginning of bbframe
2580  pos = syncd / 8;
2581  fprintf(stderr, "Start TS at %d\n", pos);
2582  missing = 0;
2583  }
2584  else
2585  {
2586  // Sanity check
2587  if (syncd / 8 != missing)
2588  {
2589  fprintf(stderr, "Lost a bbframe ?\n");
2590  missing = -1;
2591  info_unlocked();
2592  return;
2593  }
2594  pos = 0;
2595  }
2596  if (missing)
2597  {
2598  // Complete and output the partial TS packet in leftover[].
2599  tspacket *pout = out.wr();
2600  memcpy(pout->data, leftover, 188 - missing);
2601  memcpy(pout->data + (188 - missing), data + pos, missing);
2602  out.written(1);
2603  info_good_packet();
2604  ++pout;
2605  // Skip to beginning of next TS packet
2606  pos += missing;
2607  missing = 0;
2608  }
2609  while (pos + 188 <= dfl / 8)
2610  {
2611  tspacket *pout = out.wr();
2612  memcpy(pout->data, data + pos, 188);
2613  pout->data[0] = sync; // Replace CRC
2614  out.written(1);
2615  info_good_packet();
2616  pos += 188;
2617  }
2618  int remain = dfl / 8 - pos;
2619  if (remain)
2620  {
2621  memcpy(leftover, data + pos, remain);
2622  leftover[0] = sync; // Replace CRC
2623  missing = 188 - remain;
2624  }
2625  }
2626 
2628  {
2629  info_is_locked(false);
2630  locktime = 0;
2631  }
2633  {
2634  info_is_locked(true);
2635  ++locktime;
2636  opt_write(locktime_out, locktime);
2637  }
2638  void info_is_locked(bool newstate)
2639  {
2640  if (newstate != current_state)
2641  {
2642  opt_write(state_out, newstate ? 1 : 0);
2643  current_state = newstate;
2644  }
2645  }
2646 
2648  int missing; // Bytes needed to complete leftover[],
2649  // or 0 if no leftover data,
2650  // or -1 if not synced.
2651  uint8_t leftover[188];
2652  static const int MAX_TS_PER_BBFRAME = fec_info::KBCH_MAX / 8 / 188 + 1;
2653  bool locked;
2659  unsigned long locktime;
2661 }; // s2_deframer
2662 
2663 } // namespace leansdr
2664 
2665 #endif // LEANSDR_DVBS2_H
void spawn_helper(helper_instance *h, const s2_pls *pls)
Definition: dvbs2.h:2322
bch_engine< uint32_t, 192, 17, 16, uint16_t, 0x002d > s2_bch_engine_nf12
Definition: dvbs2.h:1970
complex< float > p
Definition: dvbs2.h:1134
static void split_byte(const hard_sb *pi, int stride, hard_sb accs[BPS])
Definition: dvbs2.h:1478
virtual int decode(uint8_t *cw, size_t cwbytes)=0
s2_framer(scheduler *sch, pipebuf< tspacket > &_in, pipebuf< bbframe > &_out)
Definition: dvbs2.h:2434
complex< T > * csymbols
Definition: dvbs2.h:399
unsigned long locktime
Definition: dvbs2.h:2659
bool llr_harden(llr_t v)
Definition: sdr.h:446
s2_fecenc(scheduler *sch, pipebuf< bbframe > &_in, pipebuf< fecframe< hard_sb >> &_out)
Definition: dvbs2.h:2037
uint8_t bytes[58192/8]
Definition: dvbs2.h:1917
uint8_t * softbytes_harden(hard_sb p[], int nbytes, uint8_t storage[])
Definition: softword.h:67
s2_bbscrambling bbscrambling
Definition: dvbs2.h:2423
static const char * names[]
Definition: sdr.h:476
bool send_frame(fecframe< SOFTBYTE > *pin)
Definition: dvbs2.h:2280
const T * peek()
Definition: dvbs2.h:2194
s2_plscodes< T > plscodes
Definition: dvbs2.h:1152
s2_scrambling(int codenum=0)
Definition: dvbs2.h:130
static void interleave(int bps, int rows, const hard_sb *pin, int nslots, bool msb_first, plslot< hard_ss > *pout)
Definition: dvbs2.h:1368
uint32_t lfsr_x(uint32_t X)
Definition: dvbs2.h:153
bch_engine< uint32_t, 128, 17, 16, uint16_t, 0x002d > s2_bch_engine_nf8
Definition: dvbs2.h:1972
pipereader< plslot< hard_ss > > in
Definition: dvbs2.h:396
static void interleave4050(const hard_sb *pin, int nslots, plslot< hard_ss > *pout)
Definition: dvbs2.h:1506
void print_node_stats()
Definition: ldpc.h:137
pipewriter< complex< float > > * symbols_out
Definition: dvbs2.h:1202
ldpc_engine< SOFTBIT, SOFTBYTE, 8, uint16_t > s2_ldpc_engine
Definition: dvbs2.h:1926
s2_deframer(scheduler *sch, pipebuf< bbframe > &_in, pipebuf< tspacket > &_out, pipebuf< int > *_state_out=NULL, pipebuf< unsigned long > *_locktime_out=NULL)
Definition: dvbs2.h:2516
void run_bbframe(bbframe *pin)
Definition: dvbs2.h:2547
static const int MAX_SLOTS_PER_FRAME
Definition: dvbs2.h:222
void scramble(const complex< T > *src, uint8_t r, complex< T > *dst)
Definition: dvbs2.h:374
s2_frame_receiver(scheduler *sch, sampler_interface< T > *_sampler, pipebuf< complex< T >> &_in, pipebuf< plslot< SOFTSYMB >> &_out, pipebuf< float > *_freq_out=NULL, pipebuf< float > *_ss_out=NULL, pipebuf< float > *_mer_out=NULL, pipebuf< complex< float >> *_cstln_out=NULL, pipebuf< complex< float >> *_cstln_pls_out=NULL, pipebuf< complex< float >> *_symbols_out=NULL, pipebuf< int > *_state_out=NULL)
Definition: dvbs2.h:446
s2_bbscrambling bbscrambling
Definition: dvbs2.h:2080
const char * command
Definition: dvbs2.h:2419
void add_syncs(cstln_lut< SOFTSYMB, 256 > *c)
Definition: dvbs2.h:1155
complex< float > interp_next(sampler_state *ss)
Definition: dvbs2.h:1044
int framebits() const
Definition: dvbs2.h:203
pipewriter< bbframe > out
Definition: dvbs2.h:2418
void run_frame(const bbframe *pin, fecframe< hard_sb > *pout)
Definition: dvbs2.h:2058
static void pop_symbols(hard_sb accs[BPS], hard_ss **ps, int ns)
Definition: dvbs2.h:1486
int hamming_weight(uint8_t x)
Definition: math.cpp:6
#define M_PI
Definition: rdsdemod.cpp:27
pipewriter< tspacket > out
Definition: dvbs2.h:2655
cstln_lut< hard_ss, 256 > * cstln
Definition: dvbs2.h:398
s2_scrambling scrambling
Definition: dvbs2.h:1206
pipereader< bbframe > in
Definition: dvbs2.h:2654
void info_unlocked()
Definition: dvbs2.h:2627
llr_t bits[8]
Definition: softword.h:76
bch_engine< uint32_t, 160, 17, 16, uint16_t, 0x002d > s2_bch_engine_nf10
Definition: dvbs2.h:1971
s2_ldpc_engines< SOFTBIT, SOFTBYTE > s2ldpc
Definition: dvbs2.h:2168
s2_plscodes< T > plscodes
Definition: dvbs2.h:425
Fixed< IntType, IntBits > floor(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2301
pipereader< fecframe< hard_sb > > in
Definition: dvbs2.h:1551
unsigned int uint32_t
Definition: rtptypes_win.h:46
static void deinterleave(int bps, int rows, const plslot< SOFTSYMB > *pin, int nslots, bool msb_first, SOFTBYTE *pout)
Definition: dvbs2.h:1652
code_rate
Definition: dvb.h:41
uint8_t rolloff_code
Definition: dvbs2.h:2432
uint8_t track_symbol(sampler_state *ss, const complex< float > &p, cstln_lut< SOFTSYMB, 256 > *c, int mode)
Definition: dvbs2.h:1087
helper_instance * procs
Definition: dvbs2.h:2270
s2_fecdec_helper(scheduler *sch, pipebuf< fecframe< SOFTBYTE >> &_in, pipebuf< bbframe > &_out, const char *_command, pipebuf< int > *_bitcount=NULL, pipebuf< int > *_errcount=NULL)
Definition: dvbs2.h:2213
cstln_lut< SOFTSYMB, 256 > * qpsk
Definition: dvbs2.h:1142
static void deinterleave4050(const plslot< SOFTSYMB > *pin, int nslots, SOFTBYTE *pout)
Definition: dvbs2.h:1736
virtual complex< T > interp(const complex< T > *pin, float mu, float phase)=0
pipewriter< fecframe< SOFTBYTE > > out
Definition: dvbs2.h:1864
static void split_symbol(const llr_ss &ps, hard_sb accs[], int nacc)
Definition: dvbs2.h:1798
virtual void encode(const uint8_t *msg, size_t msgbytes, uint8_t *out)=0
unsigned char uint8_t
Definition: rtptypes_win.h:42
complex< float > descramble(sampler_state *ss, const complex< float > &p)
Definition: dvbs2.h:1018
pipewriter< bbframe > out
Definition: dvbs2.h:2173
complex< T > symbols[LENGTH]
Definition: dvbs2.h:59
void info_is_locked(bool newstate)
Definition: dvbs2.h:2638
llr_t bits[8]
Definition: sdr.h:453
static void split_symbol(const llr_ss &ps, int bps, hard_sb accs[], int nacc, bool msb_first)
Definition: dvbs2.h:1781
static const uint32_t MASK
Definition: dvbs2.h:57
static const int SIZE
Definition: dvb.h:1173
void opt_write(pipewriter< T > *p, T val)
Definition: framework.h:341
unsigned short uint16_t
Definition: rtptypes_win.h:44
cstln_lut< SOFTSYMB, 256 > * cstln
Definition: dvbs2.h:1153
void fail(const char *s)
Definition: framework.cpp:11
complex< float > c
Definition: dvbs2.h:1135
pipewriter< fecframe< hard_sb > > out
Definition: dvbs2.h:2079
void encode(const ldpc_table< Taddr > *table, const SOFTWORD *msg, int k, int n, SOFTWORD *parity, int integrate=true)
Definition: ldpc.h:199
static void pack_qpsk_symbol(const llr_ss &ps, hard_sb *acc, int nacc)
Definition: dvbs2.h:1847
result * lookup(float I, float Q)
Definition: sdr.h:689
s2_scrambling scrambling
Definition: dvbs2.h:426
bool is_pls
Definition: dvbs2.h:210
pipewriter< int > * state_out
Definition: dvbs2.h:1203
int32_t i
Definition: decimators.h:244
pipewriter< complex< float > > * cstln_pls_out
Definition: dvbs2.h:1201
static void split_symbol(const llr_ss &ps, int bps, llr_sb accs[], int nacc, bool msb_first)
Definition: dvbs2.h:1814
pipewriter< plslot< SOFTSYMB > > out
Definition: dvbs2.h:1197
bool opt_writable(pipewriter< T > *p, int n=1)
Definition: framework.h:335
pipewriter< int > * state_out
Definition: dvbs2.h:2657
uint8_t hard_ss
Definition: sdr.h:423
SOFTBYTE bytes[64800/8]
Definition: dvbs2.h:1221
virtual void update_freq(float freqw, int period=1)
Definition: sdr.h:894
void written(unsigned long n)
Definition: framework.h:308
void track_agc(const complex< float > &p)
Definition: dvbs2.h:995
pipewriter< int > * errcount
Definition: dvbs2.h:2424
static void interleave(int rows, const hard_sb *pin, int nslots, plslot< hard_ss > *pout)
Definition: dvbs2.h:1413
pipewriter< T > * opt_writer(pipebuf< T > *buf, unsigned long min_write=1)
Definition: framework.h:329
pipewriter< int > * errcount
Definition: dvbs2.h:2174
void align_phase(sampler_state *ss, const complex< float > &c)
Definition: dvbs2.h:1073
ldpc_table< uint16_t > s2_ldpc_table
Definition: dvbs2.h:1867
void transform(const uint8_t *in, int bbsize, uint8_t *out)
Definition: dvbs2.h:186
bool pilots
Definition: dvbs2.h:202
crc8_engine crc8
Definition: dvbs2.h:2647
s2_frame_transmitter(scheduler *sch, pipebuf< plslot< hard_ss >> &_in, pipebuf< complex< T >> &_out)
Definition: dvbs2.h:300
pipereader< plslot< SOFTSYMB > > in
Definition: dvbs2.h:1863
s2_bch_engines s2bch
Definition: dvbs2.h:2170
s2_fecdec(scheduler *sch, pipebuf< fecframe< SOFTBYTE >> &_in, pipebuf< bbframe > &_out, pipebuf< int > *_bitcount=NULL, pipebuf< int > *_errcount=NULL)
Definition: dvbs2.h:2093
s2_bbscrambling bbscrambling
Definition: dvbs2.h:2171
pipewriter< bbframe > out
Definition: dvbs2.h:2504
int m_rateCode
Definition: sdr.h:880
void fatal(const char *s)
Definition: framework.cpp:6
s2_bch_engines s2bch
Definition: dvbs2.h:2081
const struct leansdr::modcod_info modcod_infos[32]
s2_interleaver(scheduler *sch, pipebuf< fecframe< hard_sb >> &_in, pipebuf< plslot< hard_ss >> &_out)
Definition: dvbs2.h:1229
s2_ldpc_engines< bool, hard_sb > s2ldpc
Definition: dvbs2.h:2082
uint8_t remcrc
Definition: dvbs2.h:2508
int decode_bitflip(const ldpc_table< Taddr > *table, SOFTWORD *cw, int k, int n, int max_bitflips)
Definition: ldpc.h:285
static void deinterleave(int rows, const plslot< SOFTSYMB > *pin, int nslots, SOFTBYTE *pout)
Definition: dvbs2.h:1698
s2_bch_engines s2bch
Definition: dvbs2.h:2422
T gen_sqrt(T x)
ldpc_engine< bool, hard_sb, 8, uint16_t > s2_ldpc_engine
Definition: dvbs2.h:1868
void receive_frame(const helper_job *job)
Definition: dvbs2.h:2373
pipereader< bbframe > in
Definition: dvbs2.h:2078
simplequeue< helper_job, 1024 > jobs
Definition: dvbs2.h:2278
pipereader< complex< T > > in
Definition: dvbs2.h:1196
pipereader< tspacket > in
Definition: dvbs2.h:2503
s2_deinterleaver(scheduler *sch, pipebuf< plslot< SOFTSYMB >> &_in, pipebuf< fecframe< SOFTBYTE >> &_out)
Definition: dvbs2.h:1561
pipewriter< complex< T > > out
Definition: dvbs2.h:397
uint8_t hard_sb
Definition: softword.h:21
static const uint32_t VALUE
Definition: dvbs2.h:56
static const int LENGTH
Definition: dvbs2.h:209
pipewriter< plslot< hard_ss > > out
Definition: dvbs2.h:1552
static void serialize_qpsk(const hard_sb *pin, int nslots, plslot< hard_ss > *pout)
Definition: dvbs2.h:1271
void info_good_packet()
Definition: dvbs2.h:2632
cstln_base::predef c
Definition: dvbs2.h:228
complex< int8_t > * symbols
Definition: sdr.h:478
void init_agc(const complex< T > *buf, int n)
Definition: dvbs2.h:988
SOFTSYMB symbols[LENGTH]
Definition: dvbs2.h:213
void softwords_set(hard_sb p[], int b)
Definition: softword.h:50
u8 data[SIZE_TSPACKET]
Definition: dvb.h:1174
const float cstln_amp
Definition: sdr.h:404
static void deserialize_qpsk(plslot< SOFTSYMB > *pin, int nslots, SOFTBYTE *pout)
Definition: dvbs2.h:1601
const modcod_info * check_modcod(int m)
Definition: dvbs2.h:285
int run_frame(s2_pls *pls, const modcod_info *mcinfo, const plslot< hard_ss > *pin, int nslots, complex< T > *pout)
Definition: dvbs2.h:341
s2_pls pls
Definition: dvbs2.h:1916
modcod_info * mcinfo
Definition: dvbs2.h:1195
virtual int readahead()=0
bool softword_get(const hard_sb &p, int b)
Definition: softword.h:23
pipewriter< float > * ss_out
Definition: dvbs2.h:1199
static void pack_qpsk_symbol(const llr_ss &ps, llr_sb *acc, int nacc)
Definition: dvbs2.h:1856
sampler_interface< T > * sampler
Definition: dvbs2.h:438
pipewriter< complex< float > > * cstln_out
Definition: dvbs2.h:1200
pipereader< fecframe< SOFTBYTE > > in
Definition: dvbs2.h:2417
crc8_engine crc8
Definition: dvbs2.h:2505
static void split_symbol(const llr_ss &ps, llr_sb accs[], int nacc)
Definition: dvbs2.h:1831
void skip_symbols(int ns, float omega)
Definition: dvbs2.h:690
complex< float > diffcorr
Definition: dvbs2.h:500
void softword_clear(hard_sb *p)
Definition: softword.h:32
static const int LENGTH
Definition: dvbs2.h:58
uint32_t lfsr_y(uint32_t Y)
Definition: dvbs2.h:158
pipewriter< unsigned long > * locktime_out
Definition: dvbs2.h:2660
void read(unsigned long n)
Definition: framework.h:367
pipereader< fecframe< SOFTBYTE > > in
Definition: dvbs2.h:2172
#define xfprintf(...)
Definition: dvbs2.h:702
complex< T > conjprod(const complex< T > &u, const complex< T > &v)
Definition: math.h:105
bch_engine< uint32_t, 168, 17, 14, uint16_t, 0x002b > s2_bch_engine_sf12
Definition: dvbs2.h:1974
s2_pls pls
Definition: dvbs2.h:212
pool * get_pool(const s2_pls *pls)
Definition: dvbs2.h:2309
code_rate rate
Definition: dvbs2.h:229
T cnorm2(const complex< T > &u)
Definition: math.h:89
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48
ldpc_engine< bool, hard_sb, 8, uint16_t > s2_ldpc_engine
Definition: dvbs2.h:2036
void update_cstln(const modcod_info *mcinfo)
Definition: dvbs2.h:400