2014-08-24 22:03:08 -04:00
#!/usr/bin/env python
#
2016-11-23 08:50:56 -05:00
###############################################################################
# Copyright (C) 2016 Cortney T. Buffington, N0MJS <n0mjs@me.com>
#
# This program 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 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
2014-08-24 22:03:08 -04:00
2015-08-12 11:06:30 -04:00
# This is a sample application that "plays" a voice tranmission from a file
# that was created with record.py. The file is just a pickle of an entire
# transmission.
#
# This program consults a list of "trigger groups" for each timeslot that
# will initiate playback. When playback occurs, several items are re-written:
# Source Subscriber: this DMRlink's local subscriber ID
# Source Peer: this DMRlink's local subscriber ID
# Timeslot: timeslot of the tranmission that triggered
# TGID: TGID of the message that triggered it
2014-08-24 22:03:08 -04:00
from __future__ import print_function
from twisted . internet import reactor
import sys , time
import cPickle as pickle
2016-12-18 22:51:13 -05:00
from dmrlink import IPSC , systems
from dmr_utils . utils import int_id , hex_str_3
from ipsc . ipsc_const import BURST_DATA_TYPE
2014-08-24 22:03:08 -04:00
2016-11-23 08:50:56 -05:00
__author__ = ' Cortney T. Buffington, N0MJS '
__copyright__ = ' Copyright (c) 2014 - 2015 Cortney T. Buffington, N0MJS and the K0USY Group '
__credits__ = ' Adam Fast, KC0YLK; Dave Kierzkowski KD8EYF '
__license__ = ' GNU GPLv3 '
__maintainer__ = ' Cort Buffington, N0MJS '
__email__ = ' n0mjs@me.com '
2014-08-24 22:03:08 -04:00
2015-08-11 22:18:36 -04:00
# path+filename for the transmission to play back
filename = ' ../test.pickle '
2015-08-12 11:06:30 -04:00
# trigger logic - True, trigger on these IDs, False trigger on any but these IDs
2015-08-12 11:07:52 -04:00
trigger = True
2015-08-12 11:06:30 -04:00
2015-08-11 22:18:36 -04:00
# groups that we want to trigger playback of this file (ts1 and ts2)
2015-08-12 11:14:48 -04:00
# Note this is a python list type, even if there's just one value
2015-08-12 11:06:30 -04:00
trigger_groups_1 = [ ' \x00 \x00 \x01 ' , ' \x00 \x00 \x0D ' , ' \x00 \x00 \x64 ' ]
2015-08-12 11:48:32 -04:00
trigger_groups_2 = [ ' \x00 \x0C \x30 ' , ]
2014-08-24 22:03:08 -04:00
class playIPSC ( IPSC ) :
2016-12-18 22:51:13 -05:00
def __init__ ( self , _name , _config , _logger ) :
IPSC . __init__ ( self , _name , _config , _logger )
2014-08-24 22:03:08 -04:00
self . CALL_DATA = [ ]
2015-08-11 22:18:36 -04:00
self . event_id = 1
2014-08-24 22:03:08 -04:00
#************************************************
# CALLBACK FUNCTIONS FOR USER PACKET TYPES
#************************************************
#
2016-12-18 22:51:13 -05:00
def group_voice ( self , _src_sub , _dst_group , _ts , _end , _peerid , _data ) :
2014-08-24 22:03:08 -04:00
if _end :
2016-12-18 22:51:13 -05:00
_self_peer = self . _config [ ' LOCAL ' ] [ ' RADIO_ID ' ]
2015-08-12 11:57:02 -04:00
_self_src = _self_peer [ 1 : ]
2015-08-12 11:58:02 -04:00
if ( _peerid == _self_peer ) or ( _src_sub == _self_src ) :
2016-12-18 22:51:13 -05:00
self . _logger . error ( ' ( %s ) Just received a packet that appears to have been originated by us. PeerID: %s Subscriber: %s TS: %s , TGID: %s ' , self . _system , int_id ( _peerid ) , int_id ( _src_sub ) , int ( _ts ) , int_id ( _dst_group ) )
2015-08-12 11:57:02 -04:00
return
2015-08-12 11:49:58 -04:00
if trigger == False :
2016-12-18 22:51:13 -05:00
if ( _ts == 1 and _dst_group not in trigger_groups_1 ) or ( _ts == 2 and _dst_group not in trigger_groups_2 ) :
2015-08-12 11:06:30 -04:00
return
else :
2016-12-18 22:51:13 -05:00
if ( _ts == 1 and _dst_group not in trigger_groups_1 ) or ( _ts == 2 and _dst_group not in trigger_groups_2 ) :
2015-08-12 11:06:30 -04:00
return
2016-12-18 22:51:13 -05:00
self . _logger . info ( ' ( %s ) Event ID: %s - Playback triggered from SourceID: %s , TS: %s , TGID: %s , PeerID: %s ' , self . _system , self . event_id , int_id ( _src_sub ) , _ts , int_id ( _dst_group ) , int_id ( _peerid ) )
2015-08-12 11:06:30 -04:00
# Determine the type of voice packet this is (see top of file for possible types)
_burst_data_type = _data [ 30 ]
2015-08-12 10:21:20 -04:00
2015-08-12 11:06:30 -04:00
time . sleep ( 2 )
self . CALL_DATA = pickle . load ( open ( filename , ' rb ' ) )
2016-12-18 22:51:13 -05:00
self . _logger . info ( ' ( %s ) Event ID: %s - Playing back file: %s ' , self . _system , self . event_id , filename )
2015-08-12 11:06:30 -04:00
for i in self . CALL_DATA :
_tmp_data = i
2015-08-12 10:21:20 -04:00
2015-08-12 11:06:30 -04:00
# re-Write the peer radio ID to that of this program
_tmp_data = _tmp_data . replace ( _peerid , _self_peer )
# re-Write the source subscriber ID to that of this program
_tmp_data = _tmp_data . replace ( _src_sub , _self_src )
# Re-Write the destination Group ID
_tmp_data = _tmp_data . replace ( _tmp_data [ 9 : 12 ] , _dst_group )
# Re-Write IPSC timeslot value
_call_info = int_id ( _tmp_data [ 17 : 18 ] )
2016-12-18 22:51:13 -05:00
if _ts == 1 :
2015-08-12 11:06:30 -04:00
_call_info & = ~ ( 1 << 5 )
2016-12-18 22:51:13 -05:00
elif _ts == 2 :
2015-08-12 11:06:30 -04:00
_call_info | = 1 << 5
_call_info = chr ( _call_info )
_tmp_data = _tmp_data [ : 17 ] + _call_info + _tmp_data [ 18 : ]
2015-08-12 10:26:32 -04:00
2015-08-12 11:06:30 -04:00
# Re-Write DMR timeslot value
# Determine if the slot is present, so we can translate if need be
if _burst_data_type == BURST_DATA_TYPE [ ' SLOT1_VOICE ' ] or _burst_data_type == BURST_DATA_TYPE [ ' SLOT2_VOICE ' ] :
# Re-Write timeslot if necessary...
2016-12-18 22:51:13 -05:00
if _ts == 1 :
2015-08-12 11:06:30 -04:00
_burst_data_type = BURST_DATA_TYPE [ ' SLOT1_VOICE ' ]
2016-12-18 22:51:13 -05:00
elif _ts == 2 :
2015-08-12 11:06:30 -04:00
_burst_data_type = BURST_DATA_TYPE [ ' SLOT2_VOICE ' ]
_tmp_data = _tmp_data [ : 30 ] + _burst_data_type + _tmp_data [ 31 : ]
2016-09-09 23:44:40 -04:00
2015-08-12 11:06:30 -04:00
# Send the packet to all peers in the target IPSC
self . send_to_ipsc ( _tmp_data )
time . sleep ( 0.06 )
self . CALL_DATA = [ ]
2016-12-18 22:51:13 -05:00
self . _logger . info ( ' ( %s ) Event ID: %s - Playback Completed ' , self . _system , self . event_id )
2015-08-12 11:06:30 -04:00
self . event_id = self . event_id + 1
2014-08-24 22:03:08 -04:00
2016-12-18 22:51:13 -05:00
2014-08-24 22:03:08 -04:00
if __name__ == ' __main__ ' :
2016-12-18 22:51:13 -05:00
import argparse
import os
import sys
import signal
import dmrlink_log
import dmrlink_config
# Change the current directory to the location of the application
os . chdir ( os . path . dirname ( os . path . realpath ( sys . argv [ 0 ] ) ) )
# CLI argument parser - handles picking up the config file from the command line, and sending a "help" message
parser = argparse . ArgumentParser ( )
parser . add_argument ( ' -c ' , ' --config ' , action = ' store ' , dest = ' CFG_FILE ' , help = ' /full/path/to/config.file (usually dmrlink.cfg) ' )
cli_args = parser . parse_args ( )
if not cli_args . CFG_FILE :
cli_args . CFG_FILE = os . path . dirname ( os . path . abspath ( __file__ ) ) + ' /dmrlink.cfg '
# Call the external routine to build the configuration dictionary
CONFIG = dmrlink_config . build_config ( cli_args . CFG_FILE )
# Call the external routing to start the system logger
logger = dmrlink_log . config_logging ( CONFIG [ ' LOGGER ' ] )
2014-08-24 22:03:08 -04:00
logger . info ( ' DMRlink \' record.py \' (c) 2014 N0MJS & the K0USY Group - SYSTEM STARTING... ' )
2016-12-18 22:51:13 -05:00
# Shut ourselves down gracefully with the IPSC peers.
def sig_handler ( _signal , _frame ) :
logger . info ( ' *** DMRLINK IS TERMINATING WITH SIGNAL %s *** ' , str ( _signal ) )
for system in systems :
this_ipsc = systems [ system ]
logger . info ( ' De-Registering from IPSC %s ' , system )
de_reg_req_pkt = this_ipsc . hashed_packet ( this_ipsc . _local [ ' AUTH_KEY ' ] , this_ipsc . DE_REG_REQ_PKT )
this_ipsc . send_to_ipsc ( de_reg_req_pkt )
reactor . stop ( )
# Set signal handers so that we can gracefully exit if need be
for sig in [ signal . SIGTERM , signal . SIGINT , signal . SIGQUIT ] :
signal . signal ( sig , sig_handler )
# INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC
for system in CONFIG [ ' SYSTEMS ' ] :
if CONFIG [ ' SYSTEMS ' ] [ system ] [ ' LOCAL ' ] [ ' ENABLED ' ] :
systems [ system ] = playIPSC ( system , CONFIG , logger )
reactor . listenUDP ( CONFIG [ ' SYSTEMS ' ] [ system ] [ ' LOCAL ' ] [ ' PORT ' ] , systems [ system ] , interface = CONFIG [ ' SYSTEMS ' ] [ system ] [ ' LOCAL ' ] [ ' IP ' ] )
reactor . run ( )