From 7f259fdb68025d6e7b3cfc36c3958d9c6e5f60b8 Mon Sep 17 00:00:00 2001 From: Vasil Velichkov Date: Sun, 6 May 2018 02:13:36 +0300 Subject: Add TCH/H decoder block with AMR multirate support Add new TCHH channel mode Add two new optional arguments -m CHAN_MODE, --mode=CHAN_MODE Channel mode. Valid options are 'BCCH' (Non-combined C0), 'BCCH_SDCCH4'(Combined C0), 'SDCCH8' (Stand-alone control channel) 'TCHF' (Traffic Channel, Full rate), 'TCHH' (Traffic Channel, Half rate) --sub-channel=TCH_H_CHANNEL TCH/H sub-channel. [default=0] --multi-rate=MULTI_RATE The MultiRrate configuration element from the Assigment Command message. Example: 28111a40. See 3GPP TS 44.018 - 10.5.2.21aa MultiRate configuration Example: grgsm_decode -m TCHH --sub-channel 0 --multi-rate 2811 -o voice.amr ... --- apps/grgsm_decode | 44 +++- grc/decoding/CMakeLists.txt | 4 +- grc/decoding/gsm_tch_h_decoder.xml | 92 ++++++++ grc/gsm_block_tree.xml | 1 + include/grgsm/decoding/CMakeLists.txt | 4 +- include/grgsm/decoding/tch_f_decoder.h | 3 +- include/grgsm/decoding/tch_h_decoder.h | 59 +++++ lib/decoding/CMakeLists.txt | 1 + lib/decoding/tch_h_decoder_impl.cc | 357 +++++++++++++++++++++++++++++ lib/decoding/tch_h_decoder_impl.h | 60 +++++ lib/demapping/tch_h_chans_demapper_impl.cc | 1 + swig/grgsm_swig.i | 3 + 12 files changed, 621 insertions(+), 8 deletions(-) create mode 100644 grc/decoding/gsm_tch_h_decoder.xml create mode 100644 include/grgsm/decoding/tch_h_decoder.h create mode 100644 lib/decoding/tch_h_decoder_impl.cc create mode 100644 lib/decoding/tch_h_decoder_impl.h diff --git a/apps/grgsm_decode b/apps/grgsm_decode index 9c01e66..3bc0db3 100755 --- a/apps/grgsm_decode +++ b/apps/grgsm_decode @@ -40,6 +40,8 @@ class grgsm_decoder(gr.top_block): a5=1, a5_kc=None, speech_file=None, speech_codec=None, enable_voice_boundary_detection=False, + tch_h_channel=0, + multi_rate=0, verbose=False, print_bursts=False, ppm=0): @@ -100,11 +102,16 @@ class grgsm_decoder(gr.top_block): self.tch_f_decoder = grgsm.tch_f_decoder(speech_codec, enable_voice_boundary_detection) self.tch_f_pdu_to_tagged_stream = blocks.pdu_to_tagged_stream(blocks.byte_t, "packet_len") self.tch_f_file_sink = blocks.file_sink(gr.sizeof_char*1, speech_file, False) + elif self.chan_mode == 'TCHH': + self.tch_h_demapper = grgsm.tch_h_chans_demapper(self.timeslot, tch_h_channel) + self.tch_h_decoder = grgsm.tch_h_decoder(tch_h_channel, multi_rate, enable_voice_boundary_detection) + self.tch_f_pdu_to_tagged_stream = blocks.pdu_to_tagged_stream(blocks.byte_t, "packet_len") + self.tch_f_file_sink = blocks.file_sink(gr.sizeof_char*1, speech_file, False) if self.kc != [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]: self.decryption = grgsm.decryption(self.kc, self.a5) self.cch_decoder_decrypted = grgsm.control_channels_decoder() - if self.chan_mode == 'TCHF': + if self.chan_mode in ('TCHF', 'TCHH'): self.decryption_tch_sacch = grgsm.decryption(self.kc, self.a5) self.cch_decoder = grgsm.control_channels_decoder() @@ -209,12 +216,32 @@ class grgsm_decoder(gr.top_block): if self.verbose: self.msg_connect(self.tch_f_decoder, "msgs", self.message_printer, "msgs") self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs") - + + elif self.chan_mode == 'TCHH': + self.msg_connect(self.timeslot_filter, "out", self.tch_h_demapper, "bursts") + if self.kc != [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]: + self.msg_connect(self.tch_h_demapper, "acch_bursts", self.decryption_tch_sacch, "bursts") + self.msg_connect(self.tch_h_demapper, "tch_bursts", self.decryption, "bursts") + + self.msg_connect(self.decryption_tch_sacch, "bursts", self.cch_decoder, "bursts") + self.msg_connect(self.decryption, "bursts", self.tch_h_decoder, "bursts") + else: + self.msg_connect(self.tch_h_demapper, "acch_bursts", self.cch_decoder, "bursts") + self.msg_connect(self.tch_h_demapper, "tch_bursts", self.tch_h_decoder, "bursts") + + self.msg_connect(self.tch_h_decoder, "msgs", self.socket_pdu, "pdus") + self.msg_connect(self.cch_decoder, "msgs", self.socket_pdu, "pdus") + self.msg_connect(self.tch_h_decoder, "voice", self.tch_f_pdu_to_tagged_stream, "pdus") + self.connect((self.tch_f_pdu_to_tagged_stream, 0), (self.tch_f_file_sink, 0)) + + if self.verbose: + self.msg_connect(self.tch_h_decoder, "msgs", self.message_printer, "msgs") + self.msg_connect(self.cch_decoder, "msgs", self.message_printer, "msgs") if __name__ == '__main__': # List of channel configurations - channel_modes = ['BCCH', 'BCCH_SDCCH4', 'SDCCH8', 'TCHF'] + channel_modes = ['BCCH', 'BCCH_SDCCH4', 'SDCCH8', 'TCHF', 'TCHH'] # mapping options to grgsm's enums tch_codecs = collections.OrderedDict([ @@ -265,7 +292,7 @@ if __name__ == '__main__': type='choice', choices=channel_modes, help="Channel mode. Valid options are 'BCCH' (Non-combined C0), " "'BCCH_SDCCH4'(Combined C0), 'SDCCH8' (Stand-alone control channel) " - "and 'TCHF' (Traffic Channel, Full rate) ") + "'TCHF' (Traffic Channel, Full rate), 'TCHH' (Traffic Channel, Half rate) ") parser.add_option("-t", "--timeslot", dest="timeslot", type="intx", default=0, help="Timeslot to decode [default=%default]") parser.add_option("-u", "--subslot", dest="subslot", type="intx", @@ -313,7 +340,12 @@ if __name__ == '__main__': help="TCH-F speech codec [default=%default]. " "Valid options are " + ", ".join(tch_codecs.keys())) tch_options.add_option("-o", "--output-tch", dest="speech_output_file", default="/tmp/speech.au.gsm", - help="TCH/F speech output file [default=%default].") + help="tch/f speech output file [default=%default].") + tch_options.add_option("--sub-channel", dest="tch_h_channel", default="0", type='intx', + help="TCH/H sub-channel. [default=0]") + tch_options.add_option("--multi-rate", dest="multi_rate", default="", type='string', + help="The MultiRrate configuration element from the Assignment Command message. " + "Example: 28111a40. See 3GPP TS 44.018 - 10.5.2.21aa MultiRate configuration") tch_options.add_option("--voice-boundary", dest="enable_voice_boundary_detection", action="store_true", default=False, help="Enable voice boundary detection for traffic channels. This can help reduce noice in the output.") parser.add_option_group(tch_options) @@ -358,6 +390,8 @@ if __name__ == '__main__': a5=options.a5, a5_kc=kc, speech_file=options.speech_output_file, speech_codec=tch_codecs.get(options.speech_codec), enable_voice_boundary_detection=options.enable_voice_boundary_detection, + tch_h_channel=options.tch_h_channel, + multi_rate=options.multi_rate, verbose=options.verbose, print_bursts=options.print_bursts, ppm=options.ppm) diff --git a/grc/decoding/CMakeLists.txt b/grc/decoding/CMakeLists.txt index 2f6eada..d488f21 100644 --- a/grc/decoding/CMakeLists.txt +++ b/grc/decoding/CMakeLists.txt @@ -19,5 +19,7 @@ install(FILES gsm_control_channels_decoder.xml - gsm_tch_f_decoder.xml DESTINATION share/gnuradio/grc/blocks + gsm_tch_f_decoder.xml + gsm_tch_h_decoder.xml + DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/decoding/gsm_tch_h_decoder.xml b/grc/decoding/gsm_tch_h_decoder.xml new file mode 100644 index 0000000..895104e --- /dev/null +++ b/grc/decoding/gsm_tch_h_decoder.xml @@ -0,0 +1,92 @@ + + + TCH/H decoder + gsm_tch_h_decoder + import grgsm + grgsm.tch_h_decoder($sub_channel, $mode, $boundary_check) + + + sub-channel number + sub_channel + 0 + int + + + + + TCH/H coding mode + mode + enum + + + + + + + + + + Voice boundary detection + boundary_check + False + bool + + + + $sub_channel() > -1 and $sub_channel() < 2 + + bursts + message + + + msgs + message + 1 + + + voice + message + 1 + + + +If "Voice boundary detection" is enabled, then only bursts are decoded as voice where + +- the framenumber is greater then the framenumber of a received "Connect" or "Connect Acknowlegde" message, and +- the framenumber is less then the framenumber of a "Release" message + + + diff --git a/grc/gsm_block_tree.xml b/grc/gsm_block_tree.xml index 786d7d2..b056003 100644 --- a/grc/gsm_block_tree.xml +++ b/grc/gsm_block_tree.xml @@ -50,6 +50,7 @@ Decoding gsm_control_channels_decoder gsm_tch_f_decoder + gsm_tch_h_decoder Flow control diff --git a/include/grgsm/decoding/CMakeLists.txt b/include/grgsm/decoding/CMakeLists.txt index 64bbb16..1014955 100644 --- a/include/grgsm/decoding/CMakeLists.txt +++ b/include/grgsm/decoding/CMakeLists.txt @@ -22,5 +22,7 @@ ######################################################################## install(FILES control_channels_decoder.h - tch_f_decoder.h DESTINATION include/grgsm/decoding + tch_f_decoder.h + tch_h_decoder.h + DESTINATION include/grgsm/decoding ) diff --git a/include/grgsm/decoding/tch_f_decoder.h b/include/grgsm/decoding/tch_f_decoder.h index df5f0ff..ae65f06 100644 --- a/include/grgsm/decoding/tch_f_decoder.h +++ b/include/grgsm/decoding/tch_f_decoder.h @@ -41,7 +41,8 @@ namespace gr { TCH_AFS5_15, TCH_AFS4_75, TCH_FS, - TCH_EFR + TCH_EFR, + TCH_HS, }; /*! diff --git a/include/grgsm/decoding/tch_h_decoder.h b/include/grgsm/decoding/tch_h_decoder.h new file mode 100644 index 0000000..5ea9714 --- /dev/null +++ b/include/grgsm/decoding/tch_h_decoder.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * @file + * @author (C) 2018 by Vasil Velichkov + * @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_GSM_TCH_H_DECODER_H +#define INCLUDED_GSM_TCH_H_DECODER_H + +#include +#include + +namespace gr { + namespace gsm { + + /*! + * \brief <+description of block+> + * \ingroup gsm + * + */ + class GRGSM_API tch_h_decoder : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of gsm::tch_h_decoder. + * + * To avoid accidental use of raw pointers, gsm::tch_h_decoder's + * constructor is in a private implementation + * class. gsm::tch_h_decoder::make is the public interface for + * creating new instances. + */ + static sptr make(unsigned int sub_channel, std::string multi_rate, bool boundary_check=false); + + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_TCH_H_DECODER_H */ + diff --git a/lib/decoding/CMakeLists.txt b/lib/decoding/CMakeLists.txt index 154108a..423ab92 100644 --- a/lib/decoding/CMakeLists.txt +++ b/lib/decoding/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(openbts) add_sources( control_channels_decoder_impl.cc tch_f_decoder_impl.cc + tch_h_decoder_impl.cc sch.c ) diff --git a/lib/decoding/tch_h_decoder_impl.cc b/lib/decoding/tch_h_decoder_impl.cc new file mode 100644 index 0000000..b7672e3 --- /dev/null +++ b/lib/decoding/tch_h_decoder_impl.cc @@ -0,0 +1,357 @@ +/* -*- c++ -*- */ +/* + * @file + * @author (C) 2018 by Vasil Velichkov + * @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 "tch_h_decoder_impl.h" + +extern "C" { +#include "osmocom/gsm/protocol/gsm_04_08.h" +#include "osmocom/coding/gsm0503_coding.h" +} + +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; + } + + + tch_h_decoder::sptr + tch_h_decoder::make(unsigned int sub_channel, std::string multi_rate, bool boundary_check) + { + return gnuradio::get_initial_sptr + (new tch_h_decoder_impl(sub_channel, multi_rate, boundary_check)); + } + + /* + * Constructor + */ + tch_h_decoder_impl::tch_h_decoder_impl(unsigned int sub_channel, std::string multi_rate, bool boundary_check) + : gr::block("tch_h_decoder", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_collected_bursts_num(0), + d_tch_mode(TCH_HS), + d_sub_channel(sub_channel), + d_boundary_check(boundary_check), + d_boundary_decode(false), + d_header_sent(false), + d_ft(0), + d_cmr(0) + { + //setup input/output ports + message_port_register_in(pmt::mp("bursts")); + set_msg_handler(pmt::mp("bursts"), boost::bind(&tch_h_decoder_impl::decode, this, _1)); + message_port_register_out(pmt::mp("msgs")); + message_port_register_out(pmt::mp("voice")); + + if(multi_rate.length()) + { + std::cout<<"multi_rate configuration: "< binary; + for (std::string::const_iterator it = multi_rate.begin(); + it != multi_rate.end(); it += 2) + { + std::string byte(it, it + 2); + char* end = NULL; + errno = 0; + uint8_t b = strtoul(byte.c_str(), &end, 16); + if (errno != 0 || *end != '\0') + { + throw std::invalid_argument("Invalid multi_rate hexstring"); + } + binary.push_back(b); + } + + if (binary.size() < 2) { + throw std::invalid_argument("The multi_rate is too short"); + } + + //GSM A-I/F DTAP - Assignment Command + // Protocol Discriminator: Radio Resources Management messages (6) + // DTAP Radio Resources Management Message Type: Assignment Command (0x2e) + // Channel Description 2 - Description of the First Channel, after time + // Power Command + // Channel Mode - Mode of the First Channel(Channel Set 1) + // MultiRate configuration + // Element ID: 0x03 + // Length: 4 + // 001. .... = Multirate speech version: Adaptive Multirate speech version 1 (1) + // ...0 .... = NSCB: Noise Suppression Control Bit: Noise Suppression can be used (default) (0) + // .... 1... = ICMI: Initial Codec Mode Indicator: The initial codec mode is defined by the Start Mode field (1) + // .... ..00 = Start Mode: 0 + // 0... .... = 12,2 kbit/s codec rate: is not part of the subset + // .0.. .... = 10,2 kbit/s codec rate: is not part of the subset + // ..0. .... = 7,95 kbit/s codec rate: is not part of the subset + // ...1 .... = 7,40 kbit/s codec rate: is part of the subset + // .... 0... = 6,70 kbit/s codec rate: is not part of the subset + // .... .0.. = 5,90 kbit/s codec rate: is not part of the subset + // .... ..0. = 5,15 kbit/s codec rate: is not part of the subset + // .... ...1 = 4,75 kbit/s codec rate: is part of the subset + // ..01 1010 = AMR Threshold: 13.0 dB (26) + // 0100 .... = AMR Hysteresis: 2.0 dB (4) + + const uint8_t first = binary[0]; + uint8_t multirate_speech_ver = (first >> 5) & 0x07; + if (multirate_speech_ver == 1) + { + d_tch_mode = TCH_AFS4_75; + } + else if (multirate_speech_ver == 2) + { + throw std::invalid_argument("Adaptive Multirate speech version 2 is not supported"); + } + else + { + throw std::invalid_argument("Multirate speech version"); + } + + bool ncsb = (first >> 4) & 0x01; + bool icmi = (first >> 3) & 0x01; + uint8_t start = first & 0x03; + + const uint8_t codecs = binary[1]; + for (int i = 0; i < 8; i++) + { + if ((codecs >> i) & 1) + { + d_multi_rate_codes.push_back(i); + } + } + + std::cout<<"Enabled AMR Codecs:"<::const_iterator it = d_multi_rate_codes.begin(); + it != d_multi_rate_codes.end(); + it ++) + { + switch(*it) + { + case 0: + std::cout<<"4,75 kbit/s codec rate: is part of the subset"< 4) { + throw std::invalid_argument("More then 4 multirate codes"); + } + } + } + + tch_h_decoder_impl::~tch_h_decoder_impl() + { + } + + void tch_h_decoder_impl::decode(pmt::pmt_t msg) + { + d_bursts[d_collected_bursts_num++] = msg; + if (d_collected_bursts_num <= 7) + { + return; + } + + gsmtap_hdr* header = (gsmtap_hdr*)(pmt::blob_data(pmt::cdr(msg))); + uint32_t frame_nr = be32toh(header->frame_number); + bool uplink_burst = (be16toh(header->arfcn) & 0x4000) ? true : false; + + //TODO: Check in 3gpp specs which frames could contains facch/h frames + //and replace this ugly formula with table + int fn_is_odd = (((frame_nr - (uplink_burst ? 10 : 15)) % 26) >> 2) & 1; + + ubit_t bursts_u[116 * 6] = {0}; //facch/h is 6 bursts + + //reorganize data + for (int ii = 0; ii < 8; ii++) + { + //skip the 4th and 5th bursts + if (ii == 4 || ii == 5) continue; + + int8_t* burst_bits = (int8_t*)(pmt::blob_data(pmt::cdr(d_bursts[ii])))+sizeof(gsmtap_hdr); + + //copy 6th and 7th burst to 4th and 5th position + int n = ii < 6 ? ii : ii - 2; + + memcpy(&bursts_u[n*116], &burst_bits[3],58); + memcpy(&bursts_u[n*116+58], &burst_bits[3+57+1+26],58); + } + + //Convert to sbits + sbit_t bursts_s[116 * 6] = {0}; + ubits2sbits(bursts_u, bursts_s, 116 * 6); + + //Prepare burst for the next iteration by shifting them by 4 + for (int ii = 0; ii < 4; ii++) { + d_bursts[ii] = d_bursts[ii + 4]; + } + d_collected_bursts_num = 4; + + uint8_t frameBuffer[64]; + int frameLength = -1; + int n_errors, n_bits_total; + + if (d_tch_mode == TCH_HS) + { + frameLength = gsm0503_tch_hr_decode(frameBuffer, bursts_s, fn_is_odd, &n_errors, &n_bits_total); + } + else + { + frameLength = gsm0503_tch_ahs_decode(frameBuffer, bursts_s, fn_is_odd, + fn_is_odd, //int codec_mode_req, + &d_multi_rate_codes.front(), d_multi_rate_codes.size(), + &d_ft, + &d_cmr, + &n_errors, &n_bits_total); + } + + if (frameLength < 12) + { + if (!d_boundary_check || d_boundary_decode) { + std::cerr<<"Error! frame_nr:"<type = GSMTAP_TYPE_UM; + + pmt::pmt_t msg_binary_blob = pmt::make_blob(header_plus_data, frameLength + sizeof(gsmtap_hdr)); + pmt::pmt_t msg_out = pmt::cons(pmt::PMT_NIL, msg_binary_blob); + + message_port_pub(pmt::mp("msgs"), msg_out); + + // if d_boundary_check is enabled, we set d_boundary_decode to true, when a + // "Connect" or "Connect Acknowledge" message is received, and + // we set d_boundary_decode back to false, when "Release" message is received + if (d_boundary_check) + { + // check if this is a call control message + if ((frameBuffer[3] & 0x0f) == 0x03) + { + // Connect specified in GSM 04.08, 9.3.5 + if ((frameBuffer[4] & 0x3f) == 0x07) + { + d_boundary_decode = true; + } + // Connect Acknowledge specified in GSM 04.08, 9.3.6 + else if ((frameBuffer[4] & 0x3f) == 0x0f) + { + d_boundary_decode = true; + } + // Release specified in GSM 04.08, 9.3.18 + else if ((frameBuffer[4] & 0x3f) == 0x2d) + { + d_boundary_decode = false; + } + } + } + return; + } + + if (!d_header_sent && d_tch_mode != TCH_HS) + { + const unsigned char amr_nb_magic[7] = "#!AMR\n"; + message_port_pub(pmt::mp("voice"), pmt::cons(pmt::PMT_NIL, pmt::make_blob(amr_nb_magic, 6))); + d_header_sent = true; + } + + if (!n_errors && (!d_boundary_check || d_boundary_decode)) + { + //std::cerr<<"Voice frame_nr:"< + * @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_GSM_TCH_H_DECODER_IMPL_H +#define INCLUDED_GSM_TCH_H_DECODER_IMPL_H + +#include +#include "tch_f_decoder_impl.h" + +namespace gr { + namespace gsm { + + class tch_h_decoder_impl : public tch_h_decoder + { + private: + unsigned int d_collected_bursts_num; + pmt::pmt_t d_bursts[8]; + + enum tch_mode d_tch_mode; + unsigned int d_sub_channel; + + std::vector d_multi_rate_codes; + + bool d_boundary_check; + bool d_boundary_decode; + bool d_header_sent; + + uint8_t d_ft; + uint8_t d_cmr; + + void decode(pmt::pmt_t msg); + public: + tch_h_decoder_impl(unsigned int sub_channel, std::string multi_rate, bool boundary_check=false); + ~tch_h_decoder_impl(); + }; + + } // namespace gsm +} // namespace gr + +#endif /* INCLUDED_GSM_TCH_H_DECODER_IMPL_H */ + diff --git a/lib/demapping/tch_h_chans_demapper_impl.cc b/lib/demapping/tch_h_chans_demapper_impl.cc index 2c3dc79..73f49e1 100644 --- a/lib/demapping/tch_h_chans_demapper_impl.cc +++ b/lib/demapping/tch_h_chans_demapper_impl.cc @@ -87,6 +87,7 @@ void tch_h_chans_demapper_impl::filter_tch_chans(pmt::pmt_t msg) memcpy(new_msg, header, sizeof(gsmtap_hdr)+BURST_SIZE); new_hdr->sub_type = (fn_mod13 == 12 ? GSMTAP_CHANNEL_ACCH : 0) | GSMTAP_CHANNEL_TCH_H; + new_hdr->sub_slot = d_tch_h_channel; pmt::pmt_t msg_binary_blob = pmt::make_blob(new_msg,sizeof(gsmtap_hdr)+BURST_SIZE); pmt::pmt_t msg_out = pmt::cons(pmt::PMT_NIL, msg_binary_blob); diff --git a/swig/grgsm_swig.i b/swig/grgsm_swig.i index dd86bbc..ec1eea7 100644 --- a/swig/grgsm_swig.i +++ b/swig/grgsm_swig.i @@ -38,6 +38,7 @@ #include "grgsm/receiver/cx_channel_hopper.h" #include "grgsm/decoding/control_channels_decoder.h" #include "grgsm/decoding/tch_f_decoder.h" +#include "grgsm/decoding/tch_h_decoder.h" #include "grgsm/decryption/decryption.h" #include "grgsm/demapping/universal_ctrl_chans_demapper.h" #include "grgsm/demapping/tch_f_chans_demapper.h" @@ -91,6 +92,8 @@ GR_SWIG_BLOCK_MAGIC2(gsm, cx_channel_hopper); GR_SWIG_BLOCK_MAGIC2(gsm, control_channels_decoder); %include "grgsm/decoding/tch_f_decoder.h" GR_SWIG_BLOCK_MAGIC2(gsm, tch_f_decoder); +%include "grgsm/decoding/tch_h_decoder.h" +GR_SWIG_BLOCK_MAGIC2(gsm, tch_h_decoder); %include "grgsm/decryption/decryption.h" GR_SWIG_BLOCK_MAGIC2(gsm, decryption); -- cgit v1.2.3