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 ...
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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)