/* -*- 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 "grgsm/endian.h" #include "grgsm/misc_utils/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 &bind_addr, 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(bind_addr, remote_addr, base_port_int)); } /* * The private constructor */ trx_burst_if_impl::trx_burst_if_impl( const std::string &bind_addr, 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 (base_port + 2); std::string data_dst_port = boost::lexical_cast (base_port + 102); // Init DATA interface d_data_sock = new udp_socket(bind_addr, data_src_port, remote_addr, 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 */