/* -*- c++ -*- */ /* * Copyright 2015,2016 Free Software Foundation, Inc. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "dvb_bbheader_bb_impl.h" #include <gnuradio/io_signature.h> namespace gr { namespace dtv { dvb_bbheader_bb::sptr dvb_bbheader_bb::make(dvb_standard_t standard, dvb_framesize_t framesize, dvb_code_rate_t rate, dvbs2_rolloff_factor_t rolloff, dvbt2_inputmode_t mode, dvbt2_inband_t inband, int fecblocks, int tsrate) { return gnuradio::make_block_sptr<dvb_bbheader_bb_impl>( standard, framesize, rate, rolloff, mode, inband, fecblocks, tsrate); } /* * The private constructor */ dvb_bbheader_bb_impl::dvb_bbheader_bb_impl(dvb_standard_t standard, dvb_framesize_t framesize, dvb_code_rate_t rate, dvbs2_rolloff_factor_t rolloff, dvbt2_inputmode_t mode, dvbt2_inband_t inband, int fecblocks, int tsrate) : gr::block("dvb_bbheader_bb", gr::io_signature::make(1, 1, sizeof(unsigned char)), gr::io_signature::make(1, 1, sizeof(unsigned char))) { count = 0; crc = 0x0; dvbs2x = FALSE; alternate = TRUE; nibble = TRUE; frame_size = framesize; BBHeader* f = &m_format[0].bb_header; if (framesize == FECFRAME_NORMAL) { switch (rate) { case C1_4: kbch = 16008; break; case C1_3: kbch = 21408; break; case C2_5: kbch = 25728; break; case C1_2: kbch = 32208; break; case C3_5: kbch = 38688; break; case C2_3: kbch = 43040; break; case C3_4: kbch = 48408; break; case C4_5: kbch = 51648; break; case C5_6: kbch = 53840; break; case C8_9: kbch = 57472; break; case C9_10: kbch = 58192; break; case C2_9_VLSNR: kbch = 14208; break; case C13_45: kbch = 18528; break; case C9_20: kbch = 28968; break; case C90_180: kbch = 32208; break; case C96_180: kbch = 34368; break; case C11_20: kbch = 35448; break; case C100_180: kbch = 35808; break; case C104_180: kbch = 37248; break; case C26_45: kbch = 37248; break; case C18_30: kbch = 38688; break; case C28_45: kbch = 40128; break; case C23_36: kbch = 41208; break; case C116_180: kbch = 41568; break; case C20_30: kbch = 43008; break; case C124_180: kbch = 44448; break; case C25_36: kbch = 44808; break; case C128_180: kbch = 45888; break; case C13_18: kbch = 46608; break; case C132_180: kbch = 47328; break; case C22_30: kbch = 47328; break; case C135_180: kbch = 48408; break; case C140_180: kbch = 50208; break; case C7_9: kbch = 50208; break; case C154_180: kbch = 55248; break; default: kbch = 0; break; } } else if (framesize == FECFRAME_SHORT) { switch (rate) { case C1_4: kbch = 3072; break; case C1_3: kbch = 5232; break; case C2_5: kbch = 6312; break; case C1_2: kbch = 7032; break; case C3_5: kbch = 9552; break; case C2_3: kbch = 10632; break; case C3_4: kbch = 11712; break; case C4_5: kbch = 12432; break; case C5_6: kbch = 13152; break; case C8_9: kbch = 14232; break; case C11_45: kbch = 3792; break; case C4_15: kbch = 4152; break; case C14_45: kbch = 4872; break; case C7_15: kbch = 7392; break; case C8_15: kbch = 8472; break; case C26_45: kbch = 9192; break; case C32_45: kbch = 11352; break; case C1_5_VLSNR_SF2: kbch = 2512; break; case C11_45_VLSNR_SF2: kbch = 3792; break; case C1_5_VLSNR: kbch = 3072; break; case C4_15_VLSNR: kbch = 4152; break; case C1_3_VLSNR: kbch = 5232; break; default: kbch = 0; break; } } else { switch (rate) { case C1_5_MEDIUM: kbch = 5660; break; case C11_45_MEDIUM: kbch = 7740; break; case C1_3_MEDIUM: kbch = 10620; break; default: kbch = 0; break; } } if (standard == STANDARD_DVBS2) { mode = INPUTMODE_NORMAL; inband_type_b = FALSE; } f->ts_gs = TS_GS_TRANSPORT; f->sis_mis = SIS_MIS_SINGLE; f->ccm_acm = CCM; f->issyi = ISSYI_NOT_ACTIVE; f->npd = NPD_NOT_ACTIVE; if (mode == INPUTMODE_NORMAL) { f->upl = 188 * 8; f->dfl = kbch - 80; f->sync = 0x47; } else { f->upl = 0; f->dfl = kbch - 80; f->sync = 0; } if (standard == STANDARD_DVBS2) { if (rolloff & 0x4) { dvbs2x = TRUE; } f->ro = rolloff & 0x3; } else { f->ro = 0; } build_crc8_table(); input_mode = mode; inband_type_b = inband; fec_blocks = fecblocks; fec_block = 0; ts_rate = tsrate; extra = (((kbch - 80) / 8) / 187) + 1; if (framesize != FECFRAME_MEDIUM) { set_output_multiple(kbch); } else { set_output_multiple(kbch * 2); } } /* * Our virtual destructor. */ dvb_bbheader_bb_impl::~dvb_bbheader_bb_impl() {} void dvb_bbheader_bb_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) { if (input_mode == INPUTMODE_NORMAL) { if (frame_size != FECFRAME_MEDIUM) { ninput_items_required[0] = ((noutput_items - 80) / 8); } else { ninput_items_required[0] = ((noutput_items - 160) / 8); } } else { ninput_items_required[0] = ((noutput_items - 80) / 8) + extra; } } #define CRC_POLY 0xAB // Reversed #define CRC_POLYR 0xD5 void dvb_bbheader_bb_impl::build_crc8_table(void) { int r, crc; for (int i = 0; i < 256; i++) { r = i; crc = 0; for (int j = 7; j >= 0; j--) { if ((r & (1 << j) ? 1 : 0) ^ ((crc & 0x80) ? 1 : 0)) { crc = (crc << 1) ^ CRC_POLYR; } else { crc <<= 1; } } crc_tab[i] = crc; } } /* * MSB is sent first * * The polynomial has been reversed */ int dvb_bbheader_bb_impl::add_crc8_bits(unsigned char* in, int length) { int crc = 0; int b; int i = 0; for (int n = 0; n < length; n++) { b = in[i++] ^ (crc & 0x01); crc >>= 1; if (b) { crc ^= CRC_POLY; } } if (input_mode == INPUTMODE_HIEFF) { crc ^= 0x80; } for (int n = 0; n < 8; n++) { in[i++] = (crc & (1 << n)) ? 1 : 0; } return 8; // Length of CRC } void dvb_bbheader_bb_impl::add_bbheader(unsigned char* out, int count, int padding, bool nibble) { int temp, m_frame_offset_bits; unsigned char* m_frame = out; BBHeader* h = &m_format[0].bb_header; m_frame[0] = h->ts_gs >> 1; m_frame[1] = h->ts_gs & 1; m_frame[2] = h->sis_mis; m_frame[3] = h->ccm_acm; m_frame[4] = h->issyi & 1; m_frame[5] = h->npd & 1; if (dvbs2x == TRUE) { if (alternate == TRUE) { alternate = FALSE; m_frame[6] = 1; m_frame[7] = 1; } else { alternate = TRUE; m_frame[6] = h->ro >> 1; m_frame[7] = h->ro & 1; } } else { m_frame[6] = h->ro >> 1; m_frame[7] = h->ro & 1; } m_frame_offset_bits = 8; if (h->sis_mis == SIS_MIS_MULTIPLE) { temp = h->isi; for (int n = 7; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } } else { for (int n = 7; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } } temp = h->upl; for (int n = 15; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } temp = h->dfl - padding; for (int n = 15; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } temp = h->sync; for (int n = 7; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } // Calculate syncd, this should point to the MSB of the CRC temp = count; if (temp == 0) { temp = count; } else { temp = (188 - count) * 8; } if (nibble == FALSE) { temp += 4; } for (int n = 15; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } // Add CRC to BB header, at end int len = BB_HEADER_LENGTH_BITS; m_frame_offset_bits += add_crc8_bits(m_frame, len); } void dvb_bbheader_bb_impl::add_inband_type_b(unsigned char* out, int ts_rate) { int temp, m_frame_offset_bits; unsigned char* m_frame = out; m_frame[0] = 0; m_frame[1] = 1; m_frame_offset_bits = 2; for (int n = 30; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } for (int n = 21; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } for (int n = 1; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } for (int n = 9; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } temp = ts_rate; for (int n = 26; n >= 0; n--) { m_frame[m_frame_offset_bits++] = temp & (1 << n) ? 1 : 0; } for (int n = 9; n >= 0; n--) { m_frame[m_frame_offset_bits++] = 0; } } int dvb_bbheader_bb_impl::general_work(int noutput_items, gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { const unsigned char* in = (const unsigned char*)input_items[0]; unsigned char* out = (unsigned char*)output_items[0]; int consumed = 0; int offset = 0; int padding; unsigned char b; for (int i = 0; i < noutput_items; i += kbch) { if (frame_size != FECFRAME_MEDIUM) { if (fec_block == 0 && inband_type_b == TRUE) { padding = 104; } else { padding = 0; } add_bbheader(&out[offset], count, padding, TRUE); offset = offset + 80; if (input_mode == INPUTMODE_HIEFF) { for (int j = 0; j < (int)((kbch - 80 - padding) / 8); j++) { if (count == 0) { if (*in != 0x47) { GR_LOG_WARN(d_logger, "Transport Stream sync error!"); } j--; in++; } else { b = *in++; for (int n = 7; n >= 0; n--) { out[offset++] = b & (1 << n) ? 1 : 0; } } count = (count + 1) % 188; consumed++; } if (fec_block == 0 && inband_type_b == TRUE) { add_inband_type_b(&out[offset], ts_rate); offset = offset + 104; } } else { for (int j = 0; j < (int)((kbch - 80 - padding) / 8); j++) { if (count == 0) { if (*in != 0x47) { GR_LOG_WARN(d_logger, "Transport Stream sync error!"); } in++; b = crc; crc = 0; } else { b = *in++; crc = crc_tab[b ^ crc]; } count = (count + 1) % 188; consumed++; for (int n = 7; n >= 0; n--) { out[offset++] = b & (1 << n) ? 1 : 0; } } if (fec_block == 0 && inband_type_b == TRUE) { add_inband_type_b(&out[offset], ts_rate); offset = offset + 104; } } if (inband_type_b == TRUE) { fec_block = (fec_block + 1) % fec_blocks; } } else { padding = 0; add_bbheader(&out[offset], count, padding, nibble); offset = offset + 80; for (int j = 0; j < (int)((kbch - 80) / 4); j++) { if (nibble == TRUE) { if (count == 0) { if (*in != 0x47) { GR_LOG_WARN(d_logger, "Transport Stream sync error!"); } in++; b = crc; crc = 0; } else { b = *in++; crc = crc_tab[b ^ crc]; } bsave = b; count = (count + 1) % 188; consumed++; for (int n = 7; n >= 4; n--) { out[offset++] = b & (1 << n) ? 1 : 0; } nibble = FALSE; } else { for (int n = 3; n >= 0; n--) { out[offset++] = bsave & (1 << n) ? 1 : 0; } nibble = TRUE; } } } } // Tell runtime system how many input items we consumed on // each input stream. consume_each(consumed); // Tell runtime system how many output items we produced. return noutput_items; } } /* namespace dtv */ } /* namespace gr */