From e601c366bd179f908d4f34da9fe535c2606cac32 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 17 Oct 2017 08:24:25 +0700 Subject: Refactor the 'TRX Burst Interface' block The following changes were made: - Both implementation and headers were merged with misc_utils - Fixed namespace mess: was gr::grgsm, became gr::gsm - More accurate class name was chosen: "trx_burst_if" --- lib/misc_utils/trx_burst_if_impl.cc | 275 ++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 lib/misc_utils/trx_burst_if_impl.cc (limited to 'lib/misc_utils/trx_burst_if_impl.cc') 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..432ad2f --- /dev/null +++ b/lib/misc_utils/trx_burst_if_impl.cc @@ -0,0 +1,275 @@ +/* -*- c++ -*- */ +/* @file + * @author Vadim Yanitskiy + * @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 +#include + +#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 (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 clck_src_port = boost::lexical_cast (base_port + 0); + std::string clck_dst_port = boost::lexical_cast (base_port + 100); + std::string data_src_port = boost::lexical_cast (base_port + 2); + std::string data_dst_port = boost::lexical_cast (base_port + 102); + + // Init DATA & CLCK interfaces + d_data_sock = new udp_socket(remote_addr, + data_src_port, data_dst_port, DATA_IF_MTU); + d_clck_sock = new udp_socket(remote_addr, + clck_src_port, clck_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); + + // Init timeslot filter + d_ts_filter_tn = -1; + } + + /* + * Our virtual destructor. + */ + trx_burst_if_impl::~trx_burst_if_impl() + { + // Release all UDP sockets and free memory + delete d_data_sock; + delete d_clck_sock; + } + + /* + * Timeslot filter API (getter and setter) + */ + void + trx_burst_if_impl::ts_filter_set_tn(int tn) + { + d_ts_filter_tn = (tn >= 0 && tn <= 7) ? tn : -1; + } + + int + trx_burst_if_impl::ts_filter_get_tn(void) + { + return d_ts_filter_tn; + } + + /* + * 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 clock indication + */ + void + trx_burst_if_impl::clck_ind_send(uint32_t frame_nr) + { + char buf[20]; + size_t n; + + n = snprintf(buf, 20, "IND CLOCK %u", frame_nr); + d_clck_sock->udp_send((uint8_t *) buf, n + 1); + } + + /* + * 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); + + // HACK: send clock indications every 51-th frame + if (frame_nr % 51 == 0) + clck_ind_send(frame_nr); + + // 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); + + // Timeslot filter + if (d_ts_filter_tn != -1 && buf[0] != d_ts_filter_tn) + return; + + // 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 */ -- cgit v1.2.3 From 6bac5746867d50cfffb0c2e2dd6498550ccb3fd7 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 17 Oct 2017 08:52:27 +0700 Subject: misc_utils/trx_burst_if: get rid of clock interface Clock indications are only required for BTS operation, while MS can obtain current frame number from the messages on DATA interface. --- lib/misc_utils/trx_burst_if_impl.cc | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'lib/misc_utils/trx_burst_if_impl.cc') diff --git a/lib/misc_utils/trx_burst_if_impl.cc b/lib/misc_utils/trx_burst_if_impl.cc index 432ad2f..6d63edf 100644 --- a/lib/misc_utils/trx_burst_if_impl.cc +++ b/lib/misc_utils/trx_burst_if_impl.cc @@ -75,16 +75,12 @@ namespace gr { boost::bind(&trx_burst_if_impl::handle_dl_burst, this, _1)); // Prepare port numbers - std::string clck_src_port = boost::lexical_cast (base_port + 0); - std::string clck_dst_port = boost::lexical_cast (base_port + 100); std::string data_src_port = boost::lexical_cast (base_port + 2); std::string data_dst_port = boost::lexical_cast (base_port + 102); - // Init DATA & CLCK interfaces + // Init DATA interface d_data_sock = new udp_socket(remote_addr, data_src_port, data_dst_port, DATA_IF_MTU); - d_clck_sock = new udp_socket(remote_addr, - clck_src_port, clck_dst_port, DATA_IF_MTU); // Bind DATA interface handler d_data_sock->udp_rx_handler = boost::bind( @@ -101,7 +97,6 @@ namespace gr { { // Release all UDP sockets and free memory delete d_data_sock; - delete d_clck_sock; } /* @@ -137,19 +132,6 @@ namespace gr { return true; } - /* - * Create an UDP payload with clock indication - */ - void - trx_burst_if_impl::clck_ind_send(uint32_t frame_nr) - { - char buf[20]; - size_t n; - - n = snprintf(buf, 20, "IND CLOCK %u", frame_nr); - d_clck_sock->udp_send((uint8_t *) buf, n + 1); - } - /* * Create an UDP payload with burst bits * and some channel data. @@ -169,10 +151,6 @@ namespace gr { // Extract frame number uint32_t frame_nr = be32toh(header->frame_number); - // HACK: send clock indications every 51-th frame - if (frame_nr % 51 == 0) - clck_ind_send(frame_nr); - // Pack frame number buf[1] = (frame_nr >> 24) & 0xff; buf[2] = (frame_nr >> 16) & 0xff; -- cgit v1.2.3 From 962e2d83bb0eb62e6d1222339977c2f5f23d0dbd Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 17 Oct 2017 09:24:55 +0700 Subject: misc_utils/trx_burst_if: get rid of built-in timeslot filter Since the API of 'Timeslot Filter' block was exposed, we can get rid of built-in timeslot filter and use the proper methods. --- lib/misc_utils/trx_burst_if_impl.cc | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'lib/misc_utils/trx_burst_if_impl.cc') diff --git a/lib/misc_utils/trx_burst_if_impl.cc b/lib/misc_utils/trx_burst_if_impl.cc index 6d63edf..8f458b0 100644 --- a/lib/misc_utils/trx_burst_if_impl.cc +++ b/lib/misc_utils/trx_burst_if_impl.cc @@ -85,9 +85,6 @@ namespace gr { // Bind DATA interface handler d_data_sock->udp_rx_handler = boost::bind( &trx_burst_if_impl::handle_ul_burst, this, _1, _2); - - // Init timeslot filter - d_ts_filter_tn = -1; } /* @@ -99,21 +96,6 @@ namespace gr { delete d_data_sock; } - /* - * Timeslot filter API (getter and setter) - */ - void - trx_burst_if_impl::ts_filter_set_tn(int tn) - { - d_ts_filter_tn = (tn >= 0 && tn <= 7) ? tn : -1; - } - - int - trx_burst_if_impl::ts_filter_get_tn(void) - { - return d_ts_filter_tn; - } - /* * Check if burst is a RACH burst */ @@ -190,10 +172,6 @@ namespace gr { // Compose a new UDP payload with burst burst_pack(msg, buf); - // Timeslot filter - if (d_ts_filter_tn != -1 && buf[0] != d_ts_filter_tn) - return; - // Send a burst d_data_sock->udp_send(buf, 158); } -- cgit v1.2.3