diff options
author | Piotr Krysik <ptrkrysik@gmail.com> | 2017-09-12 11:45:20 +0200 |
---|---|---|
committer | Piotr Krysik <ptrkrysik@gmail.com> | 2017-09-12 11:45:20 +0200 |
commit | e6e787959f51f280a78a2dc7bd7d1c16b11f8fa9 (patch) | |
tree | 55fb27eda2931f318450f72fd89dd7e0d2a16a9f /lib | |
parent | 45b87000728ac61c086e70f78fb1f638f026fd4b (diff) | |
parent | 76e4b334535223a07c0a8d93186a046b7d9818cb (diff) |
Merge branch 'fixeria/trx' into development
# Conflicts:
# swig/grgsm_swig.i
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/trx_interface/trx_impl.cc | 273 | ||||
-rw-r--r-- | lib/trx_interface/trx_impl.h | 61 | ||||
-rw-r--r-- | lib/trx_interface/udp_socket.cc | 119 | ||||
-rw-r--r-- | lib/trx_interface/udp_socket.h | 69 |
5 files changed, 524 insertions, 0 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9880e58..7804e07 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -96,6 +96,8 @@ list(APPEND grgsm_sources qa_utils/message_source_impl.cc qa_utils/message_sink_impl.cc decryption/decryption_impl.cc + trx_interface/udp_socket.cc + trx_interface/trx_impl.cc ) diff --git a/lib/trx_interface/trx_impl.cc b/lib/trx_interface/trx_impl.cc new file mode 100644 index 0000000..2068da3 --- /dev/null +++ b/lib/trx_interface/trx_impl.cc @@ -0,0 +1,273 @@ +/* -*- 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_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 grgsm { + + trx::sptr + trx::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_impl(remote_addr, base_port_int)); + } + + /* + * The private constructor + */ + trx_impl::trx_impl(const std::string &remote_addr, int base_port) + : gr::block("trx", + 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_impl::handle_dl_burst, this, _1)); + + // Prepare port numbers + std::string clck_src_port = boost::lexical_cast<std::string> (base_port + 0); + std::string clck_dst_port = boost::lexical_cast<std::string> (base_port + 100); + 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 & 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_impl::handle_ul_burst, this, _1, _2); + + // Init timeslot filter + d_ts_filter_tn = -1; + } + + /* + * Our virtual destructor. + */ + trx_impl::~trx_impl() + { + // Release all UDP sockets and free memory + delete d_data_sock; + delete d_clck_sock; + } + + /* + * Timeslot filter API (getter and setter) + */ + void + trx_impl::ts_filter_set_tn(int tn) + { + d_ts_filter_tn = (tn >= 0 && tn <= 7) ? tn : -1; + } + + int + trx_impl::ts_filter_get_tn(void) + { + return d_ts_filter_tn; + } + + /* + * Check if burst is a RACH burst + */ + bool trx_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_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_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_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_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 grgsm */ +} /* namespace gr */ diff --git a/lib/trx_interface/trx_impl.h b/lib/trx_interface/trx_impl.h new file mode 100644 index 0000000..19e4848 --- /dev/null +++ b/lib/trx_interface/trx_impl.h @@ -0,0 +1,61 @@ +/* -*- 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_IMPL_H +#define INCLUDED_GRGSM_TRX_IMPL_H + +#include <stddef.h> + +#include <grgsm/gsmtap.h> +#include <grgsm/trx_interface/trx.h> + +namespace gr { + namespace grgsm { + + class trx_impl : public trx + { + private: + udp_socket *d_data_sock; + udp_socket *d_clck_sock; + int d_ts_filter_tn; + + bool detect_rach(uint8_t *burst); + void clck_ind_send(uint32_t frame_nr); + void burst_pack(pmt::pmt_t msg, uint8_t *buf); + + public: + trx_impl(const std::string &remote_addr, int base_port); + ~trx_impl(); + + /* Timeslot filter API */ + void ts_filter_set_tn(int tn); + int ts_filter_get_tn(void); + + void handle_dl_burst(pmt::pmt_t msg); + void handle_ul_burst(uint8_t *payload, size_t len); + }; + + } // namespace grgsm +} // namespace gr + +#endif /* INCLUDED_GRGSM_TRX_IMPL_H */ + diff --git a/lib/trx_interface/udp_socket.cc b/lib/trx_interface/udp_socket.cc new file mode 100644 index 0000000..be4bb66 --- /dev/null +++ b/lib/trx_interface/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 grgsm { + + 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 blocks */ +}/* namespace gr */ diff --git a/lib/trx_interface/udp_socket.h b/lib/trx_interface/udp_socket.h new file mode 100644 index 0000000..5bcc42b --- /dev/null +++ b/lib/trx_interface/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 grgsm { + + 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 blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GRGSM_TRX_UDP_SOCKET_H */ |