diff options
Diffstat (limited to 'lib')
36 files changed, 1636 insertions, 219 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index db440e4..923de48 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -70,6 +70,7 @@ add_subdirectory(flow_control) add_subdirectory(misc_utils) add_subdirectory(qa_utils) add_subdirectory(receiver) +add_subdirectory(transmitter) ######################################################################## # Setup library diff --git a/lib/decoding/sch.c b/lib/decoding/sch.c index 9cf6ac4..fff82ea 100644 --- a/lib/decoding/sch.c +++ b/lib/decoding/sch.c @@ -21,7 +21,7 @@ */ #include <string.h> -#include "gsm_constants.h" +#include <grgsm/gsm_constants.h> #include <stdbool.h> #include <osmocom/coding/gsm0503_coding.h> diff --git a/lib/flow_control/CMakeLists.txt b/lib/flow_control/CMakeLists.txt index 30a5f50..b8f63f7 100644 --- a/lib/flow_control/CMakeLists.txt +++ b/lib/flow_control/CMakeLists.txt @@ -23,6 +23,7 @@ add_sources( burst_sdcch_subslot_splitter_impl.cc burst_timeslot_filter_impl.cc burst_timeslot_splitter_impl.cc + burst_type_filter_impl.cc dummy_burst_filter_impl.cc uplink_downlink_splitter_impl.cc ) diff --git a/lib/flow_control/burst_type_filter_impl.cc b/lib/flow_control/burst_type_filter_impl.cc new file mode 100644 index 0000000..c8bbd7e --- /dev/null +++ b/lib/flow_control/burst_type_filter_impl.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* @file + * @author (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; 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 <gnuradio/io_signature.h> +#include "burst_type_filter_impl.h" +#include <stdio.h> +#include <grgsm/endian.h> +#include <grgsm/gsmtap.h> + + +namespace gr { + namespace gsm { + + burst_type_filter::sptr + burst_type_filter::make(const std::vector<uint8_t> & selected_burst_types) + { + return gnuradio::get_initial_sptr + (new burst_type_filter_impl(selected_burst_types)); + } + + /* + * The private constructor + */ + burst_type_filter_impl::burst_type_filter_impl(const std::vector<uint8_t> & selected_burst_types) + : gr::block("burst_type_filter", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_filter_policy(FILTER_POLICY_DEFAULT) + { + set_selected_burst_types(selected_burst_types); + + message_port_register_in(pmt::mp("bursts_in")); + message_port_register_out(pmt::mp("bursts_out")); + + set_msg_handler(pmt::mp("bursts_in"), boost::bind(&burst_type_filter_impl::process_burst, this, _1)); + } + + /* + * Our virtual destructor. + */ + burst_type_filter_impl::~burst_type_filter_impl() {} + + void burst_type_filter_impl::process_burst(pmt::pmt_t msg) + { + if (d_filter_policy == FILTER_POLICY_DROP_ALL) + return; + + if (d_filter_policy == FILTER_POLICY_PASS_ALL) { + message_port_pub(pmt::mp("bursts_out"), msg); + return; + } + + gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(pmt::cdr(msg)); + if (std::find(d_selected_burst_types.begin(), d_selected_burst_types.end(), header->sub_type) != d_selected_burst_types.end()) //check if burst type is listed in burst types to pass + { + message_port_pub(pmt::mp("bursts_out"), msg); + } + } + + /* Filtering policy */ + filter_policy + burst_type_filter_impl::get_policy(void) + { + return d_filter_policy; + } + + filter_policy + burst_type_filter_impl::set_policy(filter_policy policy) + { + d_filter_policy = policy; + return d_filter_policy; + } + + void + burst_type_filter_impl::set_selected_burst_types(const std::vector<uint8_t> & selected_burst_types) + { + d_selected_burst_types.assign(selected_burst_types.begin(), selected_burst_types.end()); + } + } /* namespace gsm */ +} /* namespace gr */ diff --git a/lib/flow_control/burst_type_filter_impl.h b/lib/flow_control/burst_type_filter_impl.h new file mode 100644 index 0000000..5c6ad14 --- /dev/null +++ b/lib/flow_control/burst_type_filter_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* @file + * @author (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef INCLUDED_GSM_BURST_TYPE_FILTER_IMPL_H +#define INCLUDED_GSM_BURST_TYPE_FILTER_IMPL_H + +#define BURST_TYPE_LEN 148 + +#include <grgsm/flow_control/burst_type_filter.h> + +namespace gr { + namespace gsm { + + class burst_type_filter_impl : public burst_type_filter + { + private: + filter_policy d_filter_policy; + std::vector<uint8_t> d_selected_burst_types; + public: + burst_type_filter_impl(const std::vector<uint8_t> & selected_burst_types); + ~burst_type_filter_impl(); + void process_burst(pmt::pmt_t msg); + + /* External API */ + /* Filtering policy */ + filter_policy get_policy(void); + filter_policy set_policy(filter_policy policy); + + void set_selected_burst_types(const std::vector<uint8_t> & selected_burst_types); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_BURST_TYPE_FILTER_IMPL_H */ + diff --git a/lib/flow_control/uplink_downlink_splitter_impl.cc b/lib/flow_control/uplink_downlink_splitter_impl.cc index 691feb3..de5ae30 100644 --- a/lib/flow_control/uplink_downlink_splitter_impl.cc +++ b/lib/flow_control/uplink_downlink_splitter_impl.cc @@ -30,7 +30,7 @@ #include <grgsm/endian.h> #define BURST_SIZE 148 namespace gr { - namespace grgsm { + namespace gsm { uplink_downlink_splitter::sptr uplink_downlink_splitter::make() @@ -71,6 +71,6 @@ namespace gr { uplink_downlink_splitter_impl::~uplink_downlink_splitter_impl() { } - } /* namespace grgsm */ + } /* namespace gsm */ } /* namespace gr */ diff --git a/lib/flow_control/uplink_downlink_splitter_impl.h b/lib/flow_control/uplink_downlink_splitter_impl.h index fb8b2b8..5edfe5a 100644 --- a/lib/flow_control/uplink_downlink_splitter_impl.h +++ b/lib/flow_control/uplink_downlink_splitter_impl.h @@ -26,7 +26,7 @@ #include <grgsm/flow_control/uplink_downlink_splitter.h> namespace gr { - namespace grgsm { + namespace gsm { class uplink_downlink_splitter_impl : public uplink_downlink_splitter { @@ -36,7 +36,7 @@ namespace gr { void process_msg(pmt::pmt_t msg); }; - } // namespace grgsm + } // namespace gsm } // namespace gr #endif /* INCLUDED_GRGSM_UPLINK_DOWNLINK_SPLITTER_IMPL_H */ diff --git a/lib/misc_utils/CMakeLists.txt b/lib/misc_utils/CMakeLists.txt index 720eee3..e0fc818 100644 --- a/lib/misc_utils/CMakeLists.txt +++ b/lib/misc_utils/CMakeLists.txt @@ -33,5 +33,9 @@ add_sources( message_printer_impl.cc msg_to_tag_impl.cc tmsi_dumper_impl.cc + time_spec.cc + fn_time.cc + udp_socket.cc + trx_burst_if_impl.cc ) diff --git a/lib/misc_utils/controlled_fractional_resampler_cc_impl.cc b/lib/misc_utils/controlled_fractional_resampler_cc_impl.cc index 3376c67..36cf170 100644 --- a/lib/misc_utils/controlled_fractional_resampler_cc_impl.cc +++ b/lib/misc_utils/controlled_fractional_resampler_cc_impl.cc @@ -177,6 +177,6 @@ namespace gr { set_relative_rate(1.0 / resamp_ratio); } - } /* namespace grgsm */ + } /* namespace gsm */ } /* namespace gr */ diff --git a/lib/misc_utils/controlled_fractional_resampler_cc_impl.h b/lib/misc_utils/controlled_fractional_resampler_cc_impl.h index 24e00ed..1ca8082 100644 --- a/lib/misc_utils/controlled_fractional_resampler_cc_impl.h +++ b/lib/misc_utils/controlled_fractional_resampler_cc_impl.h @@ -64,7 +64,7 @@ namespace gr { void set_resamp_ratio(float resamp_ratio); }; - } // namespace grgsm + } // namespace gsm } // namespace gr #endif /* INCLUDED_GRGSM_CONTROLLED_FRACTIONAL_RESAMPLER_CC_IMPL_H */ diff --git a/lib/misc_utils/fn_time.cc b/lib/misc_utils/fn_time.cc new file mode 100644 index 0000000..2773f33 --- /dev/null +++ b/lib/misc_utils/fn_time.cc @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @author Vadim Yanitskiy <axilirator@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#include <grgsm/misc_utils/fn_time.h> +#include <grgsm/misc_utils/time_spec.h> +#include <math.h> + +#define GSM_HYPER_FRAME (26 * 51 * 2048) +#define GSM_SYM_RATE (13.0e6 / 48.0) + +#define GSM_TS_PERIOD (156.25 / GSM_SYM_RATE) +#define GSM_FN_PERIOD (8 * GSM_TS_PERIOD) + +namespace gr { + namespace gsm { + /** + * Computes difference between two frame numbers modulo + * GSM_HYPER_FRAME / 2. The result is correct if difference + * between the frame numbers is not bigger than GSM_HYPER_FRAME / 2. + * @param fn1 first frame number + * @param fn2 second frame number + * @return computed difference + */ + static int fnmod_delta(uint32_t fn1, uint32_t fn2) + { + int delta, h2; + + delta = (fn1 % GSM_HYPER_FRAME) - (fn2 % GSM_HYPER_FRAME); + + h2 = GSM_HYPER_FRAME / 2; + + if (delta >= h2) { + delta -= GSM_HYPER_FRAME; + } else if(delta < -h2) { + delta += GSM_HYPER_FRAME; + } + + return delta; + } + + static int fn_time_diff_delta(uint32_t fn, uint32_t fn_ref, + time_spec_t time_diff_hint) + { + int frames_diff, fn_delta; + frames_diff = int(round(time_diff_hint.get_real_secs() / GSM_FN_PERIOD)); + fn_delta = fnmod_delta(fn, fn_ref + frames_diff) + frames_diff; + + return fn_delta; + } + + /** + * Computes difference between reference frame number + * and a second frame number. + * @param fn_ref reference frame number modulo GSM_HYPER_FRAME + * @param fn second frame number modulo GSM_HYPER_FRAME + * @param time_ref precise timestamp of the first sample in the fn_ref + * @param time_hint coarse time for fn that is used as a hint to avoid + * ambiguities caused by modulo operation applied to + * frame numbers + * @return difference between fn_ref and fn + */ + time_format fn_time_delta_cpp(uint32_t fn_ref, time_format time_ref, uint32_t fn_x, + time_format time_hint, uint32_t ts_num, uint32_t ts_ref) + { + time_spec_t time_diff_hint = time_spec_t(time_hint.first, time_hint.second) - time_spec_t(time_ref.first, time_ref.second); + int fn_delta = fn_time_diff_delta(fn_x, fn_ref, time_diff_hint); + time_spec_t time_x_precise = fn_delta * GSM_FN_PERIOD + time_spec_t(time_ref.first, time_ref.second) + (static_cast<int>(ts_num) - static_cast<int>(ts_ref)) * GSM_TS_PERIOD; + + return time_format(time_x_precise.get_full_secs(), time_x_precise.get_frac_secs()); + } + + } /* namespace gsm */ +} /* namespace gr */ + diff --git a/lib/misc_utils/msg_to_tag_impl.cc b/lib/misc_utils/msg_to_tag_impl.cc index 0ab65e7..e08c7e6 100644 --- a/lib/misc_utils/msg_to_tag_impl.cc +++ b/lib/misc_utils/msg_to_tag_impl.cc @@ -94,6 +94,6 @@ namespace gr { return noutput_items; } - } /* namespace grgsm */ + } /* namespace gsm */ } /* namespace gr */ diff --git a/lib/misc_utils/msg_to_tag_impl.h b/lib/misc_utils/msg_to_tag_impl.h index 39c6ca3..55e1fae 100644 --- a/lib/misc_utils/msg_to_tag_impl.h +++ b/lib/misc_utils/msg_to_tag_impl.h @@ -44,7 +44,7 @@ namespace gr { gr_vector_void_star &output_items); }; - } // namespace grgsm + } // namespace gsm } // namespace gr #endif /* INCLUDED_GRGSM_MSG_TO_TAG_IMPL_H */ diff --git a/lib/misc_utils/time_spec.cc b/lib/misc_utils/time_spec.cc new file mode 100644 index 0000000..5293da2 --- /dev/null +++ b/lib/misc_utils/time_spec.cc @@ -0,0 +1,122 @@ +// +// Copyright 2011-2013 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// This program 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 program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <grgsm/misc_utils/time_spec.h> + +namespace gr { + namespace gsm { + + /*********************************************************************** + * Time spec constructors + **********************************************************************/ + #define time_spec_init(full, frac) { \ + const time_t _full = time_t(full); \ + const double _frac = double(frac); \ + const int _frac_int = int(_frac); \ + _full_secs = _full + _frac_int; \ + _frac_secs = _frac - _frac_int; \ + if (_frac_secs < 0) {\ + _full_secs -= 1; \ + _frac_secs += 1; \ + } \ + } + + inline long long fast_llround(const double x){ + return (long long)(x + 0.5); // assumption of non-negativity + } + + time_spec_t::time_spec_t(const time_spec_t & spec){ + time_spec_init(spec.get_full_secs(), spec.get_frac_secs()); + } + + time_spec_t::time_spec_t(double secs){ + time_spec_init(0, secs); + } + + time_spec_t::time_spec_t(time_t full_secs, double frac_secs){ + time_spec_init(full_secs, frac_secs); + } + + time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate){ + const double frac_secs = tick_count/tick_rate; + time_spec_init(full_secs, frac_secs); + } + + time_spec_t time_spec_t::from_ticks(long long ticks, double tick_rate){ + const long long rate_i = (long long)(tick_rate); + const double rate_f = tick_rate - rate_i; + const time_t secs_full = time_t(ticks/rate_i); + const long long ticks_error = ticks - (secs_full*rate_i); + const double ticks_frac = ticks_error - secs_full*rate_f; + return time_spec_t(secs_full, ticks_frac/tick_rate); + } + + /*********************************************************************** + * Time spec accessors + **********************************************************************/ + long time_spec_t::get_tick_count(double tick_rate) const{ + return long(fast_llround(this->get_frac_secs()*tick_rate)); + } + + long long time_spec_t::to_ticks(double tick_rate) const{ + const long long rate_i = (long long)(tick_rate); + const double rate_f = tick_rate - rate_i; + const long long ticks_full = this->get_full_secs()*rate_i; + const double ticks_error = this->get_full_secs()*rate_f; + const double ticks_frac = this->get_frac_secs()*tick_rate; + return ticks_full + fast_llround(ticks_error + ticks_frac); + } + + double time_spec_t::get_real_secs(void) const{ + return this->get_full_secs() + this->get_frac_secs(); + } + + /*********************************************************************** + * Time spec math overloads + **********************************************************************/ + time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ + time_spec_init( + this->get_full_secs() + rhs.get_full_secs(), + this->get_frac_secs() + rhs.get_frac_secs() + ); + return *this; + } + + time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ + time_spec_init( + this->get_full_secs() - rhs.get_full_secs(), + this->get_frac_secs() - rhs.get_frac_secs() + ); + return *this; + } + + bool operator==(const time_spec_t &lhs, const time_spec_t &rhs){ + return + lhs.get_full_secs() == rhs.get_full_secs() and + lhs.get_frac_secs() == rhs.get_frac_secs() + ; + } + + bool operator<(const time_spec_t &lhs, const time_spec_t &rhs){ + return ( + (lhs.get_full_secs() < rhs.get_full_secs()) or ( + (lhs.get_full_secs() == rhs.get_full_secs()) and + (lhs.get_frac_secs() < rhs.get_frac_secs()) + )); + } + } +} diff --git a/lib/misc_utils/trx_burst_if_impl.cc b/lib/misc_utils/trx_burst_if_impl.cc new file mode 100644 index 0000000..8f458b0 --- /dev/null +++ b/lib/misc_utils/trx_burst_if_impl.cc @@ -0,0 +1,231 @@ +/* -*- c++ -*- */ +/* @file + * @author Vadim Yanitskiy <axilirator@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; 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 <gnuradio/io_signature.h> +#include <boost/lexical_cast.hpp> + +#include "udp_socket.h" +#include "trx_burst_if_impl.h" + +#define BURST_SIZE 148 +#define DATA_IF_MTU 160 + +/** + * 41-bit RACH synchronization sequence + * GSM 05.02 Chapter 5.2.7 Access burst (AB) + */ +static uint8_t rach_synch_seq[] = { + 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, +}; + +namespace gr { + namespace gsm { + + trx_burst_if::sptr + trx_burst_if::make( + const std::string &remote_addr, + const std::string &base_port) + { + int base_port_int = boost::lexical_cast<int> (base_port); + + return gnuradio::get_initial_sptr + (new trx_burst_if_impl(remote_addr, base_port_int)); + } + + /* + * The private constructor + */ + trx_burst_if_impl::trx_burst_if_impl( + const std::string &remote_addr, + int base_port + ) : gr::block("trx_burst_if", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) + { + message_port_register_in(pmt::mp("bursts")); + message_port_register_out(pmt::mp("bursts")); + + // Bind a port handler + set_msg_handler(pmt::mp("bursts"), + boost::bind(&trx_burst_if_impl::handle_dl_burst, this, _1)); + + // Prepare port numbers + std::string data_src_port = boost::lexical_cast<std::string> (base_port + 2); + std::string data_dst_port = boost::lexical_cast<std::string> (base_port + 102); + + // Init DATA interface + d_data_sock = new udp_socket(remote_addr, + data_src_port, data_dst_port, DATA_IF_MTU); + + // Bind DATA interface handler + d_data_sock->udp_rx_handler = boost::bind( + &trx_burst_if_impl::handle_ul_burst, this, _1, _2); + } + + /* + * Our virtual destructor. + */ + trx_burst_if_impl::~trx_burst_if_impl() + { + // Release all UDP sockets and free memory + delete d_data_sock; + } + + /* + * Check if burst is a RACH burst + */ + bool trx_burst_if_impl::detect_rach(uint8_t *burst) + { + // Compare synchronization sequence + for (int i = 0; i < 41; i++) + if (burst[i + 8] != rach_synch_seq[i]) + return false; + + // Make sure TB and GP are filled by 0x00 + for (int i = 0; i < 63; i++) + if (burst[i + 85] != 0x00) + return false; + + return true; + } + + /* + * Create an UDP payload with burst bits + * and some channel data. + */ + void + trx_burst_if_impl::burst_pack(pmt::pmt_t msg, uint8_t *buf) + { + pmt::pmt_t header_plus_burst = pmt::cdr(msg); + + // Extract GSMTAP header from message + gsmtap_hdr *header = (gsmtap_hdr *) + pmt::blob_data(header_plus_burst); + + // Pack timeslot index + buf[0] = header->timeslot; + + // Extract frame number + uint32_t frame_nr = be32toh(header->frame_number); + + // Pack frame number + buf[1] = (frame_nr >> 24) & 0xff; + buf[2] = (frame_nr >> 16) & 0xff; + buf[3] = (frame_nr >> 8) & 0xff; + buf[4] = (frame_nr >> 0) & 0xff; + + // Pack RSSI (-dBm) + buf[5] = -(uint8_t) header->signal_dbm; + + // Pack correlator timing offset (TOA) + // FIXME: where to find this value? + buf[6] = 0; + buf[7] = 0; + + // Extract bits {0..1} from message + // Despite GR-GSM uses int8_t, they are not real sbits {-127..127} + uint8_t *burst = (uint8_t *) + (pmt::blob_data(header_plus_burst)) + sizeof(gsmtap_hdr); + + // Convert to transceiver interface specific bits {255..0} + for (int i = 0; i < 148; i++) + buf[8 + i] = burst[i] ? 255 : 0; + + // Fill two unused bytes + buf[156] = 0x00; + buf[157] = 0x00; + } + + void + trx_burst_if_impl::handle_dl_burst(pmt::pmt_t msg) + { + // 8 bytes of header + 148 bytes of burst + // + two unused, but required bytes + // otherwise bursts would be rejected + uint8_t buf[158]; + + // Compose a new UDP payload with burst + burst_pack(msg, buf); + + // Send a burst + d_data_sock->udp_send(buf, 158); + } + + void + trx_burst_if_impl::handle_ul_burst(uint8_t *payload, size_t len) + { + // Check length according to the protocol + if (len != 154) + return; + + /* Make sure TS index is correct */ + if (payload[0] >= 8) + return; + + /* Unpack and check frame number */ + uint32_t fn = (payload[1] << 24) + | (payload[2] << 16) + | (payload[3] << 8) + | payload[4]; + + if (fn >= 2715648) + return; + + // Prepare a buffer for GSMTAP header and burst + uint8_t buf[sizeof(gsmtap_hdr) + BURST_SIZE]; + + // Set up pointer to GSMTAP header structure + struct gsmtap_hdr *header = (struct gsmtap_hdr *) buf; + memset(header, 0x00, sizeof(struct gsmtap_hdr)); + + // Fill in basic info + header->version = GSMTAP_VERSION; + header->hdr_len = sizeof(gsmtap_hdr) / 4; + header->type = GSMTAP_TYPE_UM_BURST; + + // Set timeslot index and frame number + header->timeslot = payload[0]; + header->frame_number = htobe32(fn); + + // Check if one is a RACH burst + header->sub_type = detect_rach(payload + 6) ? + GSMTAP_BURST_ACCESS : GSMTAP_BURST_NORMAL; + + // Copy burst bits (0 & 1) for source message + memcpy(buf + sizeof(gsmtap_hdr), payload + 6, BURST_SIZE); + + // Create a pmt blob + pmt::pmt_t blob = pmt::make_blob(buf, sizeof(gsmtap_hdr) + BURST_SIZE); + pmt::pmt_t msg = pmt::cons(pmt::PMT_NIL, blob); + + /* Send a message to the output */ + message_port_pub(pmt::mp("bursts"), msg); + } + + } /* namespace gsm */ +} /* namespace gr */ diff --git a/lib/misc_utils/trx_burst_if_impl.h b/lib/misc_utils/trx_burst_if_impl.h new file mode 100644 index 0000000..35f939c --- /dev/null +++ b/lib/misc_utils/trx_burst_if_impl.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* @file + * @author Vadim Yanitskiy <axilirator@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef INCLUDED_GRGSM_TRX_BURST_IF_IMPL_H +#define INCLUDED_GRGSM_TRX_BURST_IF_IMPL_H + +#include <stddef.h> + +#include <grgsm/gsmtap.h> +#include <grgsm/misc_utils/trx_burst_if.h> + +namespace gr { + namespace gsm { + + class trx_burst_if_impl : public trx_burst_if + { + private: + udp_socket *d_data_sock; + + bool detect_rach(uint8_t *burst); + void burst_pack(pmt::pmt_t msg, uint8_t *buf); + + public: + trx_burst_if_impl(const std::string &remote_addr, int base_port); + ~trx_burst_if_impl(); + + void handle_dl_burst(pmt::pmt_t msg); + void handle_ul_burst(uint8_t *payload, size_t len); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GRGSM_TRX_BURST_IF_IMPL_H */ + diff --git a/lib/misc_utils/udp_socket.cc b/lib/misc_utils/udp_socket.cc new file mode 100644 index 0000000..5c689c7 --- /dev/null +++ b/lib/misc_utils/udp_socket.cc @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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 <gnuradio/thread/thread.h> +#include <gnuradio/io_signature.h> +#include <gnuradio/blocks/pdu.h> +#include <pmt/pmt.h> + +#include <boost/lexical_cast.hpp> +#include "udp_socket.h" + +using boost::asio::ip::udp; + +namespace gr { + namespace gsm { + + udp_socket::udp_socket( + const std::string &remote_addr, + const std::string &src_port, + const std::string &dst_port, + size_t mtu) + { + // Resize receive buffer according to MTU value + d_rxbuf.resize(mtu); + + // Resolve remote host address + udp::resolver resolver(d_io_service); + + udp::resolver::query rx_query( + udp::v4(), remote_addr, src_port, + boost::asio::ip::resolver_query_base::passive); + udp::resolver::query tx_query( + udp::v4(), remote_addr, dst_port, + boost::asio::ip::resolver_query_base::passive); + + d_udp_endpoint_rx = *resolver.resolve(rx_query); + d_udp_endpoint_tx = *resolver.resolve(tx_query); + + // Create a socket + d_udp_socket.reset(new udp::socket(d_io_service, d_udp_endpoint_rx)); + + // Setup read handler + d_udp_socket->async_receive_from( + boost::asio::buffer(d_rxbuf), d_udp_endpoint_rx, + boost::bind(&udp_socket::handle_udp_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + + // Start server + d_thread = gr::thread::thread( + boost::bind(&udp_socket::run_io_service, this)); + } + + udp_socket::~udp_socket() + { + // Stop server + d_io_service.stop(); + d_thread.interrupt(); + d_thread.join(); + } + + void + udp_socket::run_io_service(void) + { + d_io_service.run(); + } + + void + udp_socket::udp_send(uint8_t *data, size_t len) + { + d_udp_socket->send_to( + boost::asio::buffer(data, len), + d_udp_endpoint_tx); + } + + void + udp_socket::handle_udp_read( + const boost::system::error_code& error, + size_t bytes_transferred) + { + if (error) + return; + + // Call incoming data handler + if (udp_rx_handler != NULL) + udp_rx_handler((uint8_t *) &d_rxbuf[0], bytes_transferred); + + d_udp_socket->async_receive_from( + boost::asio::buffer(d_rxbuf), d_udp_endpoint_rx, + boost::bind(&udp_socket::handle_udp_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + } /* namespace gsm */ +}/* namespace gr */ diff --git a/lib/misc_utils/udp_socket.h b/lib/misc_utils/udp_socket.h new file mode 100644 index 0000000..15b2c66 --- /dev/null +++ b/lib/misc_utils/udp_socket.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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. + */ + +#ifndef INCLUDED_GRGSM_TRX_UDP_SOCKET_H +#define INCLUDED_GRGSM_TRX_UDP_SOCKET_H + +#include <gnuradio/thread/thread.h> + +#include <boost/function.hpp> +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <boost/bind.hpp> +#include <pmt/pmt.h> + +namespace gr { + namespace gsm { + + class udp_socket + { + private: + boost::asio::io_service d_io_service; + std::vector<char> d_rxbuf; + gr::thread::thread d_thread; + bool d_started; + bool d_finished; + + boost::asio::ip::udp::endpoint d_udp_endpoint_rx; + boost::asio::ip::udp::endpoint d_udp_endpoint_tx; + boost::shared_ptr<boost::asio::ip::udp::socket> d_udp_socket; + + void handle_udp_read(const boost::system::error_code& error, + size_t bytes_transferred); + void run_io_service(void); + + public: + udp_socket( + const std::string &remote_addr, + const std::string &src_port, + const std::string &dst_port, + size_t mtu); + ~udp_socket(); + + void udp_send(uint8_t *data, size_t len); + boost::function<void (uint8_t *, size_t)> udp_rx_handler; + }; + + } /* namespace gsm */ +} /* namespace gr */ + +#endif /* INCLUDED_GRGSM_TRX_UDP_SOCKET_H */ diff --git a/lib/qa_utils/burst_sink_impl.cc b/lib/qa_utils/burst_sink_impl.cc index 102c5be..bdc2192 100644 --- a/lib/qa_utils/burst_sink_impl.cc +++ b/lib/qa_utils/burst_sink_impl.cc @@ -47,7 +47,8 @@ namespace gr { burst_sink_impl::burst_sink_impl() : gr::block("burst_sink", gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)) + gr::io_signature::make(0, 0, 0)), + d_bursts(pmt::PMT_NIL) { message_port_register_in(pmt::mp("in")); set_msg_handler(pmt::mp("in"), boost::bind(&burst_sink_impl::process_burst, this, _1)); @@ -105,7 +106,10 @@ namespace gr { { return d_burst_data; } - + pmt::pmt_t burst_sink_impl::get_bursts() + { + return d_bursts; + } } /* namespace gsm */ } /* namespace gr */ diff --git a/lib/qa_utils/burst_sink_impl.h b/lib/qa_utils/burst_sink_impl.h index 1035430..e87422d 100644 --- a/lib/qa_utils/burst_sink_impl.h +++ b/lib/qa_utils/burst_sink_impl.h @@ -35,6 +35,7 @@ namespace gr { std::vector<int> d_framenumbers; std::vector<int> d_timeslots; std::vector<std::string> d_burst_data; + pmt::pmt_t d_bursts; public: burst_sink_impl(); ~burst_sink_impl(); @@ -42,6 +43,7 @@ namespace gr { virtual std::vector<int> get_framenumbers(); virtual std::vector<int> get_timeslots(); virtual std::vector<std::string> get_burst_data(); + virtual pmt::pmt_t get_bursts(); }; } // namespace gsm diff --git a/lib/receiver/CMakeLists.txt b/lib/receiver/CMakeLists.txt index 343d2f8..123eba5 100644 --- a/lib/receiver/CMakeLists.txt +++ b/lib/receiver/CMakeLists.txt @@ -23,4 +23,5 @@ add_sources( receiver_config.cc receiver_impl.cc viterbi_detector.cc + time_sample_ref.cc ) diff --git a/lib/receiver/clock_offset_control_impl.cc b/lib/receiver/clock_offset_control_impl.cc index 868cbc2..d62c801 100644 --- a/lib/receiver/clock_offset_control_impl.cc +++ b/lib/receiver/clock_offset_control_impl.cc @@ -25,7 +25,7 @@ #endif #include <sch.h> -#include <gsm_constants.h> +#include <grgsm/gsm_constants.h> #include "clock_offset_control_impl.h" namespace gr diff --git a/lib/receiver/gsm_constants.h b/lib/receiver/gsm_constants.h deleted file mode 100644 index 9052290..0000000 --- a/lib/receiver/gsm_constants.h +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- c++ -*- */ -/* - * @file - * @author (C) 2014 by Piotr Krysik <ptrkrysik@gmail.com> - * @section LICENSE - * - * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GSM_CONSTANTS_H -#define INCLUDED_GSM_CONSTANTS_H - -#define GSM_SYMBOL_RATE (1625000.0/6.0) //symbols per second -#define GSM_SYMBOL_PERIOD (1.0/GSM_SYMBOL_RATE) //seconds per symbol - -//Burst timing -#define TAIL_BITS 3 -#define GUARD_BITS 8 -#define GUARD_FRACTIONAL 0.25 //fractional part of guard period -#define GUARD_PERIOD GUARD_BITS + GUARD_FRACTIONAL -#define DATA_BITS 57 //size of 1 data block in normal burst -#define STEALING_BIT 1 -#define N_TRAIN_BITS 26 -#define N_SYNC_BITS 64 -#define USEFUL_BITS 142 //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS ) -#define FCCH_BITS USEFUL_BITS -#define BURST_SIZE (USEFUL_BITS+2*TAIL_BITS) -#define PROCESSED_CHUNK BURST_SIZE+2*GUARD_PERIOD - -#define SCH_DATA_LEN 39 -#define TS_BITS (TAIL_BITS+USEFUL_BITS+TAIL_BITS+GUARD_BITS) //a full TS (156 bits) -#define TS_PER_FRAME 8 -#define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // 156.25 * 8 -#define FCCH_POS TAIL_BITS -#define SYNC_POS 39 -#define TRAIN_POS ( TAIL_BITS + (DATA_BITS+STEALING_BIT) + 5) //first 5 bits of a training sequence - //aren't used for channel impulse response estimation -#define TRAIN_BEGINNING 5 -#define SAFETY_MARGIN 6 // - -#define FCCH_HITS_NEEDED (USEFUL_BITS - 4) -#define FCCH_MAX_MISSES 1 -#define FCCH_MAX_FREQ_OFFSET 100 - -#define CHAN_IMP_RESP_LENGTH 5 - -#define MAX_SCH_ERRORS 10 //maximum number of subsequent sch errors after which gsm receiver goes to find_next_fcch state - -typedef enum {empty, fcch_burst, sch_burst, normal_burst, rach_burst, dummy, dummy_or_normal, normal_or_noise} burst_type; -typedef enum {unknown, multiframe_26, multiframe_51} multiframe_type; - -static const unsigned char SYNC_BITS[] = { - 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, - 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1 -}; - -const unsigned FCCH_FRAMES[] = {0, 10, 20, 30, 40}; -const unsigned SCH_FRAMES[] = {1, 11, 21, 31, 41}; - -const unsigned BCCH_FRAMES[] = {2, 3, 4, 5}; //!!the receiver shouldn't care about logical - //!!channels so this will be removed from this header -const unsigned TEST_CCH_FRAMES[] = {2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47, 48, 49}; -const unsigned TRAFFIC_CHANNEL_F[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; -const unsigned TEST51[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}; - - -#define TSC0 0 -#define TSC1 1 -#define TSC2 2 -#define TSC3 3 -#define TSC4 4 -#define TSC5 5 -#define TSC6 6 -#define TSC7 7 -#define TS_DUMMY 8 - -#define TRAIN_SEQ_NUM 9 - -#define TIMESLOT0 0 -#define TIMESLOT1 1 -#define TIMESLOT2 2 -#define TIMESLOT3 3 -#define TIMESLOT4 4 -#define TIMESLOT5 5 -#define TIMESLOT6 6 -#define TIMESLOT7 7 - - -static const unsigned char train_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS] = { - {0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1}, - {0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1}, - {0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0}, - {0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0}, - {0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1}, - {0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0}, - {1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1}, - {1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0}, - {0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1} // DUMMY -}; - - -//Dummy burst 0xFB 76 0A 4E 09 10 1F 1C 5C 5C 57 4A 33 39 E9 F1 2F A8 -static const unsigned char dummy_burst[] = { - 0, 0, 0, - 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, - 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, - 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 0, 0, - - 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, - 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, - 0, 0, 0, 1, 0, 1, - - 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, - 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, - 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 0, 1, 0, - 0, 0, 0 -}; - - -/* - * The frequency correction burst is used for frequency synchronization - * of the mobile. This is broadcast in TS0 together with the SCH and - * BCCH. - * - * Modulating the bits below causes a spike at 62.5kHz above (below for - * COMPACT) the center frequency. One can use this spike with a narrow - * band filter to accurately determine the center of the channel. - */ -static const unsigned char fc_fb[] = { - 0, 0, 0, //I don't use this tables, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //I copied this here from burst_types.h because - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //the description is very informative - p.krysik - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 -}; - -static const unsigned char fc_compact_fb[] = { - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 -}; - - -#endif /* INCLUDED_GSM_CONSTANTS_H */ diff --git a/lib/receiver/receiver_config.h b/lib/receiver/receiver_config.h index 6ad43a1..b3c0f49 100644 --- a/lib/receiver/receiver_config.h +++ b/lib/receiver/receiver_config.h @@ -25,7 +25,7 @@ #include <vector> #include <algorithm> #include <stdint.h> -#include <gsm_constants.h> +#include <grgsm/gsm_constants.h> class multiframe_configuration { diff --git a/lib/receiver/receiver_impl.cc b/lib/receiver/receiver_impl.cc index c7626b5..ffaf9ee 100644 --- a/lib/receiver/receiver_impl.cc +++ b/lib/receiver/receiver_impl.cc @@ -73,10 +73,13 @@ namespace gr ) : gr::sync_block("receiver", gr::io_signature::make(1, -1, sizeof(gr_complex)), gr::io_signature::make(0, 0, 0)), + d_samples_consumed(0), + d_rx_time_received(false), + d_time_samp_ref(GSM_SYMBOL_RATE * osr), d_OSR(osr), d_process_uplink(process_uplink), d_chan_imp_length(CHAN_IMP_RESP_LENGTH), - d_counter(0), + d_counter(0), //TODO: use nitems_read instead of d_counter d_fcch_start_pos(0), d_freq_offset_setting(0), d_state(fcch_search), @@ -174,8 +177,13 @@ namespace gr d_freq_offset_tag_in_fcch = tag_offset < last_sample_nr; } } + + /* Obtaining current time with use of rx_time tag provided i.e. by UHD devices */ + /* And storing it in time_sample_ref for sample number to time conversion */ + std::vector<tag_t> rx_time_tags; /* Main state machine */ + d_samples_consumed = 0; switch (d_state) { case fcch_search: fcch_search_handler(input, noutput_items); @@ -188,7 +196,20 @@ namespace gr break; } - return 0; + get_tags_in_window(rx_time_tags, 0, 0, d_samples_consumed, pmt::string_to_symbol("rx_time")); + if(!rx_time_tags.empty()){ + d_rx_time_received = true; + tag_t rx_time_tag = *(rx_time_tags.begin()); + + uint64_t rx_time_full_part = to_uint64(tuple_ref(rx_time_tag.value,0)); + double rx_time_frac_part = to_double(tuple_ref(rx_time_tag.value,1)); + + time_spec_t current_rx_time = time_spec_t(rx_time_full_part, rx_time_frac_part); + uint64_t current_start_offset = rx_time_tag.offset; + d_time_samp_ref.update(current_rx_time, current_start_offset); + } + + return d_samples_consumed; } void @@ -248,7 +269,9 @@ namespace gr d_burst_nr++; /* Consume samples up to the next guard period */ - consume_each(burst_start + BURST_SIZE * d_OSR + 4 * d_OSR); + unsigned int to_consume = burst_start + BURST_SIZE * d_OSR + 4 * d_OSR; +// consume_each(to_consume); + d_samples_consumed += to_consume; /* Update current state */ d_state = synchronized; @@ -320,7 +343,7 @@ namespace gr case sch_burst: { - int d_ncc, d_bcc; + int ncc, bcc; int t1, t2, t3; int rc; @@ -332,12 +355,8 @@ namespace gr detect_burst(input, &channel_imp_resp[0], d_c0_burst_start, output_binary); - /* Compose a message with GSMTAP header and bits */ - send_burst(d_burst_nr, output_binary, - GSMTAP_BURST_SCH, input_nr); - /* Attempt to decode SCH burst */ - rc = decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc); + rc = decode_sch(&output_binary[3], &t1, &t2, &t3, &ncc, &bcc); if (rc) { if (++d_failed_sch >= MAX_SCH_ERRORS) { /* We have to resynchronize, change state */ @@ -352,6 +371,10 @@ namespace gr break; } + /* Compose a message with GSMTAP header and bits */ + send_burst(d_burst_nr, output_binary, + GSMTAP_BURST_SCH, input_nr, d_c0_burst_start); + /** * Decoding was successful, now * compute offset from burst_start, @@ -380,7 +403,7 @@ namespace gr /* Compose a message with GSMTAP header and bits */ send_burst(d_burst_nr, output_binary, - GSMTAP_BURST_NORMAL, input_nr); + GSMTAP_BURST_NORMAL, input_nr, d_c0_burst_start); break; } @@ -404,13 +427,13 @@ namespace gr /* Compose a message with GSMTAP header and bits */ send_burst(d_burst_nr, output_binary, - GSMTAP_BURST_NORMAL, input_nr); + GSMTAP_BURST_NORMAL, input_nr, normal_burst_start); } else { d_c0_burst_start = dummy_burst_start; /* Compose a message with GSMTAP header and bits */ send_burst(d_burst_nr, dummy_burst, - GSMTAP_BURST_DUMMY, input_nr); + GSMTAP_BURST_DUMMY, input_nr, dummy_burst_start); } break; @@ -462,7 +485,7 @@ namespace gr burst_start, output_binary); /* Compose a message with GSMTAP header and bits */ - send_burst(d_burst_nr, output_binary, GSMTAP_BURST_NORMAL, input_nr); + send_burst(d_burst_nr, output_binary, GSMTAP_BURST_NORMAL, input_nr, burst_start); break; } @@ -483,7 +506,8 @@ namespace gr /* Consume samples of the burst up to next guard period */ to_consume += TS_BITS * d_OSR + d_burst_nr.get_offset(); - consume_each(to_consume); +// consume_each(to_consume); + d_samples_consumed += to_consume; } } } @@ -674,7 +698,8 @@ namespace gr } d_counter += to_consume; - consume_each(to_consume); +// consume_each(to_consume); + d_samples_consumed += to_consume; return result; } @@ -725,7 +750,8 @@ namespace gr } d_counter += to_consume; - consume_each(to_consume); +// consume_each(to_consume); + d_samples_consumed += to_consume; return result; } @@ -979,7 +1005,7 @@ namespace gr void receiver_impl::send_burst(burst_counter burst_nr, const unsigned char * burst_binary, uint8_t burst_type, - size_t input_nr) + size_t input_nr, unsigned int burst_start) { /* Buffer for GSMTAP header and burst */ uint8_t buf[sizeof(gsmtap_hdr) + BURST_SIZE]; @@ -1018,12 +1044,26 @@ namespace gr tap_header->signal_dbm = static_cast<int8_t>(d_signal_dbm); tap_header->snr_db = 0; /* FIXME: Can we calculate this? */ + pmt::pmt_t pdu_header = pmt::make_dict(); + + /* Add timestamp of the first sample - if available */ + if(d_rx_time_received) { + time_spec_t time_spec_of_first_sample = d_time_samp_ref.offset_to_time(nitems_read(0)+burst_start); + uint64_t full = time_spec_of_first_sample.get_full_secs(); + double frac = time_spec_of_first_sample.get_frac_secs(); + pdu_header = + pmt::dict_add(pdu_header, pmt::mp("fn_time"), + pmt::cons( + pmt::cons(pmt::from_uint64(be32toh(frame_number)), pmt::from_uint64(tn)), + pmt::cons(pmt::from_uint64(full), pmt::from_double(frac)))); + } + /* Copy burst to the buffer */ memcpy(burst, burst_binary, BURST_SIZE); /* Allocate a new message */ pmt::pmt_t blob = pmt::make_blob(buf, sizeof(gsmtap_hdr) + BURST_SIZE); - pmt::pmt_t msg = pmt::cons(pmt::PMT_NIL, blob); + pmt::pmt_t msg = pmt::cons(pdu_header, blob); /* Send message */ if (input_nr == 0) @@ -1092,6 +1132,5 @@ namespace gr { d_state = fcch_search; } - } /* namespace gsm */ } /* namespace gr */ diff --git a/lib/receiver/receiver_impl.h b/lib/receiver/receiver_impl.h index 0b032db..b880837 100644 --- a/lib/receiver/receiver_impl.h +++ b/lib/receiver/receiver_impl.h @@ -25,16 +25,20 @@ #include <grgsm/receiver/receiver.h> #include <grgsm/gsmtap.h> -#include <gsm_constants.h> +#include <grgsm/gsm_constants.h> #include <receiver_config.h> #include <vector> +#include "time_sample_ref.h" namespace gr { namespace gsm { class receiver_impl : public receiver { private: - unsigned int d_c0_burst_start; + unsigned int d_samples_consumed; + bool d_rx_time_received; + time_sample_ref d_time_samp_ref; + int d_c0_burst_start; float d_c0_signal_dbm; /**@name Configuration of the receiver */ @@ -195,7 +199,7 @@ namespace gr { * @param burst_binary - content of the burst * @b_type - type of the burst */ - void send_burst(burst_counter burst_nr, const unsigned char * burst_binary, uint8_t burst_type, size_t input_nr); + void send_burst(burst_counter burst_nr, const unsigned char * burst_binary, uint8_t burst_type, size_t input_nr, unsigned int burst_start=-1); /** * Configures burst types in different channels @@ -209,13 +213,13 @@ namespace gr { gr_vector_const_void_star &input_items, int noutput_items); public: - receiver_impl(int osr, const std::vector<int> &cell_allocation, const std::vector<int> &tseq_nums, bool process_uplink); - ~receiver_impl(); + receiver_impl(int osr, const std::vector<int> &cell_allocation, const std::vector<int> &tseq_nums, bool process_uplink); + ~receiver_impl(); - int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); - virtual void set_cell_allocation(const std::vector<int> &cell_allocation); - virtual void set_tseq_nums(const std::vector<int> & tseq_nums); - virtual void reset(); + int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + virtual void set_cell_allocation(const std::vector<int> &cell_allocation); + virtual void set_tseq_nums(const std::vector<int> & tseq_nums); + virtual void reset(); }; } // namespace gsm } // namespace gr diff --git a/lib/receiver/time_sample_ref.cc b/lib/receiver/time_sample_ref.cc new file mode 100644 index 0000000..0cf85ed --- /dev/null +++ b/lib/receiver/time_sample_ref.cc @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * @file + * @author (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <math.h> +#include "time_sample_ref.h" + +namespace gr { + namespace gsm { + time_sample_ref::time_sample_ref(double samp_rate): d_samp_rate(samp_rate) + { + } + + time_sample_ref::~time_sample_ref() + { + } + + void time_sample_ref::update(time_spec_t last_rx_time, uint64_t current_start_offset) + { + d_last_rx_time = last_rx_time; + d_current_start_offset = current_start_offset; + } + + time_spec_t time_sample_ref::offset_to_time(uint64_t offset) + { + uint64_t samples_from_last_rx_time = offset - d_current_start_offset; + time_spec_t time = time_spec_t(static_cast<double>(samples_from_last_rx_time)/d_samp_rate) + d_last_rx_time; + + return time; + } + + uint64_t time_sample_ref::time_to_offset(time_spec_t time) + { + double samples_since_last_rx_time_tag = (time-d_last_rx_time).get_real_secs()*d_samp_rate; +// double fractional_part = round(samples_since_last_rx_time_tag) - samples_since_last_rx_time_tag; + uint64_t offset = static_cast<uint64_t>(round(samples_since_last_rx_time_tag)) + d_current_start_offset; + + return offset; + } + } // namespace gsm +} // namespace gr + diff --git a/lib/receiver/time_sample_ref.h b/lib/receiver/time_sample_ref.h new file mode 100644 index 0000000..793944d --- /dev/null +++ b/lib/receiver/time_sample_ref.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * @file + * @author (C) 2017 by Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_TIME_SAMPLE_REF_IMPL_H +#define INCLUDED_TIME_SAMPLE_REF_IMPL_H + +#include <stdint.h> +#include <grgsm/misc_utils/time_spec.h> + +namespace gr { + namespace gsm { + /* + Class for storing time reference and for conversions time<->sample number + */ + class time_sample_ref + { + private: + double d_samp_rate; + time_spec_t d_last_rx_time; + uint64_t d_current_start_offset; + public: + time_sample_ref(double samp_rate); + ~time_sample_ref(); + void update(time_spec_t last_rx_time, uint64_t current_start_offset); + time_spec_t offset_to_time(uint64_t offset); + uint64_t time_to_offset(time_spec_t time); + }; + } // namespace gsm +} // namespace gr +#endif// INCLUDED_TIME_SAMPLE_REF_IMPL_H diff --git a/lib/receiver/viterbi_detector.cc b/lib/receiver/viterbi_detector.cc index 6a64a2c..3dce379 100644 --- a/lib/receiver/viterbi_detector.cc +++ b/lib/receiver/viterbi_detector.cc @@ -56,7 +56,8 @@ */ #include <gnuradio/gr_complex.h> -#include <gsm_constants.h> +#include <grgsm/gsm_constants.h> +#include <cmath> #define PATHS_NUM (1 << (CHAN_IMP_RESP_LENGTH-1)) diff --git a/lib/transmitter/CMakeLists.txt b/lib/transmitter/CMakeLists.txt new file mode 100644 index 0000000..eb53162 --- /dev/null +++ b/lib/transmitter/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright 2011,2012 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. + +add_sources( + txtime_setter_impl.cc + preprocess_tx_burst_impl.cc + gen_test_ab_impl +) diff --git a/lib/transmitter/gen_test_ab_impl.cc b/lib/transmitter/gen_test_ab_impl.cc new file mode 100644 index 0000000..bb9c9f6 --- /dev/null +++ b/lib/transmitter/gen_test_ab_impl.cc @@ -0,0 +1,107 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; 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 <gnuradio/io_signature.h> +#include <grgsm/gsmtap.h> +#include <grgsm/gsm_constants.h> +#include "gen_test_ab_impl.h" + +namespace gr { + namespace gsm { + + static uint8_t rach_synch_seq[] = { + 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0 , + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, + }; + + static uint8_t AB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +// static uint8_t AB[] = {0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1}; +// static uint8_t AB[] = { 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; +// static uint8_t AB[] = {1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,1,0,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +// ,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + gen_test_ab::sptr + gen_test_ab::make() + { + return gnuradio::get_initial_sptr + (new gen_test_ab_impl()); + } + + /* + * The private constructor + */ + gen_test_ab_impl::gen_test_ab_impl() + : gr::block("gen_test_ab", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) + { + message_port_register_in(pmt::intern("bursts_in")); + message_port_register_out(pmt::intern("bursts_out")); + + set_msg_handler(pmt::intern("bursts_in"), boost::bind(&gen_test_ab_impl::generate_ab, this, _1)); + } + + /* + * Our virtual destructor. + */ + gen_test_ab_impl::~gen_test_ab_impl() + { + } + + void gen_test_ab_impl::generate_ab(pmt::pmt_t burst) + { + uint8_t buf[sizeof(gsmtap_hdr) + 148]; + struct gsmtap_hdr *tap_header = (struct gsmtap_hdr *) buf; + uint8_t *access_burst = buf + sizeof(gsmtap_hdr); + +// memset(access_burst, 0, 8); /* TB */ +// memcpy(access_burst + 8, rach_synch_seq, 41); /* sync seq */ +// memcpy(access_burst + 49, AB, 36); /* payload */ +// memset(access_burst + 85, 0, 63); /* TB + GP */ + + memcpy(access_burst, AB, 148); + + gsmtap_hdr * header = (gsmtap_hdr *)(pmt::blob_data(pmt::cdr(burst))); + uint32_t frame_nr = be32toh(header->frame_number); + frame_nr = (frame_nr+51)% (26*51*2048); + + tap_header->version = GSMTAP_VERSION; + tap_header->hdr_len = sizeof(gsmtap_hdr) / 4; + tap_header->type = GSMTAP_TYPE_UM_BURST; + tap_header->sub_type = GSMTAP_BURST_ACCESS; + tap_header->frame_number = htobe32(frame_nr); + tap_header->timeslot = header->timeslot; + tap_header->arfcn = 0; + + pmt::pmt_t blob = pmt::make_blob(buf, sizeof(gsmtap_hdr) + BURST_SIZE); + pmt::pmt_t pdu_header = pmt::make_dict(); + + pmt::pmt_t new_msg = pmt::cons(pdu_header, blob); + message_port_pub(pmt::intern("bursts_out"), new_msg); + } + } /* namespace gsm */ +} /* namespace gr */ + diff --git a/lib/transmitter/gen_test_ab_impl.h b/lib/transmitter/gen_test_ab_impl.h new file mode 100644 index 0000000..366481e --- /dev/null +++ b/lib/transmitter/gen_test_ab_impl.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef INCLUDED_GSM_GEN_TEST_AB_IMPL_H +#define INCLUDED_GSM_GEN_TEST_AB_IMPL_H + +#include <grgsm/transmitter/gen_test_ab.h> +#include <grgsm/misc_utils/time_spec.h> +#include <grgsm/misc_utils/fn_time.h> + +namespace gr { + namespace gsm { + + class gen_test_ab_impl : public gen_test_ab + { + private: + void generate_ab(pmt::pmt_t burst); + + public: + gen_test_ab_impl(); + ~gen_test_ab_impl(); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_GEN_TEST_AB_IMPL_H */ + diff --git a/lib/transmitter/preprocess_tx_burst_impl.cc b/lib/transmitter/preprocess_tx_burst_impl.cc new file mode 100644 index 0000000..5fbac98 --- /dev/null +++ b/lib/transmitter/preprocess_tx_burst_impl.cc @@ -0,0 +1,96 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @author Vadim Yanitskiy <axilirator@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; 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 <assert.h> + +#include <gnuradio/io_signature.h> +#include <grgsm/gsm_constants.h> +#include <grgsm/gsmtap.h> + +#include "preprocess_tx_burst_impl.h" + +namespace gr { + namespace gsm { + + preprocess_tx_burst::sptr + preprocess_tx_burst::make() + { + return gnuradio::get_initial_sptr + (new preprocess_tx_burst_impl()); + } + + /* + * The private constructor + */ + preprocess_tx_burst_impl::preprocess_tx_burst_impl() + : gr::block("preprocess_tx_burst", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) + { + message_port_register_in(pmt::mp("bursts_in")); + message_port_register_out(pmt::mp("bursts_out")); + + set_msg_handler(pmt::mp("bursts_in"), + boost::bind(&preprocess_tx_burst_impl::process_burst, this, _1)); + } + + /* + * Our virtual destructor. + */ + preprocess_tx_burst_impl::~preprocess_tx_burst_impl() + { + } + + void preprocess_tx_burst_impl::process_burst(pmt::pmt_t msg_in) + { + pmt::pmt_t blob_in = pmt::cdr(msg_in); + + // Extract GSMTAP header from message + gsmtap_hdr *burst_hdr = (gsmtap_hdr *) pmt::blob_data(blob_in); + + // Extract burst bits from message + uint8_t *burst_bits = (uint8_t *) + (pmt::blob_data(blob_in)) + sizeof(gsmtap_hdr); + + // Determine and check burst length + size_t burst_len = pmt::blob_length(blob_in) - sizeof(gsmtap_hdr); + assert(burst_len == BURST_SIZE); + + // The Access Burst last has reduced length + if (burst_hdr->sub_type == GSMTAP_BURST_ACCESS) + burst_len = ACCESS_BURST_SIZE; + + // Prepare an output message + pmt::pmt_t blob_out = pmt::make_blob(burst_bits, burst_len); + pmt::pmt_t msg_out = pmt::cons(pmt::car(msg_in), blob_out); + + /* Send a message to the output */ + message_port_pub(pmt::mp("bursts_out"), msg_out); + } + + } /* namespace gsm */ +} /* namespace gr */ diff --git a/lib/transmitter/preprocess_tx_burst_impl.h b/lib/transmitter/preprocess_tx_burst_impl.h new file mode 100644 index 0000000..27fc508 --- /dev/null +++ b/lib/transmitter/preprocess_tx_burst_impl.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef INCLUDED_GSM_PREPROCESS_TX_BURST_IMPL_H +#define INCLUDED_GSM_PREPROCESS_TX_BURST_IMPL_H + +#include <grgsm/transmitter/preprocess_tx_burst.h> +#include <grgsm/misc_utils/time_spec.h> +#include <grgsm/misc_utils/fn_time.h> + +namespace gr { + namespace gsm { + + class preprocess_tx_burst_impl : public preprocess_tx_burst + { + private: + void process_burst(pmt::pmt_t burst); + + public: + preprocess_tx_burst_impl(); + ~preprocess_tx_burst_impl(); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_PREPROCESS_TX_BURST_IMPL_H */ + diff --git a/lib/transmitter/txtime_setter_impl.cc b/lib/transmitter/txtime_setter_impl.cc new file mode 100644 index 0000000..33bc994 --- /dev/null +++ b/lib/transmitter/txtime_setter_impl.cc @@ -0,0 +1,196 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @author Vadim Yanitskiy <axilirator@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; 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 <gnuradio/io_signature.h> +#include <grgsm/gsmtap.h> + +#include "txtime_setter_impl.h" + +#define UNKNOWN_FN 0xffffffff +#define MAX_EARLY_TIME_DIFF 10.0 + +namespace gr { + namespace gsm { + + txtime_setter::sptr + txtime_setter::make( + uint32_t init_fn, uint64_t init_time_secs, + double init_time_fracs, uint64_t time_hint_secs, + double time_hint_fracs, double timing_advance, + double delay_correction) + { + return gnuradio::get_initial_sptr + (new txtime_setter_impl(init_fn, init_time_secs, + init_time_fracs, time_hint_secs, time_hint_fracs, + timing_advance, delay_correction)); + } + + /* + * The private constructor + */ + txtime_setter_impl::txtime_setter_impl( + uint32_t init_fn, uint64_t init_time_secs, + double init_time_fracs, uint64_t time_hint_secs, + double time_hint_fracs, double timing_advance, + double delay_correction + ) : gr::block("txtime_setter", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_time_hint(time_hint_secs,time_hint_fracs), + d_time_ref(init_time_secs,init_time_fracs), + d_delay_correction(delay_correction), + d_timing_advance(timing_advance), + d_fn_ref(init_fn), + d_ts_ref(0) + { + // Register I/O ports + message_port_register_in(pmt::mp("fn_time")); + message_port_register_in(pmt::mp("bursts_in")); + message_port_register_out(pmt::mp("bursts_out")); + + // Bind message handlers + set_msg_handler(pmt::mp("fn_time"), + boost::bind(&txtime_setter_impl::process_fn_time_reference, + this, _1)); + set_msg_handler(pmt::mp("bursts_in"), + boost::bind(&txtime_setter_impl::process_txtime_of_burst, + this, _1)); + } + + /* + * Our virtual destructor. + */ + txtime_setter_impl::~txtime_setter_impl() + { + } + + void txtime_setter_impl::process_fn_time_reference(pmt::pmt_t msg) + { + pmt::pmt_t not_found = pmt::intern("not_found"); + pmt::pmt_t fn_time, time_hint; + + fn_time = pmt::dict_ref(msg, + pmt::intern("fn_time"), not_found); + time_hint = pmt::dict_ref(msg, + pmt::intern("fn_time"), not_found); + + if (fn_time != not_found) { + uint32_t fn_ref = static_cast<uint32_t> + (pmt::to_uint64(pmt::car(pmt::car(fn_time)))); + uint32_t ts = static_cast<uint32_t> + (pmt::to_uint64(pmt::cdr(pmt::car(fn_time)))); + uint64_t time_secs = pmt::to_uint64( + pmt::car(pmt::cdr(fn_time))); + double time_fracs = pmt::to_double( + pmt::cdr(pmt::cdr(fn_time))); + + set_fn_time_reference(fn_ref, ts, time_secs, time_fracs); + } else if (time_hint != not_found) { + set_time_hint(pmt::to_uint64(pmt::car(fn_time)), + pmt::to_double(pmt::cdr(fn_time))); + } + } + + void txtime_setter_impl::process_txtime_of_burst(pmt::pmt_t msg_in) + { + if (d_fn_ref != UNKNOWN_FN) + { + pmt::pmt_t blob = pmt::cdr(msg_in); + + // Extract GSMTAP header from message + gsmtap_hdr *header = (gsmtap_hdr *) pmt::blob_data(blob); + uint32_t frame_nr = be32toh(header->frame_number); + uint32_t ts_num = header->timeslot; + + time_format txtime = fn_time_delta_cpp(d_fn_ref, d_time_ref, + frame_nr, d_time_hint, ts_num, d_ts_ref); + + time_spec_t txtime_spec = time_spec_t(txtime.first, txtime.second); + txtime_spec -= d_delay_correction; + txtime_spec -= d_timing_advance; + + time_spec_t current_time_estimate = time_spec_t(d_time_hint.first, d_time_hint.second); + + if (txtime_spec <= current_time_estimate) { // Drop too late bursts + std::cout << "lB" << std::flush; + } else if (txtime_spec > current_time_estimate + MAX_EARLY_TIME_DIFF) { // Drop too early bursts + std::cout << "eB" << std::flush; //TODO: too early condition might happen when changing BTSes. + //Wrong fn_time is applied to new or old bursts in such situation. + //This solution is not perfect as MS might be blocked upto + //MAX_EARLY_TIME_DIFF seconds. + //Better solution would be to indentify fn_time and burst coming + //from given BTS (i.e. based on ARFCN) and dropping bursts for which + //the bts_id doesn't match with bts_id of fn_time. + } else { //process bursts that are in the right time-frame + pmt::pmt_t tags_dict = pmt::dict_add( + pmt::make_dict(), + pmt::intern("tx_time"), + pmt::make_tuple( + pmt::from_uint64(txtime_spec.get_full_secs()), + pmt::from_double(txtime_spec.get_frac_secs())) + ); + + tags_dict = pmt::dict_add(tags_dict, + pmt::intern("fn"), pmt::from_uint64(frame_nr)); + tags_dict = pmt::dict_add(tags_dict, + pmt::intern("ts"), pmt::from_uint64(ts_num)); + + // Send a message to the output + pmt::pmt_t msg_out = pmt::cons(tags_dict, pmt::cdr(msg_in)); + message_port_pub(pmt::mp("bursts_out"), msg_out); + } + } + } + + void txtime_setter_impl::set_fn_time_reference( + uint32_t fn, uint32_t ts, uint64_t time_secs, + double time_fracs) + { + d_fn_ref = fn; + d_ts_ref = ts; + d_time_ref = std::make_pair(time_secs, time_fracs); + set_time_hint(time_secs, time_fracs); + } + + void txtime_setter_impl::set_time_hint( + uint64_t time_hint_secs, double time_hint_fracs) + { + d_time_hint = std::make_pair(time_hint_secs, time_hint_fracs); + } + + void txtime_setter_impl::set_delay_correction(double delay_correction) + { + d_delay_correction = delay_correction; + } + + void txtime_setter_impl::set_timing_advance(double timing_advance) + { + d_timing_advance = timing_advance; + } + + } /* namespace gsm */ +} /* namespace gr */ diff --git a/lib/transmitter/txtime_setter_impl.h b/lib/transmitter/txtime_setter_impl.h new file mode 100644 index 0000000..62f500a --- /dev/null +++ b/lib/transmitter/txtime_setter_impl.h @@ -0,0 +1,64 @@ +/* -*- c++ -*- */ +/* @file + * @author Piotr Krysik <ptrkrysik@gmail.com> + * @section LICENSE + * + * Gr-gsm 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-gsm 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-gsm; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef INCLUDED_GSM_TXTIME_SETTER_IMPL_H +#define INCLUDED_GSM_TXTIME_SETTER_IMPL_H + +#include <grgsm/transmitter/txtime_setter.h> +#include <grgsm/misc_utils/time_spec.h> +#include <grgsm/misc_utils/fn_time.h> + +namespace gr { + namespace gsm { + + class txtime_setter_impl : public txtime_setter + { + private: + uint32_t d_fn_ref; + uint32_t d_ts_ref; + time_format d_time_ref; + time_format d_time_hint; + double d_timing_advance; + double d_delay_correction; + + void process_fn_time_reference(pmt::pmt_t msg); + void process_txtime_of_burst(pmt::pmt_t msg); + + public: + txtime_setter_impl(uint32_t init_fn, uint64_t init_time_secs, + double init_time_fracs, uint64_t time_hint_secs, + double time_hint_fracs, double timing_advance, + double delay_correction); + ~txtime_setter_impl(); + + // Where all the action really happens + void set_fn_time_reference(uint32_t fn, uint32_t ts, + uint64_t time_secs, double time_fracs); + void set_time_hint(uint64_t time_hint_secs, double time_hint_fracs); + void set_delay_correction(double delay_correction); + void set_timing_advance(double timing_advance); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_TXTIME_SETTER_IMPL_H */ |