X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=gr-atsc%2Fsrc%2Flib%2Fatsci_viterbi_gen.cc;fp=gr-atsc%2Fsrc%2Flib%2Fatsci_viterbi_gen.cc;h=ea5c3fa87189a6c9dafb30d4ca20a3acd7a4f4bf;hb=35e43e8d8c271e6842191cac3fc3f2f88a861183;hp=0000000000000000000000000000000000000000;hpb=ea29b08aeb54227e6628f655ccfdb96fe4d8c378;p=debian%2Fgnuradio diff --git a/gr-atsc/src/lib/atsci_viterbi_gen.cc b/gr-atsc/src/lib/atsci_viterbi_gen.cc new file mode 100644 index 00000000..ea5c3fa8 --- /dev/null +++ b/gr-atsc/src/lib/atsci_viterbi_gen.cc @@ -0,0 +1,267 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +using std::cerr; + +/* + * Trellis-encode a whole pile of 12 data segments for ATSC. + * This also includes scrambling the data among twelve Trellis encoders. + * + * Input is twelve 207-byte blocks of raw data (Reed-Solomon output that's + * been scrambled up by interleaving with other blocks). + * + * Output is 12 x 208 x 4 bytes, each byte containing a 3-bit symbol. + * The first 4 bytes are the segment sync symbol. + * + Got the first version of Trellis encoder coded. Compiles, but I + didn't realize that each data segment contains an odd number of BITS! + The second data segment in a field starts by pulling bits out of the + middles of the bytes it's encoding. You actually have to read all the + entries in that table on page 59 AND 60 to get it. + + There's a 4-segment asymmetric pattern of bit accesses. + There's a 3-segment asymmetric pattern of muxing encoders. + + The result is there's a 12-segment pattern that repeats throughout + the encoding of a field. So this routine now encodes 12 segments at once. + + This encoding system was either designed by a complete idiot or by + a complete genius. It's highly complex when it could have been very + simple. Now the question is whether + this incredible complexity buys us anything subtle and important. + */ + +#define SEGMENT_SIZE 207 +#define INPUT_SIZE (SEGMENT_SIZE * 12) +#define DIBITS_PER_BYTE 4 +#define EXTRAS (4 * 12) /* FIXME, sync symbols and such */ +#define SYMBOLS_OUT ((INPUT_SIZE * DIBITS_PER_BYTE) + EXTRAS) +#define SEGOF(x) ( (x) / ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE)) +#define SYMOF(x) (((x) % ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))-4) +#define ENCODERS 12 +#define ENCODER_SEG_BUMP 4 + + +/* Shift counts to bit numbers (high order, low order); 9x entries unused */ +static const int bit1[8] = {1, 99, 3, 98, 5, 97, 7, 96}; +static const int bit2[8] = {0, 99, 2, 98, 4, 97, 6, 96}; + +/* Detailed Debugging */ +int debug_dec = 0; + +/* + * Build indirect data structures to say which symbols go into which + * encoder, and then where the resulting dibits from the encoders go. + */ +int +build_decode_structures (char *fileout) +{ + int retval = 0; + int i; + int encoder; + int trellis_wheredata[ENCODERS]; + unsigned char *symp, *next_sym_seg; + unsigned char symbols[SYMBOLS_OUT]; + int chunk; + int shift; + int skip_encoder_bump; + int *enco_syms[ENCODERS]; + int *enco_dibits[ENCODERS]; + int j; + /* The data structures we'll build and then spit out... */ + int sync_symbol_indices[1000]; + int sync_symbol_indices_max; + int enco_which_syms[ENCODERS][INPUT_SIZE]; + int enco_which_dibits[ENCODERS][INPUT_SIZE]; + int enco_which_max; + #define BIT_PTR(int,shif) (((int) << 3) | ((shif) & 0x7)) + /* Running indices into them as we build 'em... */ + int *syncsyms = sync_symbol_indices; + + /* Start our running pointers at the start of our per-encoder subarrays */ + for (i = 0; i < ENCODERS; i++) { + enco_dibits[i] = enco_which_dibits[i]; + enco_syms[i] = enco_which_syms[i]; + } + + encoder = ENCODERS - ENCODER_SEG_BUMP; + skip_encoder_bump = 0; + symp = symbols; + next_sym_seg = symp; + + for (chunk = 0; + chunk < INPUT_SIZE; + chunk += ENCODERS) { + /* Associate data bytes with the Trellis encoders. + They get loaded or stored in an order that depends on where we are in the + segment sync progress (sigh). + GRR! When the chunk reload happens at the same time as the + segment boundary, we should bump the encoder NOW for the reload, + rather than LATER during the bitshift transition!!! */ + if (symp >= next_sym_seg) { + encoder = (encoder + ENCODER_SEG_BUMP) % ENCODERS; + skip_encoder_bump = 1; + } + + /* Remember where the data bytes are going to go, once we've + accumulated them from the 12 interleaved decoders */ + for (i = 0; i < ENCODERS; i++) { + trellis_wheredata[encoder] = chunk+i; + encoder++; + if (encoder >= ENCODERS) encoder = 0; + } + + for (shift = 6; shift >= 0; shift -= 2) { + + /* Segment boundaries happen to occur on some bitshift transitions. */ + if (symp >= next_sym_seg) { + /* Segment transition. Output a data segment sync symbol, and + mess with the trellis encoder mux. */ + *syncsyms++ = symp - symbols; + symp += 4; + next_sym_seg = symp + (SEGMENT_SIZE * DIBITS_PER_BYTE); + + if (!skip_encoder_bump) + encoder = (encoder + ENCODER_SEG_BUMP) % ENCODERS; + skip_encoder_bump = 0; + } + + /* Now run each of the 12 Trellis encoders to spit out 12 symbols. + Each encoder takes input from the same byte of the chunk, but the + outputs of the encoders come out in various orders. + NOPE -- this is false. The encoders take input from various + bytes of the chunk (which changes at segment sync time), AND + they also come out in various orders. You really do have to + keep separate track of: the datasegs bytes, the encoders, and + the symbol bytes -- because they're all moving with respect to + each other!!! */ + for (i = 0; i < ENCODERS; i++) { + if (debug_dec) + printf ("Seg %ld Symb %3ld Trell %2d Byte %6d Bits %d-%d = ", + (long) SEGOF(symp-symbols), (long) SYMOF(symp-symbols), + encoder, trellis_wheredata[encoder], + bit1[shift], bit2[shift]); + + /* Decoding: Grab symbol, run through decoder, slice dibit into + buffer. */ + /* This symbol goes into this encoder next */ + *(enco_syms[encoder]++) = symp - symbols; + symp++; + /* The next output from this encoder goes into these dibits */ + *(enco_dibits[encoder]++) = BIT_PTR(trellis_wheredata[encoder], shift); + + encoder++; if (encoder >= ENCODERS) encoder = 0; + } /* Encoders */ + } /* Bit shifts */ + +#if 0 + /* Now dump out the chunk of 12 data bytes that the twelve decoders have + accumulated. */ + unsigned char trellis_buffer[ENCODERS]; + unsigned char dibit; + unsigned char symbol; + int save_state; + for (i = 0; i < ENCODERS; i++) { + datasegs [trellis_wheredata[encoder]] = trellis_buffer[encoder]; + encoder++; + if (encoder >= ENCODERS) encoder = 0; + } /* Dumping encoder bytes */ +#endif + } /* Chunks */ + + /* Now print the resulting data structures in C++ */ + + if (!freopen(fileout, "w", stdout)) + return 2; + + printf ("/*\n\ + * atsc_viterbi_mux.cc\n\ + *\n\ + * Data structures for knowing which symbols are fed to which\n\ + * Viterbi decoders, and then where to put the resulting output dibits.\n\ + *\n\ + * Generated by 'atsc_viterbi_gen.cc'.\n\ + */\n\n"); + sync_symbol_indices_max = syncsyms - sync_symbol_indices; + printf ("const unsigned int sync_symbol_indices_max = %d;\n", + sync_symbol_indices_max); + printf ("const unsigned int sync_symbol_indices[%d] = {\n ", + sync_symbol_indices_max); + for (i = 0; i < sync_symbol_indices_max; i++) { + printf ("%d,%s", sync_symbol_indices[i], (7 == i%8)? "\n ": " "); + } + printf ("};\n\n"); + + enco_which_max = enco_dibits[0] - enco_which_dibits[0]; + for (i = 0; i < ENCODERS; i++) + if (enco_which_max != enco_dibits[i] - enco_which_dibits[i]) { + cerr << "Encoder " << i << " has different max_dibits " << + enco_dibits[i] - enco_which_dibits[i] << " than " << enco_which_max; + retval = 3; + } + + printf ("const unsigned int enco_which_max = %d;\n" , enco_which_max); + + printf ("const unsigned int enco_which_syms[%d][%d] = {\n", + ENCODERS, enco_which_max); + for (i = 0; i < ENCODERS; i++) { + printf (" /* %d */\n {", i); + for (j = 0; j < enco_which_max; j++) + printf ("%d,%s", enco_which_syms[i][j], (7 == j%8)? "\n ": " "); + printf ("},\n"); + } + printf ("};\n\n"); + + printf ("const unsigned int enco_which_dibits[%d][%d] = {\n", + ENCODERS, enco_which_max); + for (i = 0; i < ENCODERS; i++) { + printf (" /* %d */\n {", i); + for (j = 0; j < enco_which_max; j++) + printf ("%d,%s", enco_which_dibits[i][j], (7 == j%8)? "\n ": " "); + printf ("},\n"); + } + printf ("};\n\n"); + return retval; +} + +int +usage() +{ + cerr << "atsc_viterbi_gen: Usage:\n"; + cerr << " ./atsc_viterbi_gen -o atsc_viterbi_mux.cc\n"; + cerr << "That's all, folks!\n"; + return 1; +} + + +int +main(int argc, char **argv) +{ + if (argc != 3) return usage(); + if (argv[1][0] != '-' + || argv[1][1] != 'o' + || argv[1][2] != 0 ) return usage(); + return build_decode_structures(argv[2]); +}