blob: 0dc43a64e82811d66c4a070fb37f6a45a3e1721a [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>
ptrkrysike9539c12015-07-06 08:34:22 +020034#include <endian.h>
35#include <boost/foreach.hpp>
piotrdda22272014-08-04 11:31:54 +020036
ptrkrysik402c1fa2014-12-03 22:09:29 +010037#include "extract_system_info_impl.h"
38
piotrdda22272014-08-04 11:31:54 +020039namespace gr {
40 namespace gsm {
41 boost::mutex extract_mutex;
42 void extract_system_info_impl::process_bursts(pmt::pmt_t msg)
43 {
ptrkrysika31a4812014-12-15 09:10:01 +010044 pmt::pmt_t burst_plus_header_blob = pmt::cdr(msg);
45 gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(burst_plus_header_blob);
piotrdda22272014-08-04 11:31:54 +020046
piotrdda22272014-08-04 11:31:54 +020047 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020048 info.id = be16toh(header->arfcn);
piotrdda22272014-08-04 11:31:54 +020049 info.pwr_db = header->signal_dbm;
piotrdda22272014-08-04 11:31:54 +020050
51 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020052
53 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
54 d_c0_channels[info.id].copy_nonzero_elements(info);
55 } else {
56 d_c0_channels[info.id] = info;
57 }
piotrdda22272014-08-04 11:31:54 +020058 }
59
60 void extract_system_info_impl::process_sysinfo(pmt::pmt_t msg){
ptrkrysika31a4812014-12-15 09:10:01 +010061 pmt::pmt_t message_plus_header_blob = pmt::cdr(msg);
62 uint8_t * message_plus_header = (uint8_t *)pmt::blob_data(message_plus_header_blob);
63 gsmtap_hdr * header = (gsmtap_hdr *)message_plus_header;
64 uint8_t * msg_elements = (uint8_t *)(message_plus_header+sizeof(gsmtap_hdr));
piotrdda22272014-08-04 11:31:54 +020065
66 if(msg_elements[2]==0x1b){
piotrdda22272014-08-04 11:31:54 +020067 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020068 info.id = be16toh(header->arfcn); //take arfcn
piotrdda22272014-08-04 11:31:54 +020069 info.pwr_db = header->signal_dbm;
ptrkrysika31a4812014-12-15 09:10:01 +010070 info.cell_id = (msg_elements[3]<<8)+msg_elements[4]; //take cell id
71 info.lac = (msg_elements[8]<<8)+msg_elements[9]; //take lac
72 info.mnc = (msg_elements[7]>>4); //take mnc
piotrdda22272014-08-04 11:31:54 +020073 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020074 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
75 d_c0_channels[info.id].copy_nonzero_elements(info);
76 } else {
77 d_c0_channels[info.id] = info;
piotrdda22272014-08-04 11:31:54 +020078 }
piotrdda22272014-08-04 11:31:54 +020079 }
80 else if(msg_elements[2]==0x1c){
piotrdda22272014-08-04 11:31:54 +020081 chan_info info;
ptrkrysike9539c12015-07-06 08:34:22 +020082 info.id = be16toh(header->arfcn); //take arfcn
piotrdda22272014-08-04 11:31:54 +020083 info.pwr_db = header->signal_dbm;
ptrkrysike9539c12015-07-06 08:34:22 +020084 info.lac = (msg_elements[6]<<8)+msg_elements[7]; //take lac
85 info.mnc = (msg_elements[5]>>4); //take mnc
piotrdda22272014-08-04 11:31:54 +020086
piotrdda22272014-08-04 11:31:54 +020087 boost::mutex::scoped_lock lock(extract_mutex);
ptrkrysike9539c12015-07-06 08:34:22 +020088 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
89 d_c0_channels[info.id].copy_nonzero_elements(info);
90 } else {
91 d_c0_channels[info.id] = info;
piotrdda22272014-08-04 11:31:54 +020092 }
ptrkrysike9539c12015-07-06 08:34:22 +020093 } else if(msg_elements[2]==0x1a){ //System Information Type 2
94 chan_info info;
95 info.id = be16toh(header->arfcn); //take arfcn
96 info.pwr_db = header->signal_dbm;
97 boost::mutex::scoped_lock lock(extract_mutex);
98 //read neighbour cells
99 decode_neighbour_cells(msg_elements, 3, info.id);
100// unsigned int byte_nr, arfcn, bit;
101// arfcn=124;
102// bit=4;
103// for (byte_nr = 0; byte_nr <= 15; byte_nr++) {
104// while (bit-- != 0) {
105// if (((msg_elements[byte_nr+3] >> bit) & 1) == 1){
106// d_c0_channels[info.id].neighbour_cells.insert(arfcn);
107// }
108// arfcn--;
109// }
110// bit=8;
111// }
112
113 if(d_c0_channels.find(info.id) != d_c0_channels.end()){
114 d_c0_channels[info.id].copy_nonzero_elements(info);
115 } else {
116 d_c0_channels[info.id] = info;
117 }
piotrdda22272014-08-04 11:31:54 +0200118 }
119 }
120
ptrkrysike9539c12015-07-06 08:34:22 +0200121 void extract_system_info_impl::decode_neighbour_cells(uint8_t * data, unsigned int offset, unsigned int chan_id)
122 {
123 unsigned int curr_offset, byte, bit, arfcn, format;
124 uint8_t oct;
125 curr_offset = offset;
126 format = data[curr_offset];
127
128 if ((format & 0xc0) == 0x00)
129 {
130 /* bit map 0 */
131 bit = 4;
132 arfcn = 125;
133 for (byte = 0; byte <= 15; byte++)
134 {
135 oct = data[curr_offset];
136 while (bit-- != 0)
137 {
138 arfcn--;
139 if (((oct >> bit) & 1) == 1)
140 {
141 d_c0_channels[chan_id].neighbour_cells.insert(arfcn);
142 }
143 }
144 bit = 8;
145 curr_offset++;
146 }
piotrdda22272014-08-04 11:31:54 +0200147 }
ptrkrysike9539c12015-07-06 08:34:22 +0200148 else if ((format & 0xc8) == 0x80)
149 {
150 /* 1024 range */
151// dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 1024);
152 }
153 else if ((format & 0xce) == 0x88)
154 {
155 /* 512 range */
156// dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 512);
157 }
158 else if ((format & 0xce) == 0x8a)
159 {
160 /* 256 range */
161// dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 256);
162 }
163 else if ((format & 0xce) == 0x8c)
164 {
165 /* 128 range */
166// dissect_channel_list_n_range(tvb, tree, pinfo, curr_offset, len, 128);
167 }
168 else if ((format & 0xce) == 0x8e)
169 {
170 /* variable bit map */
171 arfcn = ((format & 0x01) << 9) | (data[curr_offset+1] << 1) | ((data[curr_offset+2] & 0x80) >> 7);
172 curr_offset = curr_offset + 2;
173 bit = 7;
174 for(byte = 0; byte <= (15-2); byte++){
175 oct = data[curr_offset];
176 while (bit-- != 0){
177 arfcn++;
178 if (((oct >> bit) & 1) == 1){
179 d_c0_channels[chan_id].neighbour_cells.insert(arfcn);
180 }
181 }
182 bit = 8;
183 curr_offset++;
184 }
185 }
186
187 return;
piotrdda22272014-08-04 11:31:54 +0200188 }
189
ptrkrysike9539c12015-07-06 08:34:22 +0200190// void extract_system_info_impl::dissect_channel_list_n_range(guint32 offset, guint len, gint range)
191// {
192// int curr_offset = offset, bit_offset, f0, arfcn_orig, w[64], wsize, i;
193// int octet, nwi = 1, jwi=0, imax, iused, arfcn;
194// uint8_t list[1024];
195
196// memset((void*)list,0,sizeof(list));
197
198//// subtree = proto_tree_add_subtree_format(tree,tvb, curr_offset, len,
199//// ett_gsm_rr_elem[DE_RR_NEIGH_CELL_DESC], NULL, "Range %d format", range);
200
201// octet = data[curr_offset];
202// if (range == 1024) {
203// f0 = (octet>>2)&1;
204// if (f0)
205// list[0] = 1;
206// arfcn_orig = 0;
207// wsize = 10;
208// imax = 16;
209// bit_offset = curr_offset*8 + 6;
210// }
211// else {
212// bit_offset = curr_offset*8 + 7;
213// arfcn_orig = (gint) tvb_get_bits(tvb, bit_offset, 10, FALSE);
214//// proto_tree_add_bits_item(subtree, hf_n_range_orig_arfcn, tvb, bit_offset, 10, ENC_BIG_ENDIAN);
215// bit_offset+=10;
216
217// list[arfcn_orig] = 1;
218
219// switch (range) {
220// case 512:
221// wsize=9;
222// imax = 17;
223// break;
224// case 256:
225// wsize=8;
226// imax = 21;
227// break;
228// case 128:
229// wsize=7;
230// imax = 28;
231// break;
232// default:
233//// DISSECTOR_ASSERT_NOT_REACHED();
234// }
235// }
236// iused = imax; /* in case the list is actually full */
237
238// /* extract the variable size w[] elements */
239// for (i=1; i<=imax; i++) {
240// w[i] = (gint) tvb_get_bits(tvb, bit_offset, wsize, FALSE);
241//// proto_tree_add_text(subtree, tvb, bit_offset>>3, ((bit_offset+wsize-1)>>3) - (bit_offset>>3) + 1 , "%s %s(%d): %d",
242//// decode_bits_in_field(bit_offset, wsize, w[i]),
243//// "W",
244//// i,
245//// w[i]);
246// bit_offset += wsize;
247// curr_offset = bit_offset>>3;
248
249// if ((iused == imax) && (w[i] == 0) ) {
250// iused = i - 1;
251// }
252// if ((curr_offset-offset)>len) {
253// iused = i - 1;
254// break;
255// }
256// if (++jwi == nwi) { /* check if the number of wi at this wsize has been extracted */
257// jwi = 0; /* reset the count of wi at this size */
258// nwi <<= 1; /* get twice as many of the next size */
259// wsize--; /* make the next size 1 bit smaller */
260// }
261// }
262
263// for (i=1; i<=iused; i++) {
264// arfcn = (f_k(i, w, range) + arfcn_orig)%1024;
265// list[arfcn] = 1;
266// }
267
268//// display_channel_list(list, tvb, tree, offset, curr_offset-offset);
269
270// return;
271// }
272
piotrdda22272014-08-04 11:31:54 +0200273 std::vector<int> extract_system_info_impl::get_chans()
274 {
ptrkrysike9539c12015-07-06 08:34:22 +0200275 std::vector<int> chans_ids;
276 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
277 chans_ids.push_back(i.second.id);
piotrdda22272014-08-04 11:31:54 +0200278 }
piotrdda22272014-08-04 11:31:54 +0200279 return chans_ids;
280 }
281
282 std::vector<int> extract_system_info_impl::get_lac()
283 {
ptrkrysike9539c12015-07-06 08:34:22 +0200284 std::vector<int> lacs;
285 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
286 lacs.push_back(i.second.lac);
piotrdda22272014-08-04 11:31:54 +0200287 }
ptrkrysike9539c12015-07-06 08:34:22 +0200288 return lacs;
piotrdda22272014-08-04 11:31:54 +0200289 }
ptrkrysike9539c12015-07-06 08:34:22 +0200290
piotrdda22272014-08-04 11:31:54 +0200291 std::vector<int> extract_system_info_impl::get_mnc()
292 {
ptrkrysike9539c12015-07-06 08:34:22 +0200293 std::vector<int> mncs;
294 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
295 mncs.push_back(i.second.mnc);
piotrdda22272014-08-04 11:31:54 +0200296 }
ptrkrysike9539c12015-07-06 08:34:22 +0200297 return mncs;
piotrdda22272014-08-04 11:31:54 +0200298 }
ptrkrysike9539c12015-07-06 08:34:22 +0200299
piotrdda22272014-08-04 11:31:54 +0200300 std::vector<int> extract_system_info_impl::get_cell_id()
301 {
ptrkrysike9539c12015-07-06 08:34:22 +0200302 std::vector<int> cell_ids;
303 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
304 cell_ids.push_back(i.second.cell_id);
piotrdda22272014-08-04 11:31:54 +0200305 }
ptrkrysike9539c12015-07-06 08:34:22 +0200306 return cell_ids;
piotrdda22272014-08-04 11:31:54 +0200307 }
308
309 std::vector<int> extract_system_info_impl::get_pwrs()
310 {
ptrkrysike9539c12015-07-06 08:34:22 +0200311 std::vector<int> pwrs;
312 BOOST_FOREACH(chan_info_map::value_type &i, d_c0_channels){
313 pwrs.push_back(i.second.pwr_db);
piotrdda22272014-08-04 11:31:54 +0200314 }
piotrdda22272014-08-04 11:31:54 +0200315 return pwrs;
316 }
ptrkrysike9539c12015-07-06 08:34:22 +0200317 std::vector<int> extract_system_info_impl::get_neighbours(int chan_id)
318 {
319 std::vector<int> neighbour_cells;
320 BOOST_FOREACH(int n, d_c0_channels[chan_id].neighbour_cells){
321 neighbour_cells.push_back(n);
322 }
323 return neighbour_cells;
324 }
piotrdda22272014-08-04 11:31:54 +0200325
326 void extract_system_info_impl::reset()
327 {
ptrkrysike9539c12015-07-06 08:34:22 +0200328 d_c0_channels.clear();
piotrdda22272014-08-04 11:31:54 +0200329 if(!empty_p(pmt::mp("bursts"))){
330 delete_head_blocking(pmt::mp("bursts"));
331 }
ptrkrysike9539c12015-07-06 08:34:22 +0200332 if(!empty_p(pmt::mp("msgs"))){
333 delete_head_blocking(pmt::mp("msgs"));
334 }
piotrdda22272014-08-04 11:31:54 +0200335 }
336
337 extract_system_info::sptr
338 extract_system_info::make()
339 {
340 return gnuradio::get_initial_sptr
341 (new extract_system_info_impl());
342 }
343
344 /*
345 * The private constructor
346 */
347 extract_system_info_impl::extract_system_info_impl()
348 : gr::block("extract_system_info",
349 gr::io_signature::make(0, 0, 0),
350 gr::io_signature::make(0, 0, 0)),
351 after_reset(false)
352 {
353 message_port_register_in(pmt::mp("bursts"));
354 set_msg_handler(pmt::mp("bursts"), boost::bind(&extract_system_info_impl::process_bursts, this, _1));
355 message_port_register_in(pmt::mp("msgs"));
356 set_msg_handler(pmt::mp("msgs"), boost::bind(&extract_system_info_impl::process_sysinfo, this, _1));
357 }
358
359 /*
360 * Our virtual destructor.
361 */
362 extract_system_info_impl::~extract_system_info_impl()
363 {
364 }
365
366
367 } /* namespace gsm */
368} /* namespace gr */
369