blob: 994c92bda465cd8dae1eb7a789c45c528275dabb [file] [log] [blame]
piotrdda22272014-08-04 11:31:54 +02001/* -*- c++ -*- */
ptrkrysik529895b2014-12-02 18:07:38 +01002/*
3 * @file
4 * @author Piotr Krysik <ptrkrysik@gmail.com>
5 * @section LICENSE
6 *
7 * Gr-gsm is free software; you can redistribute it and/or modify
piotrdda22272014-08-04 11:31:54 +02008 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
ptrkrysik529895b2014-12-02 18:07:38 +010011 *
12 * Gr-gsm is distributed in the hope that it will be useful,
piotrdda22272014-08-04 11:31:54 +020013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
ptrkrysik529895b2014-12-02 18:07:38 +010016 *
piotrdda22272014-08-04 11:31:54 +020017 * You should have received a copy of the GNU General Public License
ptrkrysik529895b2014-12-02 18:07:38 +010018 * along with gr-gsm; see the file COPYING. If not, write to
piotrdda22272014-08-04 11:31:54 +020019 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <gnuradio/io_signature.h>
ptrkrysik3be74a72014-12-13 10:11:00 +010028#include <grgsm/gsmtap.h>
ptrkrysik402c1fa2014-12-03 22:09:29 +010029#include <unistd.h>
ptrkrysike9539c12015-07-06 08:34:22 +020030#include <map>
piotrdda22272014-08-04 11:31:54 +020031#include <iterator>
32#include <algorithm>
piotrdda22272014-08-04 11:31:54 +020033#include <iostream>
David Holm41b63f22015-08-22 16:52:42 +020034#include <grgsm/endian.h>
ptrkrysike9539c12015-07-06 08:34:22 +020035#include <boost/foreach.hpp>
ptrkrysik09405382015-08-02 22:02:52 +020036extern "C" {
37 #include <osmocom/gsm/gsm48_ie.h>
38}
39
piotrdda22272014-08-04 11:31:54 +020040
ptrkrysik402c1fa2014-12-03 22:09:29 +010041#include "extract_system_info_impl.h"
42
piotrdda22272014-08-04 11:31:54 +020043namespace gr {
44 namespace gsm {
45 boost::mutex extract_mutex;
46 void extract_system_info_impl::process_bursts(pmt::pmt_t msg)
47 {
ptrkrysika31a4812014-12-15 09:10:01 +010048 pmt::pmt_t burst_plus_header_blob = pmt::cdr(msg);
49 gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(burst_plus_header_blob);
piotrdda22272014-08-04 11:31:54 +020050
piotrdda22272014-08-04 11:31:54 +020051 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020052 info.id = be16toh(header->arfcn);
piotrdda22272014-08-04 11:31:54 +020053 info.pwr_db = header->signal_dbm;
piotrdda22272014-08-04 11:31:54 +020054
55 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020056
57 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
58 d_c0_channels[info.id].copy_nonzero_elements(info);
59 } else {
60 d_c0_channels[info.id] = info;
61 }
piotrdda22272014-08-04 11:31:54 +020062 }
63
64 void extract_system_info_impl::process_sysinfo(pmt::pmt_t msg){
ptrkrysika31a4812014-12-15 09:10:01 +010065 pmt::pmt_t message_plus_header_blob = pmt::cdr(msg);
66 uint8_t * message_plus_header = (uint8_t *)pmt::blob_data(message_plus_header_blob);
67 gsmtap_hdr * header = (gsmtap_hdr *)message_plus_header;
68 uint8_t * msg_elements = (uint8_t *)(message_plus_header+sizeof(gsmtap_hdr));
ptrkrysik09405382015-08-02 22:02:52 +020069 struct gsm_sysinfo_freq freq[1024];
piotrdda22272014-08-04 11:31:54 +020070
71 if(msg_elements[2]==0x1b){
piotrdda22272014-08-04 11:31:54 +020072 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020073 info.id = be16toh(header->arfcn); //take arfcn
piotrdda22272014-08-04 11:31:54 +020074 info.pwr_db = header->signal_dbm;
ptrkrysika31a4812014-12-15 09:10:01 +010075 info.cell_id = (msg_elements[3]<<8)+msg_elements[4]; //take cell id
76 info.lac = (msg_elements[8]<<8)+msg_elements[9]; //take lac
77 info.mnc = (msg_elements[7]>>4); //take mnc
piotrdda22272014-08-04 11:31:54 +020078 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020079 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
80 d_c0_channels[info.id].copy_nonzero_elements(info);
81 } else {
82 d_c0_channels[info.id] = info;
piotrdda22272014-08-04 11:31:54 +020083 }
piotrdda22272014-08-04 11:31:54 +020084 }
85 else if(msg_elements[2]==0x1c){
piotrdda22272014-08-04 11:31:54 +020086 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020087 info.id = be16toh(header->arfcn); //take arfcn
piotrdda22272014-08-04 11:31:54 +020088 info.pwr_db = header->signal_dbm;
ptrkrysike9539c12015-07-06 08:34:22 +020089 info.lac = (msg_elements[6]<<8)+msg_elements[7]; //take lac
90 info.mnc = (msg_elements[5]>>4); //take mnc
piotrdda22272014-08-04 11:31:54 +020091
piotrdda22272014-08-04 11:31:54 +020092 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020093 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
94 d_c0_channels[info.id].copy_nonzero_elements(info);
95 } else {
96 d_c0_channels[info.id] = info;
piotrdda22272014-08-04 11:31:54 +020097 }
ptrkrysik09405382015-08-02 22:02:52 +020098 }
99 else if(msg_elements[2]==0x1a){ //System Information Type 2
100 memset(freq, 0, sizeof(freq));
ptrkrysike9539c12015-07-06 08:34:22 +0200101 chan_info info;
102 info.id = be16toh(header->arfcn); //take arfcn
103 info.pwr_db = header->signal_dbm;
104 boost::mutex::scoped_lock lock(extract_mutex);
105 //read neighbour cells
ptrkrysik09405382015-08-02 22:02:52 +0200106 gsm48_decode_freq_list(freq, &msg_elements[3], 16, 0xce, 0x01);
ptrkrysik09405382015-08-02 22:02:52 +0200107
108 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
109 d_c0_channels[info.id].copy_nonzero_elements(info);
110 } else {
111 d_c0_channels[info.id] = info;
112 }
ptrkrysik5e376742015-08-06 10:02:04 +0200113
114 for(int arfcn=0; arfcn<sizeof(freq); arfcn++){
115 if(freq[arfcn].mask==0x01){
116 d_c0_channels[info.id].neighbour_cells.insert(arfcn);
117 }
118 }
ptrkrysik09405382015-08-02 22:02:52 +0200119 }
120 else if(msg_elements[2]==0x02){ //System Information Type 2bis
121 memset(freq, 0, sizeof(freq));
122 chan_info info;
123 info.id = be16toh(header->arfcn); //take arfcn
124 info.pwr_db = header->signal_dbm;
125 boost::mutex::scoped_lock lock(extract_mutex);
126 //read neighbour cells
127 gsm48_decode_freq_list(freq, &msg_elements[3], 16, 0xce, 0x01);
ptrkrysik09405382015-08-02 22:02:52 +0200128 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
129 d_c0_channels[info.id].copy_nonzero_elements(info);
130 } else {
131 d_c0_channels[info.id] = info;
132 }
ptrkrysik5e376742015-08-06 10:02:04 +0200133
134 for(int arfcn=0; arfcn<sizeof(freq); arfcn++){
135 if(freq[arfcn].mask==0x01){
136 d_c0_channels[info.id].neighbour_cells.insert(arfcn);
137 }
138 }
ptrkrysik09405382015-08-02 22:02:52 +0200139 }
140 else if(msg_elements[2]==0x03){ //System Information Type 2ter
141 memset(freq, 0, sizeof(freq));
142 chan_info info;
143 info.id = be16toh(header->arfcn); //take arfcn
144 info.pwr_db = header->signal_dbm;
145 boost::mutex::scoped_lock lock(extract_mutex);
146 //read neighbour cells
147 gsm48_decode_freq_list(freq, &msg_elements[3], 16, 0x8e, 0x01);
ptrkrysike9539c12015-07-06 08:34:22 +0200148 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
149 d_c0_channels[info.id].copy_nonzero_elements(info);
150 } else {
151 d_c0_channels[info.id] = info;
152 }
ptrkrysik5e376742015-08-06 10:02:04 +0200153
154 for(int arfcn=0; arfcn<sizeof(freq); arfcn++){
155 if(freq[arfcn].mask==0x01){
156 d_c0_channels[info.id].neighbour_cells.insert(arfcn);
157 }
158 }
piotrdda22272014-08-04 11:31:54 +0200159 }
160 }
161
piotrdda22272014-08-04 11:31:54 +0200162 std::vector<int> extract_system_info_impl::get_chans()
163 {
ptrkrysike9539c12015-07-06 08:34:22 +0200164 std::vector<int> chans_ids;
165 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
166 chans_ids.push_back(i.second.id);
piotrdda22272014-08-04 11:31:54 +0200167 }
piotrdda22272014-08-04 11:31:54 +0200168 return chans_ids;
169 }
170
171 std::vector<int> extract_system_info_impl::get_lac()
172 {
ptrkrysike9539c12015-07-06 08:34:22 +0200173 std::vector<int> lacs;
174 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
175 lacs.push_back(i.second.lac);
piotrdda22272014-08-04 11:31:54 +0200176 }
ptrkrysike9539c12015-07-06 08:34:22 +0200177 return lacs;
piotrdda22272014-08-04 11:31:54 +0200178 }
ptrkrysike9539c12015-07-06 08:34:22 +0200179
piotrdda22272014-08-04 11:31:54 +0200180 std::vector<int> extract_system_info_impl::get_mnc()
181 {
ptrkrysike9539c12015-07-06 08:34:22 +0200182 std::vector<int> mncs;
183 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
184 mncs.push_back(i.second.mnc);
piotrdda22272014-08-04 11:31:54 +0200185 }
ptrkrysike9539c12015-07-06 08:34:22 +0200186 return mncs;
piotrdda22272014-08-04 11:31:54 +0200187 }
ptrkrysike9539c12015-07-06 08:34:22 +0200188
piotrdda22272014-08-04 11:31:54 +0200189 std::vector<int> extract_system_info_impl::get_cell_id()
190 {
ptrkrysike9539c12015-07-06 08:34:22 +0200191 std::vector<int> cell_ids;
192 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
193 cell_ids.push_back(i.second.cell_id);
piotrdda22272014-08-04 11:31:54 +0200194 }
ptrkrysike9539c12015-07-06 08:34:22 +0200195 return cell_ids;
piotrdda22272014-08-04 11:31:54 +0200196 }
197
198 std::vector<int> extract_system_info_impl::get_pwrs()
199 {
ptrkrysike9539c12015-07-06 08:34:22 +0200200 std::vector<int> pwrs;
201 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
202 pwrs.push_back(i.second.pwr_db);
piotrdda22272014-08-04 11:31:54 +0200203 }
piotrdda22272014-08-04 11:31:54 +0200204 return pwrs;
205 }
ptrkrysike9539c12015-07-06 08:34:22 +0200206 std::vector<int> extract_system_info_impl::get_neighbours(int chan_id)
207 {
208 std::vector<int> neighbour_cells;
209 BOOST_FOREACH(int n, d_c0_channels[chan_id].neighbour_cells){
210 neighbour_cells.push_back(n);
211 }
212 return neighbour_cells;
213 }
piotrdda22272014-08-04 11:31:54 +0200214
215 void extract_system_info_impl::reset()
216 {
ptrkrysike9539c12015-07-06 08:34:22 +0200217 d_c0_channels.clear();
piotrdda22272014-08-04 11:31:54 +0200218 if(!empty_p(pmt::mp("bursts"))){
219 delete_head_blocking(pmt::mp("bursts"));
220 }
ptrkrysike9539c12015-07-06 08:34:22 +0200221 if(!empty_p(pmt::mp("msgs"))){
222 delete_head_blocking(pmt::mp("msgs"));
223 }
piotrdda22272014-08-04 11:31:54 +0200224 }
225
226 extract_system_info::sptr
227 extract_system_info::make()
228 {
229 return gnuradio::get_initial_sptr
230 (new extract_system_info_impl());
231 }
232
233 /*
234 * The private constructor
235 */
236 extract_system_info_impl::extract_system_info_impl()
237 : gr::block("extract_system_info",
238 gr::io_signature::make(0, 0, 0),
239 gr::io_signature::make(0, 0, 0)),
240 after_reset(false)
241 {
242 message_port_register_in(pmt::mp("bursts"));
243 set_msg_handler(pmt::mp("bursts"), boost::bind(&extract_system_info_impl::process_bursts, this, _1));
244 message_port_register_in(pmt::mp("msgs"));
245 set_msg_handler(pmt::mp("msgs"), boost::bind(&extract_system_info_impl::process_sysinfo, this, _1));
246 }
247
248 /*
249 * Our virtual destructor.
250 */
251 extract_system_info_impl::~extract_system_info_impl()
252 {
253 }
254
255
256 } /* namespace gsm */
257} /* namespace gr */
258