/* * Copyright 2004,2006,2010 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include pager_flex_sync_sptr pager_make_flex_sync() { return gnuradio::get_initial_sptr(new pager_flex_sync()); } // FLEX sync block takes input from sliced baseband stream [0-3] at specified // channel rate. Symbol timing is established based on receiving one of the // defined FLEX protocol synchronization words. The block outputs one FLEX frame // worth of bits on each output phase for the data portion of the frame. Unused phases // get all zeros, which are considered idle code words. pager_flex_sync::pager_flex_sync() : gr_block ("flex_sync", gr_make_io_signature (1, 1, sizeof(unsigned char)), gr_make_io_signature (4, 4, sizeof(unsigned char))), d_sync(10) // Fixed at 10 samples per baud (@ 1600 baud) { enter_idle(); } void pager_flex_sync::forecast(int noutput_items, gr_vector_int &inputs_required) { // samples per bit X number of outputs needed int items = noutput_items*d_spb; for (unsigned int i = 0; i < inputs_required.size(); i++) inputs_required[i] = items; } int pager_flex_sync::index_avg(int start, int end) { // modulo average if (start < end) return (end + start)/2; else return ((end + start)/2 + d_spb/2) % d_spb; } bool pager_flex_sync::test_sync(unsigned char sym) { // 64-bit FLEX sync code: // AAAA:BBBBBBBB:CCCC // // Where BBBBBBBB is always 0xA6C6AAAA // and AAAA^CCCC is 0xFFFF // // Specific values of AAAA determine what bps and encoding the // packet is beyond the frame information word // // First we match on the marker field with a hamming distance < 4 // Then we match on the outer code with a hamming distance < 4 d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2); gr_int64 val = d_sync[d_index]; gr_int32 marker = ((val & 0x0000FFFFFFFF0000ULL)) >> 16; if (gr_count_bits32(marker^FLEX_SYNC_MARKER) < 4) { gr_int32 code = ((val & 0xFFFF000000000000ULL) >> 32) | (val & 0x000000000000FFFFULL); for (int i = 0; i < num_flex_modes; i++) { if (gr_count_bits32(code^flex_modes[i].sync) < 4) { d_mode = i; return true; } } // Marker received but doesn't match known codes // All codes have high word inverted to low word unsigned short high = (code & 0xFFFF0000) >> 16; unsigned short low = code & 0x0000FFFF; unsigned short syn = high^low; if (syn == 0xFFFF) fprintf(stderr, "Unknown sync code detected: %08X\n", code); } return false; } void pager_flex_sync::enter_idle() { d_state = ST_IDLE; d_index = 0; d_start = 0; d_center = 0; d_end = 0; d_count = 0; d_mode = 0; d_baudrate = 1600; d_levels = 2; d_spb = 16000/d_baudrate; d_bit_a = 0; d_bit_b = 0; d_bit_c = 0; d_bit_d = 0; d_hibit = false; fflush(stdout); } void pager_flex_sync::enter_syncing() { d_start = d_index; d_state = ST_SYNCING; } void pager_flex_sync::enter_sync1() { d_state = ST_SYNC1; d_end = d_index; d_center = index_avg(d_start, d_end); // Center of goodness d_count = 0; } void pager_flex_sync::enter_sync2() { d_state = ST_SYNC2; d_count = 0; d_baudrate = flex_modes[d_mode].baud; d_levels = flex_modes[d_mode].levels; d_spb = 16000/d_baudrate; if (d_baudrate == 3200) { // Oversampling buffer just got halved d_center = d_center/2; // We're here at the center of a 1600 baud bit // So this hack puts the index and bit counter // in the right place for 3200 bps. d_index = d_index/2-d_spb/2; d_count = -1; } } void pager_flex_sync::enter_data() { d_state = ST_DATA; d_count = 0; } void pager_flex_sync::parse_fiw() { // Nothing is done with these now, but these will end up getting // passed as metadata when mblocks are available // Bits 31-28 are frame number related, but unknown function // This might be a checksum d_unknown2 = pageri_reverse_bits8((d_fiw >> 24) & 0xF0); // Cycle is bits 27-24, reversed d_cycle = pageri_reverse_bits8((d_fiw >> 20) & 0xF0); // Frame is bits 23-17, reversed d_frame = pageri_reverse_bits8((d_fiw >> 16) & 0xFE); // Bits 16-11 are some sort of marker, usually identical across // many frames but sometimes changes between frames or modes d_unknown1 = (d_fiw >> 11) & 0x3F; //printf("CYC:%02i FRM:%03i\n", d_cycle, d_frame); } int pager_flex_sync::output_symbol(unsigned char sym) { // Here is where we output a 1 or 0 on each phase according // to current FLEX mode and symbol value. Unassigned phases // are zero from the enter_idle() initialization. // // FLEX can transmit the data portion of the frame at either // 1600 bps or 3200 bps, and can use either two- or four-level // FSK encoding. // // At 1600 bps, 2-level, a single "phase" is transmitted with bit // value '0' using level '3' and bit value '1' using level '0'. // // At 1600 bps, 4-level, a second "phase" is transmitted, and the // di-bits are encoded with a gray code: // // Symbol Phase 1 Phase 2 // ------ ------- ------- // 0 1 1 // 1 1 0 // 2 0 0 // 3 0 1 // // At 1600 bps, 4-level, these are called PHASE A and PHASE B. // // At 3200 bps, the same 1 or 2 bit encoding occurs, except that // additionally two streams are interleaved on alternating symbols. // Thus, PHASE A (and PHASE B if 4-level) are decoded on one symbol, // then PHASE C (and PHASE D if 4-level) are decoded on the next. int bits = 0; if (d_baudrate == 1600) { d_bit_a = (sym < 2); if (d_levels == 4) d_bit_b = (sym == 0) || (sym == 3); *d_phase_a++ = d_bit_a; *d_phase_b++ = d_bit_b; *d_phase_c++ = d_bit_c; *d_phase_d++ = d_bit_d; bits++; } else { if (!d_hibit) { d_bit_a = (sym < 2); if (d_levels == 4) d_bit_b = (sym == 0) || (sym == 3); d_hibit = true; } else { d_bit_c = (sym < 2); if (d_levels == 4) d_bit_d = (sym == 0) || (sym == 3); d_hibit = false; *d_phase_a++ = d_bit_a; *d_phase_b++ = d_bit_b; *d_phase_c++ = d_bit_c; *d_phase_d++ = d_bit_d; bits++; } } return bits; } int pager_flex_sync::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]; d_phase_a = (unsigned char *)output_items[0]; d_phase_b = (unsigned char *)output_items[1]; d_phase_c = (unsigned char *)output_items[2]; d_phase_d = (unsigned char *)output_items[3]; int i = 0, j = 0; int ninputs = ninput_items[0]; while (i < ninputs && j < noutput_items) { unsigned char sym = *in++; i++; d_index = ++d_index % d_spb; switch (d_state) { case ST_IDLE: // Continually compare the received symbol stream // against the known FLEX sync words. if (test_sync(sym)) enter_syncing(); break; case ST_SYNCING: // Wait until we stop seeing sync, then calculate // the center of the bit period (d_center) if (!test_sync(sym)) enter_sync1(); break; case ST_SYNC1: // Skip 16 bits of dotting, then accumulate 32 bits // of Frame Information Word. if (d_index == d_center) { d_fiw = (d_fiw << 1) | (sym > 1); if (++d_count == 48) { // FIW is accumulated, call BCH to error correct it pageri_bch3221(d_fiw); parse_fiw(); enter_sync2(); } } break; case ST_SYNC2: // This part and the remainder of the frame are transmitted // at either 1600 bps or 3200 bps based on the received // FLEX sync word. The second SYNC header is 25ms of idle bits // at either speed. if (d_index == d_center) { // Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps if (++d_count == d_baudrate/40) enter_data(); } break; case ST_DATA: // The data portion of the frame is 1760 ms long at either // baudrate. This is 2816 bits @ 1600 bps and 5632 bits @ 3200 bps. // The output_symbol() routine decodes and doles out the bits // to each of the four transmitted phases of FLEX interleaved codes. if (d_index == d_center) { j += output_symbol(sym); if (++d_count == d_baudrate*1760/1000) enter_idle(); } break; default: assert(0); // memory corruption of d_state if ever gets here break; } } consume_each(i); return j; }