diff --git a/src/lib/air_modes_slicer.cc b/src/lib/air_modes_slicer.cc index a2b150c..942869e 100644 --- a/src/lib/air_modes_slicer.cc +++ b/src/lib/air_modes_slicer.cc @@ -31,6 +31,7 @@ #include #include #include +#include extern "C" { @@ -58,6 +59,14 @@ air_modes_slicer::air_modes_slicer(int channel_rate, gr_msg_queue_sptr queue) : set_output_multiple(1+d_check_width * 2); //how do you specify buffer size for sinks? } +static bool pmtcompare(pmt::pmt_t x, pmt::pmt_t y) +{ + uint64_t t_x, t_y; + t_x = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(x, 0)); + t_y = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(y, 0)); + return t_x < t_y; +} + int air_modes_slicer::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) @@ -146,8 +155,48 @@ int air_modes_slicer::work(int noutput_items, } else { if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j; } - } + + /******************** BEGIN TIMESTAMP BS ******************/ + uint64_t abs_sample_cnt = nitems_read(0); + std::vector tags; + + //printf("nitems_read: %i", abs_sample_cnt); + pmt::pmt_t timestamp = pmt::mp(pmt::mp(0), pmt::mp(0)); //so we don't barf if there isn't one + + get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + i); + //tags.back() is the most recent timestamp, then. + if(tags.size() > 0) { + std::sort(tags.begin(), tags.end(), pmtcompare); + + do { + timestamp = tags.back(); + tags.pop_back(); + } while(!pmt::pmt_eqv(gr_tags::get_key(timestamp), pmt::pmt_string_to_symbol("time"))); //only interested in timestamps + + uint64_t timestamp_secs = pmt_to_uint64(pmt_tuple_ref(timestamp, 0)); + double timestamp_frac = pmt_to_double(pmt_tuple_ref(timestamp, 1)); + uint64_t timestamp_sample = gr_tags::get_nitems(timestamp); + //now we have to offset the timestamp based on the current sample number + uint64_t timestamp_delta = (abs_sample_cnt + i) - timestamp_sample; + + timestamp_frac += timestamp_delta * (1.0 / (d_samples_per_chip * d_chip_rate)); + if(timestamp_frac > 1.0) { + timestamp_frac -= 1.0; + timestamp_secs++; + } + + rx_packet.timestamp_secs = timestamp_secs; + rx_packet.timestamp_frac = timestamp_frac; + } + else { + rx_packet.timestamp_secs = 0; + rx_packet.timestamp_frac = 0; + } + + /******************* END TIMESTAMP BS *********************/ + + //increment for the next round i += packet_length * d_samples_per_symbol; //here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC. @@ -237,7 +286,8 @@ int air_modes_slicer::work(int noutput_items, } } - d_payload << " " << std::setw(6) << rx_packet.parity << " " << std::dec << rx_packet.reference_level; + d_payload << " " << std::setw(6) << rx_packet.parity << " " << std::dec << rx_packet.reference_level + << " " << rx_packet.timestamp_secs << " " << rx_packet.timestamp_frac; gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str())); d_queue->handle(msg); diff --git a/src/lib/air_modes_types.h b/src/lib/air_modes_types.h index bc12bcd..bc8af53 100644 --- a/src/lib/air_modes_types.h +++ b/src/lib/air_modes_types.h @@ -36,6 +36,8 @@ struct modes_packet { framer_packet_type type; //what length packet are we unsigned int message_type; float reference_level; + unsigned long timestamp_secs; //timestamp from tags + double timestamp_frac; }; #endif diff --git a/src/python/modes_print.py b/src/python/modes_print.py index c1af26f..3d3d6ea 100644 --- a/src/python/modes_print.py +++ b/src/python/modes_print.py @@ -30,7 +30,9 @@ class modes_output_print(modes_parse.modes_parse): modes_parse.modes_parse.__init__(self, mypos) def parse(self, message): - [msgtype, shortdata, longdata, parity, ecc, reference] = message.split() + [msgtype, shortdata, longdata, parity, ecc, reference, time_secs, time_frac] = message.split() + time_secs = long(time_secs) + time_frac = float(time_frac) shortdata = long(shortdata, 16) longdata = long(longdata, 16) @@ -53,7 +55,7 @@ class modes_output_print(modes_parse.modes_parse): elif msgtype == 17: output = self.print17(shortdata, longdata, parity, ecc) else: - output = "No handler for message type " + str(msgtype) + " from " + str(ecc) + output = "No handler for message type " + str(msgtype) + " from %x" % ecc if reference == 0.0: refdb = 0.0 @@ -61,7 +63,7 @@ class modes_output_print(modes_parse.modes_parse): refdb = 10.0*math.log10(reference) if output is not None: - output = "(%.0f) " % (refdb) + output + output = "(%.0f %u %f) " % (refdb, time_secs, time_frac) + output print output def print0(self, shortdata, parity, ecc): diff --git a/src/python/uhd_modes.py b/src/python/uhd_modes.py index 6c16c32..f569a56 100755 --- a/src/python/uhd_modes.py +++ b/src/python/uhd_modes.py @@ -54,11 +54,11 @@ class adsb_rx_block (gr.top_block): self.args = args if options.filename is None: - self.u = uhd.simple_source("", uhd.io_type_t.COMPLEX_FLOAT32) + self.u = uhd.single_usrp_source("", uhd.io_type_t.COMPLEX_FLOAT32) - if(options.rx_subdev_spec is None): - options.rx_subdev_spec = "" - self.u.set_subdev_spec(options.rx_subdev_spec) + #if(options.rx_subdev_spec is None): + # options.rx_subdev_spec = "" + #self.u.set_subdev_spec(options.rx_subdev_spec) rate = options.rate self.u.set_samp_rate(rate) @@ -66,7 +66,7 @@ class adsb_rx_block (gr.top_block): if options.gain is None: #set to halfway g = self.u.get_gain_range() - options.gain = (g.min+g.max) / 2.0 + options.gain = (g.start()+g.stop()) / 2.0 if not(self.tune(options.freq)): print "Failed to set initial frequency" @@ -89,34 +89,38 @@ class adsb_rx_block (gr.top_block): #the DBSRX especially tends to be spur-prone; the LPF keeps out the #spur multiple that shows up at 2MHz - self.filtcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3) - self.filter = gr.fir_filter_fff(1, self.filtcoeffs) +# self.filtcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3) +# self.filter = gr.fir_filter_fff(1, self.filtcoeffs) self.preamble = air.modes_preamble(rate, options.threshold) self.framer = air.modes_framer(rate) self.slicer = air.modes_slicer(rate, queue) - self.connect(self.u, self.demod, self.filter) - self.connect(self.filter, self.avg) - self.connect(self.filter, (self.preamble, 0)) - self.connect(self.avg, (self.preamble, 1)) - self.connect(self.filter, (self.framer, 0)) - self.connect(self.preamble, (self.framer, 1)) - self.connect(self.filter, (self.slicer, 0)) - self.connect(self.framer, (self.slicer, 1)) + #self.nullsink = gr.file_sink(gr.sizeof_gr_complex, "/dev/null") + + #self.connect(self.u, self.nullsink) + +# self.connect(self.u, self.demod, self.filter) +# self.connect(self.filter, self.avg) +# self.connect(self.filter, (self.preamble, 0)) +# self.connect(self.avg, (self.preamble, 1)) +# self.connect(self.filter, (self.framer, 0)) +# self.connect(self.preamble, (self.framer, 1)) +# self.connect(self.filter, (self.slicer, 0)) +# self.connect(self.framer, (self.slicer, 1)) #use this flowgraph instead to omit the filter -# self.connect(self.u, self.demod) -# self.connect(self.demod, self.avg) -# self.connect(self.demod, (self.preamble, 0)) -# self.connect(self.avg, (self.preamble, 1)) -# self.connect(self.demod, (self.framer, 0)) -# self.connect(self.preamble, (self.framer, 1)) -# self.connect(self.demod, (self.slicer, 0)) -# self.connect(self.framer, (self.slicer, 1)) + self.connect(self.u, self.demod) + self.connect(self.demod, self.avg) + self.connect(self.demod, (self.preamble, 0)) + self.connect(self.avg, (self.preamble, 1)) + self.connect(self.demod, (self.framer, 0)) + self.connect(self.preamble, (self.framer, 1)) + self.connect(self.demod, (self.slicer, 0)) + self.connect(self.framer, (self.slicer, 1)) def tune(self, freq): - result = self.u.set_center_freq(freq) + result = self.u.set_center_freq(freq, 0) return result if __name__ == '__main__':