/* # Copyright 2010 Nick Foster # Copyright 2013 Nicholas Corgan # # This file is part of gr-air-modes # # gr-air-modes 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. # # gr-air-modes 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 gr-air-modes; 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 air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db) { return air_modes_preamble_sptr (new air_modes_preamble(channel_rate, threshold_db)); } air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) : gr::block ("modes_preamble", gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference gr::io_signature::make (1, 1, sizeof(float))) //the output packets { d_chip_rate = 2000000; //2Mchips per second d_samples_per_chip = channel_rate / d_chip_rate; //must be integer number of samples per chip to work d_samples_per_symbol = d_samples_per_chip * 2; d_check_width = 120 * d_samples_per_symbol; //only search to this far from the end of the stream buffer d_threshold_db = threshold_db; d_threshold = powf(10., threshold_db/20.); //the level that the sample must be above the moving average in order to qualify as a pulse d_secs_per_sample = 1.0 / channel_rate; set_output_multiple(1+d_check_width*2); std::stringstream str; str << name() << unique_id(); d_me = pmt::string_to_symbol(str.str()); d_key = pmt::string_to_symbol("preamble_found"); set_history(d_samples_per_symbol); } static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) { for(int i=0; i tstamp_tags; get_tags_in_range(tstamp_tags, 0, abs_sample_cnt, abs_sample_cnt + ninputs, pmt::string_to_symbol("rx_time")); //tags.back() is the most recent timestamp, then. if(tstamp_tags.size() > 0) { d_timestamp = tstamp_tags.back(); } for(int i=0; i < ninputs; i++) { float pulse_threshold = inavg[i] * d_threshold; if(in[i] > pulse_threshold) { //hey we got a candidate if(in[i+1] > in[i]) continue; //wait for the peak //check to see the rest of the pulses are there if( in[i+pulse_offsets[1]] < pulse_threshold ) continue; if( in[i+pulse_offsets[2]] < pulse_threshold ) continue; if( in[i+pulse_offsets[3]] < pulse_threshold ) continue; //get a more accurate bit center by finding the correlation peak across all four preamble bits bool late, early; int how_late = 0; do { double now_corr = correlate_preamble(in+i, d_samples_per_chip); double late_corr = correlate_preamble(in+i+1, d_samples_per_chip); double early_corr = correlate_preamble(in+i-1, d_samples_per_chip); late = (late_corr > now_corr); //early = (early_corr > now_corr); if(late) { i++; how_late++; } //if(early && i>0) { std::cout << "EARLY " << i << std::endl; i--; } } while(late and how_late < d_samples_per_chip);// xor early); if(0) std::cout << "We were " << how_late << " samples late" << std::endl; //now check to see that the non-peak symbols in the preamble //are below the peaks by threshold dB float avgpeak = ( in[i+pulse_offsets[0]] + in[i+pulse_offsets[1]] + in[i+pulse_offsets[2]] + in[i+pulse_offsets[3]]) / 4.0; float space_threshold = inavg[i] + (avgpeak - inavg[i])/d_threshold; bool valid_preamble = true; //f'in c++ for( int j=1.5*d_samples_per_symbol; j<=3*d_samples_per_symbol; j++) if(in[i+j] > space_threshold) valid_preamble = false; for( int j=5*d_samples_per_symbol; j<=7.5*d_samples_per_symbol; j++) if(in[i+j] > space_threshold) valid_preamble = false; if(!valid_preamble) continue; //be sure we've got enough room in the input buffer to copy out a whole packet if(ninputs-i < 240*d_samples_per_chip) { consume_each(std::max(i-1,0)); if(0) std::cout << "Preamble consumed " << std::max(i-1,0) << ", returned 0 (no room)" << std::endl; return 0; } //all right i'm prepared to call this a preamble //let's integrate and dump the output //FIXME: disable and use center sample bool life_sucks = true; if(life_sucks) { for(int j=0; j<240; j++) { out[j] = in[i+j*d_samples_per_chip]; } } else { i -= d_samples_per_chip-1; integrate_and_dump(out, &in[i], 240, d_samples_per_chip); } //get the timestamp of the preamble double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample); //now tag the preamble add_item_tag(0, //stream ID nitems_written(0), //sample d_key, //frame_info pmt::from_double(tstamp), d_me //block src id ); //std::cout << "PREAMBLE" << std::endl; //produce only one output per work call -- TODO this should probably change if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl; consume_each(i+240*d_samples_per_chip); return 240; } } //didn't get anything this time if(0) std::cout << "Preamble consumed " << ninputs << ", returned 0" << std::endl; consume_each(ninputs); return 0; }