aboutsummaryrefslogtreecommitdiffstats
path: root/lib/decoding/control_channels_decoder_impl.cc
blob: a6abaa36997bd2f00fcef8478a9add8530aba852 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* -*- c++ -*- */
/*
 * @file
 * @author (C) 2014 by Piotr Krysik <ptrkrysik@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 <grgsm/gsmtap.h>
#include "control_channels_decoder_impl.h"

#define DATA_BYTES 23

namespace gr {
  namespace gsm {

    static int ubits2sbits(ubit_t *ubits, sbit_t *sbits, int count)
    {
	    int i;

	    for (i = 0; i < count; i++) {
		    if (*ubits == 0x23) {
			    ubits++;
			    sbits++;
			    continue;
		    }
		    if ((*ubits++) & 1)
			    *sbits++ = -127;
		    else
			    *sbits++ = 127;
	    }

	    return count;
    }

    control_channels_decoder::sptr
    control_channels_decoder::make()
    {
      return gnuradio::get_initial_sptr
        (new control_channels_decoder_impl());
    }

    /*
     * Constructor
     */
    control_channels_decoder_impl::control_channels_decoder_impl()
      : gr::block("control_channels_decoder",
              gr::io_signature::make(0, 0, 0),
              gr::io_signature::make(0, 0, 0)),
              d_collected_bursts_num(0)
    {
        //setup input/output ports
        message_port_register_in(pmt::mp("bursts"));
        set_msg_handler(pmt::mp("bursts"), boost::bind(&control_channels_decoder_impl::decode, this, _1));
        message_port_register_out(pmt::mp("msgs"));
    }

    control_channels_decoder_impl::~control_channels_decoder_impl()
    {
    }

    void control_channels_decoder_impl::decode(pmt::pmt_t msg)
    {
        ubit_t bursts_u[116 * 4];
        sbit_t bursts_s[116 * 4];
        uint8_t result[23];
        int n_errors, n_bits_total;
        int8_t header_plus_data[sizeof(gsmtap_hdr)+DATA_BYTES];

        d_bursts[d_collected_bursts_num] = msg;
        d_collected_bursts_num++;

        //get convecutive bursts
        if(d_collected_bursts_num==4)
        {
            d_collected_bursts_num=0;
            //reorganize data from input bursts
            for(int ii = 0; ii < 4; ii++)
            {
                pmt::pmt_t header_plus_burst = pmt::cdr(d_bursts[ii]);
                int8_t * burst_bits = (int8_t *)(pmt::blob_data(header_plus_burst))+sizeof(gsmtap_hdr);

                memcpy(&bursts_u[ii*116], &burst_bits[3],58);
                memcpy(&bursts_u[ii*116+58], &burst_bits[3+57+1+26],58);
            }
            //convert to soft bits
            ubits2sbits(bursts_u, bursts_s, 116 * 4);
            //decode
            gsm0503_xcch_decode(result, bursts_s, &n_errors, &n_bits_total);

            //extract header of the first burst of the four bursts
            pmt::pmt_t first_header_plus_burst = pmt::cdr(d_bursts[0]);
            gsmtap_hdr * header = (gsmtap_hdr *)pmt::blob_data(first_header_plus_burst);
            //copy header and data
            memcpy(header_plus_data, header, sizeof(gsmtap_hdr));
            memcpy(header_plus_data+sizeof(gsmtap_hdr), result, DATA_BYTES);
            //set data type in the header
            ((gsmtap_hdr*)header_plus_data)->type = GSMTAP_TYPE_UM;
            //prepare message
            pmt::pmt_t msg_out = pmt::cons(pmt::PMT_NIL, pmt::make_blob(header_plus_data,DATA_BYTES+sizeof(gsmtap_hdr)));
            //send message to the output
            message_port_pub(pmt::mp("msgs"), msg_out);
        }
        return;
    }
  } /* namespace gsm */
} /* namespace gr */