/* -*- c++ -*- */ /* * Copyright 2016 <+YOU OR YOUR COMPANY+>. * * This 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. * * This software 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 this software; 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 #define dout debug && std::cout #define lout log && std::cout #include #include "constants.h" #include "rds_decoder_redsea_impl.h" #include #include #include namespace gr { namespace multirds { rds_decoder_redsea::sptr rds_decoder_redsea::make(bool log, bool debug) { return gnuradio::get_initial_sptr (new rds_decoder_redsea_impl(log, debug)); } /* * The private constructor */ rds_decoder_redsea_impl::rds_decoder_redsea_impl(bool log, bool debug) : gr::sync_block("rds_decoder_redsea", gr::io_signature::make (1, 1, sizeof(char)), gr::io_signature::make (0, 0, 0)), log(log), debug(debug) { set_output_multiple(104); // 1 RDS datagroup = 104 bits message_port_register_out(pmt::mp("out")); enter_no_sync(); dout << "constructing error lookup table"< 0) { // dout<<"found sy 14 offset A in table"< 0; i--) { reg = (reg << 1) | ((message >> (i-1)) & 0x01); if (reg & (1 << plen)) reg = reg ^ poly; } for (i = plen; i > 0; i--) { reg = reg << 1; if (reg & (1<& matrix) { uint32_t result = 0; for (size_t k=0; k < matrix.size(); k++) if ((vec >> k) & 0x01) result ^= matrix[matrix.size() - 1 - k]; return result; } // Section B.2.1: 'The calculation of the syndromes -- can easily be done by // multiplying each word with the parity matrix H.' uint32_t calcSyndrome_vec(uint32_t vec) { static const std::vector parity_check_matrix({ 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002, 0x001, 0x2dc, 0x16e, 0x0b7, 0x287, 0x39f, 0x313, 0x355, 0x376, 0x1bb, 0x201, 0x3dc, 0x1ee, 0x0f7, 0x2a7, 0x38f, 0x31b }); return matrixMultiply(vec, parity_check_matrix); } const unsigned kBitmask16 = 0x000FFFF; const unsigned kBitmask26 = 0x3FFFFFF; const unsigned kBitmask28 = 0xFFFFFFF; std::map, uint32_t> rds_decoder_redsea_impl::makeErrorLookupTable() { std::map, uint32_t> result; /*static const unsigned int offset_pos[5]={0,1,2,3,2}; static const unsigned int offset_word[5]={252,408,360,436,848}; static const unsigned int syndrome[5]={383,14,303,663,748}; static const char * const offset_name[]={"A","B","C","D","c"};*/ //const std::vector offset_words ={0x0FC, 0x198, 0x168, 0x350, 0x1B4}; for (uint8_t offset_num=0;offset_num<5;offset_num++) { //dout<<"name:" <(errvec) < 0) { uint32_t err = kErrorLookup.at({syndrome, offset}); //dout << "correcting"<> 8U) & 0xffU; bytes[1] = (group[0] ) & 0xffU; bytes[2] = (group[1] >> 8U) & 0xffU; bytes[3] = (group[1] ) & 0xffU; bytes[4] = (group[2] >> 8U) & 0xffU; bytes[5] = (group[2] ) & 0xffU; bytes[6] = (group[3] >> 8U) & 0xffU; bytes[7] = (group[3] ) & 0xffU; // RDS offset words bytes[8] = offset_chars[0]; bytes[9] = offset_chars[1]; bytes[10] = offset_chars[2]; bytes[11] = offset_chars[3]; //bytes[12]=last_wrong_blocks_counter; pmt::pmt_t data(pmt::make_blob(bytes, 12)); //pmt::pmt_t meta(pmt::PMT_NIL); pmt::pmt_t meta(pmt::from_long(0)); pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair message_port_pub(pmt::mp("out"), pdu); } unsigned int rds_decoder_redsea_impl::offset_char_to_word(char offset_char){ // {'A','B','C','D','c'}; // {252,408,360,436,848}; switch(offset_char){ case 'A':return offset_word[0]; case 'B':return offset_word[1]; case 'C':return offset_word[2]; case 'D':return offset_word[3]; case 'c':return offset_word[4]; } std::cout << "error converting offset char to word"<>10) & 0xffff;//data part of received block (upper 16 bits) block_calculated_crc=calc_syndrome(dataword,16); checkword=reg & 0x3ff;//checkword part of received block (lower 10 bits) /* manage special case of C or C' offset word */ if (block_number==2) { if (variant==0){//A offset_char = 'C'; block_received_crc=checkword^offset_word[2]; } else{//B offset_char = 'c'; block_received_crc=checkword^offset_word[4]; //dout<<"B"<>10) & 0xffff; checkword=corrected_block & 0x3ff; //dout << "corrected error"<>1); uint16_t diff2=(dataword>>1)^(last_pi); unsigned int num_diff_bits = std::bitset<16>(diff).count(); unsigned int num_diff_bits2 = std::bitset<16>(diff2).count(); if (num_diff_bits<2){ dout << "clockslip detection (forward,skipped one):"<(dataword)<<"\tlast_pi:"<(last_pi)<(dataword)<<"\tlast_pi:"<(last_pi)<>10) & 0xffff; checkword=corrected_block & 0x3ff; dout << "corrected error:"< read group type variant variant=(dataword>>11)& 0x1; // uint8_t group=(dataword>>12)& 0xf; // dout << "group:"<35) {//reduced from 35 lout << "@@@@@ Lost Sync (Got " << wrong_blocks_counter << " bad blocks on " << blocks_counter << " total)" << std::endl; enter_no_sync(); } else { lout << "@@@@@ Still Sync-ed (Got " << wrong_blocks_counter << " bad blocks on " << blocks_counter << " total)" << std::endl; } pmt::pmt_t meta(pmt::from_long(2)); pmt::pmt_t data(pmt::from_double((double)wrong_blocks_counter/(double)blocks_counter)); pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair message_port_pub(pmt::mp("out"), pdu); blocks_counter=0; wrong_blocks_counter=0; } } break; default: d_state=NO_SYNC; break; } i++; bit_counter++; } return noutput_items; }/*end of work function*/ } /* namespace multirds */ } /* namespace gr */