Ejemplo n.º 1
0
def make_rules(_hb_routing_rules):
    try:
        rule_file = import_module(_hb_routing_rules)
        logger.info('Routing rules file found and rules imported')
    except ImportError:
        sys.exit('Routing rules file not found or invalid')
    
    # Convert integer GROUP ID numbers from the config into hex strings
    # we need to send in the actual data packets.
    for _system in rule_file.RULES:
        for _rule in rule_file.RULES[_system]['GROUP_VOICE']:
            _rule['SRC_GROUP'] = hex_str_3(_rule['SRC_GROUP'])
            _rule['DST_GROUP'] = hex_str_3(_rule['DST_GROUP'])
            _rule['SRC_TS']    = _rule['SRC_TS']
            _rule['DST_TS']    = _rule['DST_TS']
            for i, e in enumerate(_rule['ON']):
                _rule['ON'][i] = hex_str_3(_rule['ON'][i])
            for i, e in enumerate(_rule['OFF']):
                _rule['OFF'][i] = hex_str_3(_rule['OFF'][i])
            _rule['TIMEOUT']= _rule['TIMEOUT']*60
            _rule['TIMER']      = time() + _rule['TIMEOUT']
        if _system not in CONFIG['SYSTEMS']:
            sys.exit('ERROR: Routing rules found for system not configured main configuration')
    for _system in CONFIG['SYSTEMS']:
        if _system not in rule_file.RULES:
            sys.exit('ERROR: Routing rules not found for all systems configured')
    return rule_file.RULES
Ejemplo n.º 2
0
def make_bridge_config(_confbridge_rules):
    try:
        bridge_file = import_module(_confbridge_rules)
        logger.info('Bridge configuration file found and imported')
    except ImportError:
        sys.exit('Bridge configuration file not found or invalid')

    # Convert integer GROUP ID numbers from the config into hex strings
    # we need to send in the actual data packets.
    #
    for _bridge in bridge_file.BRIDGES:
        for _system in bridge_file.BRIDGES[_bridge]:
            if _system['SYSTEM'] not in CONFIG['SYSTEMS']:
                sys.exit('ERROR: Conference bridges found for system not configured main configuration')
                
            _system['TGID']       = hex_str_3(_system['TGID'])
            for i, e in enumerate(_system['ON']):
                _system['ON'][i]  = hex_str_3(_system['ON'][i])
            for i, e in enumerate(_system['OFF']):
                _system['OFF'][i] = hex_str_3(_system['OFF'][i])
            for i, e in enumerate(_system['RESET']):
                _system['RESET'][i] = hex_str_3(_system['RESET'][i])
            _system['TIMEOUT']    = _system['TIMEOUT']*60
            _system['TIMER']      = time()

    return {'BRIDGE_CONF': bridge_file.BRIDGE_CONF, 'BRIDGES': bridge_file.BRIDGES, 'TRUNKS': bridge_file.TRUNKS}
Ejemplo n.º 3
0
    def load_configuration(self, _file_name):
        config = ConfigParser.ConfigParser()
        if not config.read(_file_name):
            sys.exit('Configuration file \'' + _file_name +
                     '\' is not a valid configuration file! Exiting...')
        try:
            for section in config.sections():
                if section == 'DEFAULTS':
                    self._ambeRxPort = int(
                        config.get(section, 'fromGatewayPort').split(None)[0]
                    )  # Port to listen on for AMBE frames to transmit to all peers
                    self._gateway = config.get(section, 'gateway').split(None)[
                        0]  # IP address of Analog_Bridge app
                    self._gateway_port = int(
                        config.get(section, 'toGatewayPort').split(None)[0]
                    )  # Port Analog_Bridge is listening on for AMBE frames to decode
                if section == 'RULES':
                    for rule in config.items(section):
                        _old_tg, _new_tg, _new_slot = rule[1].split(',')
                        translate.add_rule(
                            hex_str_3(int(_old_tg)),
                            (hex_str_3(int(_new_tg)), int(_new_slot)))

        except ConfigParser.Error, err:
            traceback.print_exc()
            sys.exit('Could not parse configuration file, ' + _file_name +
                     ', exiting...')
Ejemplo n.º 4
0
def build_rules(_bridge_rules):
    try:
        rule_file = import_module(_bridge_rules)
        logger.info('Bridge rules file found and rules imported')
    except ImportError:
        sys.exit('Bridging rules file not found or invalid')

    # Convert integer GROUP ID numbers from the config into hex strings
    # we need to send in the actual data packets.
    #

    for _ipsc in rule_file.RULES:
        for _rule in rule_file.RULES[_ipsc]['GROUP_VOICE']:
            _rule['SRC_GROUP']  = hex_str_3(_rule['SRC_GROUP'])
            _rule['DST_GROUP']  = hex_str_3(_rule['DST_GROUP'])
            _rule['SRC_TS']     = _rule['SRC_TS']
            _rule['DST_TS']     = _rule['DST_TS']
            for i, e in enumerate(_rule['ON']):
                _rule['ON'][i]  = hex_str_3(_rule['ON'][i])
            for i, e in enumerate(_rule['OFF']):
                _rule['OFF'][i] = hex_str_3(_rule['OFF'][i])
            _rule['TIMEOUT']= _rule['TIMEOUT']*60
            _rule['TIMER']      = time() + _rule['TIMEOUT']
        if _ipsc not in CONFIG['SYSTEMS']:
            sys.exit('ERROR: Bridge rules found for an IPSC network not configured in main configuration')
    for _ipsc in CONFIG['SYSTEMS']:
        if _ipsc not in rule_file.RULES:
            sys.exit('ERROR: Bridge rules not found for all IPSC network configured')

    return rule_file.RULES
Ejemplo n.º 5
0
def make_rules(_hb_routing_rules):
    try:
        rule_file = import_module(_hb_routing_rules)
        logger.info('Routing rules file found and rules imported')
    except ImportError:
        sys.exit('Routing rules file not found or invalid')

    # Convert integer GROUP ID numbers from the config into hex strings
    # we need to send in the actual data packets.
    for _system in rule_file.RULES:
        for _rule in rule_file.RULES[_system]['GROUP_VOICE']:
            _rule['SRC_GROUP'] = hex_str_3(_rule['SRC_GROUP'])
            _rule['DST_GROUP'] = hex_str_3(_rule['DST_GROUP'])
            _rule['SRC_TS'] = _rule['SRC_TS']
            _rule['DST_TS'] = _rule['DST_TS']
            for i, e in enumerate(_rule['ON']):
                _rule['ON'][i] = hex_str_3(_rule['ON'][i])
            for i, e in enumerate(_rule['OFF']):
                _rule['OFF'][i] = hex_str_3(_rule['OFF'][i])
            _rule['TIMEOUT'] = _rule['TIMEOUT'] * 60
            _rule['TIMER'] = time() + _rule['TIMEOUT']
        if _system not in CONFIG['SYSTEMS']:
            sys.exit(
                'ERROR: Routing rules found for system not configured main configuration'
            )
    for _system in CONFIG['SYSTEMS']:
        if _system not in rule_file.RULES:
            sys.exit(
                'ERROR: Routing rules not found for all systems configured')
    return rule_file.RULES
Ejemplo n.º 6
0
def build_rules(_bridge_rules):
    try:
        rule_file = import_module(_bridge_rules)
        logger.info('Bridge rules file found and rules imported')
    except ImportError:
        sys.exit('Bridging rules file not found or invalid')

    # Convert integer GROUP ID numbers from the config into hex strings
    # we need to send in the actual data packets.
    #

    for _ipsc in rule_file.RULES:
        for _rule in rule_file.RULES[_ipsc]['GROUP_VOICE']:
            _rule['SRC_GROUP'] = hex_str_3(_rule['SRC_GROUP'])
            _rule['DST_GROUP'] = hex_str_3(_rule['DST_GROUP'])
            _rule['SRC_TS'] = _rule['SRC_TS']
            _rule['DST_TS'] = _rule['DST_TS']
            for i, e in enumerate(_rule['ON']):
                _rule['ON'][i] = hex_str_3(_rule['ON'][i])
            for i, e in enumerate(_rule['OFF']):
                _rule['OFF'][i] = hex_str_3(_rule['OFF'][i])
            _rule['TIMEOUT'] = _rule['TIMEOUT'] * 60
            _rule['TIMER'] = time() + _rule['TIMEOUT']
        if _ipsc not in CONFIG['SYSTEMS']:
            sys.exit(
                'ERROR: Bridge rules found for an IPSC network not configured in main configuration'
            )
    for _ipsc in CONFIG['SYSTEMS']:
        if _ipsc not in rule_file.RULES:
            sys.exit(
                'ERROR: Bridge rules not found for all IPSC network configured'
            )

    return rule_file.RULES
Ejemplo n.º 7
0
 def __init__(self, _slot, _rf_src, _dst_id, _repeater_id, _cc):
     self.rf_src = hex_str_3(_rf_src)                # DMR ID of sender
     self.dst_id = hex_str_3(_dst_id)                # Talk group to send to
     self.repeater_id = hex_str_4(_repeater_id)      # Repeater ID
     self.slot = _slot                               # Slot to use
     self.cc = _cc                                   # Color code to use
     self.type = 0                                   # 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F
     self.stream_id = hex_str_4(0)                   # Stream id is same across a single session
     self.frame_count = 0                            # Count of frames in a session
     self.start_time = 0                             # Start of session
     self.time = 0                                   # Current time in session.  Used to calculate duration
Ejemplo n.º 8
0
    def runTest(self, obj):
        obj._logger.info('mike was here')
        _rx_slot = obj.rx[1]

        _rx_slot.slot = 1
        _rx_slot.rf_src = hex_str_3(3113043)
        _rx_slot.repeater_id = hex_str_4(311317)
        _rx_slot.dst_id = hex_str_3(9)
        _rx_slot.cc = 1

        obj.sendBlankAmbe(_rx_slot, hex_str_4(randint(0, 0xFFFFFFFF)))
        thread.start_new_thread(self.play_thread, (obj, ))
Ejemplo n.º 9
0
def build_acl(_sub_acl):
    try:
        logger.info(
            'ACL file found, importing entries. This will take about 1.5 seconds per 1 million IDs'
        )
        acl_file = import_module(_sub_acl)
        sections = acl_file.ACL.split(':')
        ACL_ACTION = sections[0]
        entries_str = sections[1]
        ACL = set()

        for entry in entries_str.split(','):
            if '-' in entry:
                start, end = entry.split('-')
                start, end = int(start), int(end)
                for id in range(start, end + 1):
                    ACL.add(hex_str_3(id))
            else:
                id = int(entry)
                ACL.add(hex_str_3(id))

        logger.info('ACL loaded: action "{}" for {:,} radio IDs'.format(
            ACL_ACTION, len(ACL)))

    except ImportError:
        logger.info(
            'ACL file not found or invalid - all subscriber IDs are valid')
        ACL_ACTION = 'NONE'

    # Depending on which type of ACL is used (PERMIT, DENY... or there isn't one)
    # define a differnet function to be used to check the ACL
    global allow_sub
    if ACL_ACTION == 'PERMIT':

        def allow_sub(_sub):
            if _sub in ACL:
                return True
            else:
                return False
    elif ACL_ACTION == 'DENY':

        def allow_sub(_sub):
            if _sub not in ACL:
                return True
            else:
                return False
    else:

        def allow_sub(_sub):
            return True

    return ACL
Ejemplo n.º 10
0
def build_acl(_sub_acl):
    try:
        acl_file = import_module(_sub_acl)
        for i, e in enumerate(acl_file.ACL):
            acl_file.ACL[i] = hex_str_3(acl_file.ACL[i])
        logger.info('ACL file found and ACL entries imported')
        ACL_ACTION = acl_file.ACL_ACTION
        ACL = acl_file.ACL
    except ImportError:
        logger.info('ACL file not found or invalid - all subscriber IDs are valid')
        ACL_ACTION = 'NONE'
        ACL = []

    # Depending on which type of ACL is used (PERMIT, DENY... or there isn't one)
    # define a differnet function to be used to check the ACL
    global allow_sub
    if ACL_ACTION == 'PERMIT':
        def allow_sub(_sub):
            if _sub in ACL:
                return True
            else:
                return False
    elif ACL_ACTION == 'DENY':
        def allow_sub(_sub):
            if _sub not in ACL:
                return True
            else:
                return False
    else:
        def allow_sub(_sub):
            return True
    
    return ACL
Ejemplo n.º 11
0
    def readConfigFile(self, configFileName, sec, networkName='DEFAULTS'):
        config = ConfigParser.ConfigParser()
        try:
            config.read(configFileName)
            
            if sec == None:
                sec = self.defaultOption(config, 'DEFAULTS', 'section', networkName)
            if config.has_section(sec) == False:
                logger.error('Section ' + sec + ' was not found, using DEFAULTS')
                sec = 'DEFAULTS'
            self._debug = bool(self.defaultOption(config, sec,'debug', self._debug) == 'True')
            self._outToFile = bool(self.defaultOption(config, sec,'outToFile', self._outToFile) == 'True')
            self._outToUDP = bool(self.defaultOption(config, sec,'outToUDP', self._outToUDP) == 'True')

            self._gateway = self.defaultOption(config, sec,'gateway', self._gateway)
            self._gateway_port = int(self.defaultOption(config, sec,'toGatewayPort', self._gateway_port))

            self._remote_control_port = int(self.defaultOption(config, sec,'remoteControlPort', self._remote_control_port))
            self._ambeRxPort = int(self.defaultOption(config, sec,'fromGatewayPort', self._ambeRxPort))
            self._gateway_dmr_id = int(self.defaultOption(config, sec, 'gatewayDmrId', self._gateway_dmr_id))

            _tgs = self.defaultOption(config, sec,'tgFilter', str(self._tg_filter).strip('[]'))
            self._tg_filter = map(int, _tgs.split(','))

            self._tx_tg = hex_str_3(int(self.defaultOption(config, sec, 'txTg', int_id(self._tx_tg))))
            self._tx_ts = int(self.defaultOption(config, sec, 'txTs', self._tx_ts))

        except ConfigParser.NoOptionError as e:
            print('Using a default value:', e)
        except:
            traceback.print_exc()
            sys.exit('Configuration file \''+configFileName+'\' is not a valid configuration file! Exiting...')
Ejemplo n.º 12
0
def build_acl(_sub_acl):
    try:
        acl_file = import_module(_sub_acl)
        for i, e in enumerate(acl_file.ACL):
            acl_file.ACL[i] = hex_str_3(acl_file.ACL[i])
        logger.info('ACL file found and ACL entries imported')
        ACL_ACTION = acl_file.ACL_ACTION
        ACL = acl_file.ACL_ACTION
    except ImportError:
        logger.info('ACL file not found or invalid - all subscriber IDs are valid')
        ACL_ACTION = 'NONE'
        ACL = []

    # Depending on which type of ACL is used (PERMIT, DENY... or there isn't one)
    # define a differnet function to be used to check the ACL
    global allow_sub
    if ACL_ACTION == 'PERMIT':
        def allow_sub(_sub):
            if _sub in ACL:
                return True
            else:
                return False
    elif ACL_ACTION == 'DENY':
        def allow_sub(_sub):
            if _sub not in ACL:
                return True
            else:
                return False
    else:
        def allow_sub(_sub):
            return True
    
    return ACL
Ejemplo n.º 13
0
def build_acl(_sub_acl):
    try:
        logger.info('ACL file found, importing entries. This will take about 1.5 seconds per 1 million IDs')
        acl_file = import_module(_sub_acl)
        sections = acl_file.ACL.split(':')
        ACL_ACTION = sections[0]
        entries_str = sections[1]
        ACL = set()
        
        for entry in entries_str.split(','):
            if '-' in entry:
                start,end = entry.split('-')
                start,end = int(start), int(end)
                for id in range(start, end+1):
                    ACL.add(hex_str_3(id))
            else:
                id = int(entry)
                ACL.add(hex_str_3(id))
        
        logger.info('ACL loaded: action "{}" for {:,} radio IDs'.format(ACL_ACTION, len(ACL)))
    
    except ImportError:
        logger.info('ACL file not found or invalid - all subscriber IDs are valid')
        ACL_ACTION = 'NONE'

    # Depending on which type of ACL is used (PERMIT, DENY... or there isn't one)
    # define a differnet function to be used to check the ACL
    global allow_sub
    if ACL_ACTION == 'PERMIT':
        def allow_sub(_sub):
            if _sub in ACL:
                return True
            else:
                return False
    elif ACL_ACTION == 'DENY':
        def allow_sub(_sub):
            if _sub not in ACL:
                return True
            else:
                return False
    else:
        def allow_sub(_sub):
            return True
    
    return ACL
Ejemplo n.º 14
0
    def readConfigFile(self, configFileName, sec, networkName='DEFAULTS'):
        config = ConfigParser.ConfigParser()
        try:
            config.read(configFileName)

            if sec == None:
                sec = self.defaultOption(config, 'DEFAULTS', 'section',
                                         networkName)
            if config.has_section(sec) == False:
                logger.error('Section ' + sec +
                             ' was not found, using DEFAULTS')
                sec = 'DEFAULTS'
            self._debug = bool(
                self.defaultOption(config, sec, 'debug', self._debug) ==
                'True')
            self._outToFile = bool(
                self.defaultOption(config, sec, 'outToFile', self._outToFile)
                == 'True')
            self._outToUDP = bool(
                self.defaultOption(config, sec, 'outToUDP', self._outToUDP) ==
                'True')

            self._gateway = self.defaultOption(config, sec, 'gateway',
                                               self._gateway)
            self._gateway_port = int(
                self.defaultOption(config, sec, 'toGatewayPort',
                                   self._gateway_port))

            self._remote_control_port = int(
                self.defaultOption(config, sec, 'remoteControlPort',
                                   self._remote_control_port))
            self._ambeRxPort = int(
                self.defaultOption(config, sec, 'fromGatewayPort',
                                   self._ambeRxPort))
            self._gateway_dmr_id = int(
                self.defaultOption(config, sec, 'gatewayDmrId',
                                   self._gateway_dmr_id))

            _tgs = self.defaultOption(config, sec, 'tgFilter',
                                      str(self._tg_filter).strip('[]'))
            self._tg_filter = map(int, _tgs.split(','))

            self._tx_tg = hex_str_3(
                int(
                    self.defaultOption(config, sec, 'txTg',
                                       int_id(self._tx_tg))))
            self._tx_ts = int(
                self.defaultOption(config, sec, 'txTs', self._tx_ts))

        except ConfigParser.NoOptionError as e:
            print('Using a default value:', e)
        except:
            traceback.print_exc()
            sys.exit('Configuration file \'' + configFileName +
                     '\' is not a valid configuration file! Exiting...')
Ejemplo n.º 15
0
    def playbackFromUDP(self, _sock):
        _delay = 0.055                                      # Yes, I know it should be 0.06, but there seems to be some latency, so this is a hack
        _src_sub = hex_str_3(self._gateway_dmr_id)          # DMR ID to sign this transmission with
        _src_peer = NETWORK[self._system]['LOCAL']['RADIO_ID']  # Use this peers ID as the source repeater

        logger.info('Transmit from gateway to TG {}:'.format(int_id(self._tx_tg)) )
        try:
            
            try:
                _t = open('template.bin', 'rb')             # Open the template file.  This was recorded OTA

                _tempHead = [0] * 3                         # It appears that there 3 frames of HEAD (mostly the same)
                for i in range(0, 3):
                    _tempHead[i] = self.readRecord(_t, BURST_DATA_TYPE['VOICE_HEAD'])

                _tempVoice = [0] * 6
                for i in range(0, 6):                       # Then there are 6 frames of AMBE.  We will just use them in order
                    _tempVoice[i] = self.readRecord(_t, BURST_DATA_TYPE['SLOT2_VOICE'])
                
                _tempTerm = self.readRecord(_t, BURST_DATA_TYPE['VOICE_TERM'])
                _t.close()
            except IOError:
                logger.error('Can not open template.bin file')
                return
            logger.debug('IPSC templates loaded')
            
            _eof = False
            self._seq = randint(0,32767)                    # A transmission uses a random number to begin its sequence (16 bit)

            for i in range(0, 3):                           # Output the 3 HEAD frames to our peers
                self.rewriteFrame(_tempHead[i], self._system, self._tx_ts, self._tx_tg, _src_sub, _src_peer)
                #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempHead[i])
                sleep(_delay)

            i = 0                                           # Initialize the VOICE template index
            while(_eof == False):
                _ambe = self.readAmbeFrameFromUDP(_sock)              # Read the 49*3 bit sample from the stream
                if _ambe:
                    i = (i + 1) % 6                         # Round robbin with the 6 VOICE templates
                    _frame = _tempVoice[i][:33] + _ambe + _tempVoice[i][52:]    # Insert the 3 49 bit AMBE frames
                    
                    self.rewriteFrame(_frame, self._system, self._tx_ts, self._tx_tg, _src_sub, _src_peer)
                    #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _frame)

                    sleep(_delay)                           # Since this comes from a file we have to add delay between IPSC frames
                else:
                    _eof = True                             # There are no more AMBE frames, so terminate the loop

            self.rewriteFrame(_tempTerm, self._system, self._tx_ts, self._tx_tg, _src_sub, _src_peer)
            #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempTerm)

        except IOError:
            logger.error('Can not transmit to peers')
        logger.info('Transmit complete')
Ejemplo n.º 16
0
 def __init__(self, _name, _config, _logger, _report):
     IPSC.__init__(self, _name, _config, _logger, _report)
     self.CALL_DATA = []
     
     if GROUP_SRC_SUB:
         self._logger.info('Playback: USING SUBSCRIBER ID: %s FOR GROUP REPEAT', GROUP_SRC_SUB)
         self.GROUP_SRC_SUB = hex_str_3(GROUP_SRC_SUB)
     
     if GROUP_REPEAT:
         self._logger.info('Playback: GROUP REPEAT ENABLED')
         
     if PRIVATE_REPEAT:
         self._logger.info('Playback: PRIVATE REPEAT ENABLED')
Ejemplo n.º 17
0
    def __init__(self, _name, _config, _logger, _report):
        IPSC.__init__(self, _name, _config, _logger, _report)
        self.CALL_DATA = []

        if GROUP_SRC_SUB:
            self._logger.info(
                'Playback: USING SUBSCRIBER ID: %s FOR GROUP REPEAT',
                GROUP_SRC_SUB)
            self.GROUP_SRC_SUB = hex_str_3(GROUP_SRC_SUB)

        if GROUP_REPEAT:
            self._logger.info('Playback: GROUP REPEAT ENABLED')

        if PRIVATE_REPEAT:
            self._logger.info('Playback: PRIVATE REPEAT ENABLED')
Ejemplo n.º 18
0
while True:
    ts = raw_input('Which timeslot (1, 2 or \'both\')? ')
    if ts == '1' or ts == '2' or ts == 'both':
        if ts == '1':
            ts = (1, )
        if ts == '2':
            ts = (2, )
        if ts == 'both':
            ts = (1, 2)
        break
    print('...input must be \'1\', \'2\' or \'both\'')

id = raw_input('Which Group or Subscriber ID to record? ')
id = int(id)
id = hex_str_3(id)

filename = raw_input('Filename to use for this recording? ')


class recordIPSC(IPSC):
    def __init__(self, _name, _config, _logger):
        IPSC.__init__(self, _name, _config, _logger)
        self.CALL_DATA = []

    #************************************************
    #     CALLBACK FUNCTIONS FOR USER PACKET TYPES
    #************************************************
    #
    if tx_type == 'g':
        print('Initializing to record GROUP VOICE transmission')
Ejemplo n.º 19
0
    def remote_control(self, port):
        s = socket.socket()  # Create a socket object

        s.bind(('', port))  # Bind to the port
        s.listen(5)  # Now wait for client connection.
        logger.info('Remote control is listening on {}:{}'.format(
            socket.getfqdn(), port))

        while True:
            c, addr = s.accept()  # Establish connection with client.
            logger.info('Got connection from {}'.format(addr))
            self._dmrgui = addr[0]
            _tmp = c.recv(1024)
            _tmp = _tmp.split(None)[0]  #first get rid of whitespace
            _cmd = _tmp.split('=')[0]
            logger.info('Command:"{}"'.format(_cmd))
            if _cmd:
                if _cmd == 'reread_subscribers':
                    reread_subscribers()
                elif _cmd == 'reread_config':
                    self.readConfigFile(self._configFile, None,
                                        self._currentNetwork)
                elif _cmd == 'txTg':
                    self._tx_tg = hex_str_3(int(_tmp.split('=')[1]))
                    print('New txTg = ' + str(int_id(self._tx_tg)))
                elif _cmd == 'txTs':
                    self._tx_ts = int(_tmp.split('=')[1])
                    print('New txTs = ' + str(self._tx_ts))
                elif _cmd == 'section':
                    self.readConfigFile(self._configFile, _tmp.split('=')[1])
                elif _cmd == 'gateway_dmr_id':
                    self._gateway_dmr_id = int(_tmp.split('=')[1])
                    print('New gateway_dmr_id = ' + str(self._gateway_dmr_id))
                elif _cmd == 'gateway_peer_id':
                    peerID = int(_tmp.split('=')[1])
                    self._config['LOCAL']['RADIO_ID'] = hex_str_3(peerID)
                    print('New peer_id = ' + str(peerID))
                elif _cmd == 'restart':
                    reactor.callFromThread(reactor.stop)
                elif _cmd == 'playbackFromFile':
                    self.playbackFromFile('ambe.bin')
                elif _cmd == 'tgs':
                    _args = _tmp.split('=')[1]
                    self._tg_filter = map(int, _args.split(','))
                    logger.info('New TGs={}'.format(self._tg_filter))
                elif _cmd == 'dump_template':
                    self.dumpTemplate('PrivateVoice.bin')
                elif _cmd == 'get_alias':
                    self._sock.sendto(
                        'reply dmr_info {} {} {} {}'.format(
                            self._currentNetwork,
                            int_id(self._CONFIG[self._currentNetwork]['LOCAL']
                                   ['RADIO_ID']), self._gateway_dmr_id,
                            get_subscriber_info(hex_str_3(
                                self._gateway_dmr_id))), (self._dmrgui, 34003))
                elif _cmd == 'eval':
                    _sz = len(_tmp) - 5
                    _evalExpression = _tmp[-_sz:]
                    _evalResult = eval(_evalExpression)
                    print("eval of {} is {}".format(_evalExpression,
                                                    _evalResult))
                    self._sock.sendto('reply eval {}'.format(_evalResult),
                                      (self._dmrgui, 34003))
                elif _cmd == 'exec':
                    _sz = len(_tmp) - 5
                    _evalExpression = _tmp[-_sz:]
                    exec(_evalExpression)
                    print("exec of {}".format(_evalExpression))
                else:
                    logger.error('Unknown command')
            c.close()  # Close the connection
Ejemplo n.º 20
0
class ambeIPSC(IPSC):

    _configFile = 'ambe_audio.cfg'  # Name of the config file to over-ride these default values
    _debug = False  # Debug output for each VOICE frame
    _outToFile = False  # Write each AMBE frame to a file called ambe.bin
    _outToUDP = True  # Send each AMBE frame to the _sock object (turn on/off DMRGateway operation)
    #_gateway = "192.168.1.184"
    _gateway = "127.0.0.1"  # IP address of DMRGateway app
    _gateway_port = 31000  # Port DMRGateway is listening on for AMBE frames to decode
    _remote_control_port = 31002  # Port that ambe_audio is listening on for remote control commands
    _ambeRxPort = 31003  # Port to listen on for AMBE frames to transmit to all peers
    _gateway_dmr_id = 0  # id to use when transmitting from the gateway
    _tg_filter = [2, 3, 13, 3174, 3777215, 3100, 9, 9998,
                  3112]  #set this to the tg to monitor

    _no_tg = -99  # Flag (const) that defines a value for "no tg is currently active"
    _busy_slots = [
        0, 0, 0
    ]  # Keep track of activity on each slot.  Make sure app is polite
    _sock = -1
    # Socket object to send AMBE to DMRGateway
    lastPacketTimeout = 0  # Time of last packet. Used to trigger an artifical TERM if one was not seen
    _transmitStartTime = 0  # Used for info on transmission duration
    _start_seq = 0  # Used to maintain error statistics for a transmission
    _packet_count = 0  # Used to maintain error statistics for a transmission
    _seq = 0  # Transmit frame sequence number (auto-increments for each frame)
    _f = None  # File handle for debug AMBE binary output

    _tx_tg = hex_str_3(
        9998
    )  # Hard code the destination TG.  This ensures traffic will not show up on DMR-MARC
    _tx_ts = 2  # Time Slot 2
    _currentNetwork = ""
    _dmrgui = ''

    ###### DEBUGDEBUGDEBUG
    #_d = None
    ###### DEBUGDEBUGDEBUG

    def __init__(self, _name, _config, _logger, _report):
        IPSC.__init__(self, _name, _config, _logger, _report)
        self.CALL_DATA = []

        #
        # Define default values for operation.  These will be overridden by the .cfg file if found
        #

        self._currentTG = self._no_tg
        self._currentNetwork = str(_name)
        self.readConfigFile(self._configFile, None, self._currentNetwork)

        logger.info('DMRLink ambe server')
        if self._gateway_dmr_id == 0:
            sys.exit("Error: gatewayDmrId must be set (greater than zero)")
        #
        # Open output sincs
        #
        if self._outToFile == True:
            self._f = open('ambe.bin', 'wb')
            logger.info('Opening output file: ambe.bin')
        if self._outToUDP == True:
            self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            logger.info('Send UDP frames to DMR gateway {}:{}'.format(
                self._gateway, self._gateway_port))

        ###### DEBUGDEBUGDEBUG
        #self._d = open('recordData.bin', 'wb')
        ###### DEBUGDEBUGDEBUG

        try:
            thread.start_new_thread(self.remote_control,
                                    (self._remote_control_port,
                                     ))  # Listen for remote control commands
            thread.start_new_thread(
                self.launchUDP,
                (_name,
                 ))  # Package AMBE into IPSC frames and send to all peers
        except:
            traceback.print_exc()
            logger.error("Error: unable to start thread")

    # Utility function to convert bytes to string of hex values (for debug)
    def ByteToHex(self, byteStr):
        return ''.join(["%02X " % ord(x) for x in byteStr]).strip()

    #
    # Now read the configuration file and parse out the values we need
    #
    def defaultOption(self, config, sec, opt, defaultValue):
        try:
            _value = config.get(
                sec,
                opt).split(None)[0]  # Get the value from the named section
        except ConfigParser.NoOptionError as e:
            try:
                _value = config.get(
                    'DEFAULTS',
                    opt).split(None)[0]  # Try the global DEFAULTS section
            except ConfigParser.NoOptionError as e:
                _value = defaultValue  # Not found anywhere, use the default value
        logger.info(opt + ' = ' + str(_value))
        return _value

    def readConfigFile(self, configFileName, sec, networkName='DEFAULTS'):
        config = ConfigParser.ConfigParser()
        try:
            config.read(configFileName)

            if sec == None:
                sec = self.defaultOption(config, 'DEFAULTS', 'section',
                                         networkName)
            if config.has_section(sec) == False:
                logger.error('Section ' + sec +
                             ' was not found, using DEFAULTS')
                sec = 'DEFAULTS'
            self._debug = bool(
                self.defaultOption(config, sec, 'debug', self._debug) ==
                'True')
            self._outToFile = bool(
                self.defaultOption(config, sec, 'outToFile', self._outToFile)
                == 'True')
            self._outToUDP = bool(
                self.defaultOption(config, sec, 'outToUDP', self._outToUDP) ==
                'True')

            self._gateway = self.defaultOption(config, sec, 'gateway',
                                               self._gateway)
            self._gateway_port = int(
                self.defaultOption(config, sec, 'toGatewayPort',
                                   self._gateway_port))

            self._remote_control_port = int(
                self.defaultOption(config, sec, 'remoteControlPort',
                                   self._remote_control_port))
            self._ambeRxPort = int(
                self.defaultOption(config, sec, 'fromGatewayPort',
                                   self._ambeRxPort))
            self._gateway_dmr_id = int(
                self.defaultOption(config, sec, 'gatewayDmrId',
                                   self._gateway_dmr_id))

            _tgs = self.defaultOption(config, sec, 'tgFilter',
                                      str(self._tg_filter).strip('[]'))
            self._tg_filter = map(int, _tgs.split(','))

            self._tx_tg = hex_str_3(
                int(
                    self.defaultOption(config, sec, 'txTg',
                                       int_id(self._tx_tg))))
            self._tx_ts = int(
                self.defaultOption(config, sec, 'txTs', self._tx_ts))

        except ConfigParser.NoOptionError as e:
            print('Using a default value:', e)
        except:
            traceback.print_exc()
            sys.exit('Configuration file \'' + configFileName +
                     '\' is not a valid configuration file! Exiting...')

    def rewriteFrame(self, _frame, _newSlot, _newGroup, _newSouceID,
                     _newPeerID):

        _peerid = _frame[1:5]  # int32 peer who is sending us a packet
        _src_sub = _frame[6:9]  # int32 Id of source
        _burst_data_type = _frame[30]

        ########################################################################
        # re-Write the peer radio ID to that of this program
        _frame = _frame.replace(_peerid, _newPeerID)
        # re-Write the source subscriber ID to that of this program
        _frame = _frame.replace(_src_sub, _newSouceID)
        # Re-Write the destination Group ID
        _frame = _frame.replace(_frame[9:12], _newGroup)

        # Re-Write IPSC timeslot value
        _call_info = int_id(_frame[17:18])
        if _newSlot == 1:
            _call_info &= ~(1 << 5)
        elif _newSlot == 2:
            _call_info |= 1 << 5
        _call_info = chr(_call_info)
        _frame = _frame[:17] + _call_info + _frame[18:]

        _x = struct.pack("i", self._seq)
        _frame = _frame[:20] + _x[1] + _x[0] + _frame[22:]
        self._seq = self._seq + 1

        # 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...
            if _newSlot == 1:
                _burst_data_type = BURST_DATA_TYPE['SLOT1_VOICE']
            elif _newSlot == 2:
                _burst_data_type = BURST_DATA_TYPE['SLOT2_VOICE']
            _frame = _frame[:30] + _burst_data_type + _frame[31:]

        if (time() - self._busy_slots[_newSlot]
            ) >= 0.10:  # slot is not busy so it is safe to transmit
            # Send the packet to all peers in the target IPSC
            self.send_to_ipsc(_frame)
        else:
            logger.info(
                'Slot {} is busy, will not transmit packet from gateway'.
                format(_newSlot))

    ########################################################################

    # Read a record from the captured IPSC file looking for a payload type that matches the filter
    def readRecord(self, _file, _match_type):
        _notEOF = True
        #        _file.seek(0)
        while (_notEOF):
            _data = ""
            _bLen = _file.read(4)
            if _bLen:
                _len, = struct.unpack("i", _bLen)
                if _len > 0:
                    _data = _file.read(_len)
                    _payload_type = _data[30]
                    if _payload_type == _match_type:
                        return _data
                else:
                    _notEOF = False
            else:
                _notEOF = False
        return _data

    # Read bytes from the socket with "timeout"  I hate this code.
    def readSock(self, _sock, len):
        counter = 0
        while (counter < 3):
            _ambe = _sock.recv(len)
            if _ambe: break
            sleep(0.1)
            counter = counter + 1
        return _ambe

    # Concatenate 3 frames from the stream into a bit array and return the bytes
    def readAmbeFrameFromUDP(self, _sock):
        _ambeAll = BitArray()  # Start with an empty array
        for i in range(0, 3):
            _ambe = self.readSock(_sock, 7)  # Read AMBE from the socket
            if _ambe:
                _ambe1 = BitArray('0x' + h(_ambe[0:49]))
                _ambeAll += _ambe1[0:50]  # Append the 49 bits to the string
            else:
                break
        return _ambeAll.tobytes()  # Return the 49 * 3 as an array of bytes

    # Set up the socket and run the method to gather the AMBE.  Sending it to all peers
    def launchUDP(self, _name):
        s = socket.socket()  # Create a socket object
        s.bind(('', self._ambeRxPort))  # Bind to the port

        while (1):  # Forever!
            s.listen(5)  # Now wait for client connection.
            _sock, addr = s.accept()  # Establish connection with client.
            if int_id(self._tx_tg) > 0:  # Test if we are allowed to transmit
                self.playbackFromUDP(_sock)  # SSZ was here.
            else:
                self.transmitDisabled(
                    _sock,
                    self._system)  #tg is zero, so just eat the network trafic
            _sock.close()

    # This represents a full transmission (HEAD, VOICE and TERM)
    def playbackFromUDP(self, _sock):
        _delay = 0.055  # Yes, I know it should be 0.06, but there seems to be some latency, so this is a hack
        _src_sub = hex_str_3(
            self._gateway_dmr_id)  # DMR ID to sign this transmission with
        _src_peer = self._config['LOCAL'][
            'RADIO_ID']  # Use this peers ID as the source repeater

        logger.info('Transmit from gateway to TG {}:'.format(
            int_id(self._tx_tg)))
        try:

            try:
                _t = open(
                    'template.bin',
                    'rb')  # Open the template file.  This was recorded OTA

                _tempHead = [
                    0
                ] * 3  # It appears that there 3 frames of HEAD (mostly the same)
                for i in range(0, 3):
                    _tempHead[i] = self.readRecord(
                        _t, BURST_DATA_TYPE['VOICE_HEAD'])

                _tempVoice = [0] * 6
                for i in range(
                        0, 6
                ):  # Then there are 6 frames of AMBE.  We will just use them in order
                    _tempVoice[i] = self.readRecord(
                        _t, BURST_DATA_TYPE['SLOT2_VOICE'])

                _tempTerm = self.readRecord(_t, BURST_DATA_TYPE['VOICE_TERM'])
                _t.close()
            except IOError:
                logger.error('Can not open template.bin file')
                return
            logger.debug('IPSC templates loaded')

            _eof = False
            self._seq = randint(
                0, 32767
            )  # A transmission uses a random number to begin its sequence (16 bit)

            for i in range(0, 3):  # Output the 3 HEAD frames to our peers
                self.rewriteFrame(_tempHead[i], self._tx_ts, self._tx_tg,
                                  _src_sub, _src_peer)
                #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempHead[i])
                sleep(_delay)

            i = 0  # Initialize the VOICE template index
            while (_eof == False):
                _ambe = self.readAmbeFrameFromUDP(
                    _sock)  # Read the 49*3 bit sample from the stream
                if _ambe:
                    i = (i + 1) % 6  # Round robbin with the 6 VOICE templates
                    _frame = _tempVoice[i][:33] + _ambe + _tempVoice[i][
                        52:]  # Insert the 3 49 bit AMBE frames

                    self.rewriteFrame(_frame, self._tx_ts, self._tx_tg,
                                      _src_sub, _src_peer)
                    #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _frame)

                    sleep(
                        _delay
                    )  # Since this comes from a file we have to add delay between IPSC frames
                else:
                    _eof = True  # There are no more AMBE frames, so terminate the loop

            self.rewriteFrame(_tempTerm, self._tx_ts, self._tx_tg, _src_sub,
                              _src_peer)
            #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempTerm)

        except IOError:
            logger.error('Can not transmit to peers')
        logger.info('Transmit complete')

    def transmitDisabled(self, _sock):
        _eof = False
        logger.debug('Transmit disabled begin')
        while (_eof == False):
            if self.readAmbeFrameFromUDP(_sock):
                pass
            else:
                _eof = True  # There are no more AMBE frames, so terminate the loop
        logger.debug('Transmit disabled end')

    # Debug method used to test the AMBE code.
    def playbackFromFile(self, _fileName):
        _r = open(_fileName, 'rb')
        _eof = False

        host = socket.gethostbyname(
            socket.gethostname())  # Get local machine name
        _sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        _sock.connect((host, self._ambeRxPort))

        while (_eof == False):

            for i in range(0, 3):
                _ambe = _r.read(7)
                if _ambe:
                    _sock.send(_ambe)
                else:
                    _eof = True
            sleep(0.055)
        logger.info('File playback complete')

    def dumpTemplate(self, _fileName):
        _file = open(_fileName, 'rb')
        _eof = False

        while (_eof == False):
            _data = ""
            _bLen = _file.read(4)
            if _bLen:
                _len, = struct.unpack("i", _bLen)
                if _len > 0:
                    _data = _file.read(_len)
                    self.dumpIPSCFrame(_data)
            else:
                _eof = True
        logger.info('File dump complete')

    #************************************************
    #     CALLBACK FUNCTIONS FOR USER PACKET TYPES
    #************************************************
    #

    def group_voice(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data):

        #self.dumpIPSCFrame(_data)

        # THIS FUNCTION IS NOT COMPLETE!!!!
        _payload_type = _data[30:31]
        # _ambe_frames = _data[33:52]
        _ambe_frames = BitArray('0x' + h(_data[33:52]))
        _ambe_frame1 = _ambe_frames[0:49]
        _ambe_frame2 = _ambe_frames[50:99]
        _ambe_frame3 = _ambe_frames[100:149]

        _tg_id = int_id(_dst_sub)

        self._busy_slots[_ts] = time()

        ###### DEBUGDEBUGDEBUG
        #        if _tg_id == 2:
        #            __iLen = len(_data)
        #            self._d.write(struct.pack("i", __iLen))
        #            self._d.write(_data)
        #        else:
        #            self.rewriteFrame(_data, 1, 9)
        ###### DEBUGDEBUGDEBUG

        if _tg_id in self._tg_filter:  #All TGs
            _dst_sub = get_alias(_dst_sub, talkgroup_ids)
            if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
                if self._currentTG == self._no_tg:
                    _src_sub = get_subscriber_info(_src_sub)
                    logger.info(
                        'Voice Transmission Start on TS {} and TG {} ({}) from {}'
                        .format(_ts, _dst_sub, _tg_id, _src_sub))
                    self._sock.sendto(
                        'reply log2 {} {}'.format(_src_sub, _tg_id),
                        (self._dmrgui, 34003))

                    self._currentTG = _tg_id
                    self._transmitStartTime = time()
                    self._start_seq = int_id(_data[20:22])
                    self._packet_count = 0
                else:
                    if self._currentTG != _tg_id:
                        if time() > self.lastPacketTimeout:
                            self._currentTG = self._no_tg  #looks like we never saw an EOT from the last stream
                            logger.warning('EOT timeout')
                        else:
                            logger.warning(
                                'Transmission in progress, will not decode stream on TG {}'
                                .format(_tg_id))
            if self._currentTG == _tg_id:
                if _payload_type == BURST_DATA_TYPE['VOICE_TERM']:
                    _source_packets = (
                        int_id(_data[20:22]) - self._start_seq
                    ) - 3  # the 3 is because  the start and end are not part of the voice but counted in the RTP
                    if self._packet_count > _source_packets:
                        self._packet_count = _source_packets
                    if _source_packets > 0:
                        _lost_percentage = 100.0 - (
                            (self._packet_count / float(_source_packets)) *
                            100.0)
                    else:
                        _lost_percentage = 0.0
                    _duration = (time() - self._transmitStartTime)
                    logger.info(
                        'Voice Transmission End {:.2f} seconds loss rate: {:.2f}% ({}/{})'
                        .format(_duration, _lost_percentage,
                                _source_packets - self._packet_count,
                                _source_packets))
                    self._sock.sendto(
                        "reply log" +
                        strftime(" %m/%d/%y %H:%M:%S",
                                 localtime(self._transmitStartTime)) +
                        ' {} {} "{}"'.format(get_subscriber_info(_src_sub),
                                             _ts, _dst_sub) +
                        ' {:.2f}%'.format(_lost_percentage) +
                        ' {:.2f}s'.format(_duration), (self._dmrgui, 34003))
                    self._currentTG = self._no_tg
                if _payload_type == BURST_DATA_TYPE['SLOT1_VOICE']:
                    self.outputFrames(_ambe_frames, _ambe_frame1, _ambe_frame2,
                                      _ambe_frame3)
                    self._packet_count += 1
                if _payload_type == BURST_DATA_TYPE['SLOT2_VOICE']:
                    self.outputFrames(_ambe_frames, _ambe_frame1, _ambe_frame2,
                                      _ambe_frame3)
                    self._packet_count += 1
                self.lastPacketTimeout = time() + 10

        else:
            if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
                _dst_sub = get_alias(_dst_sub, talkgroup_ids)
                logger.warning(
                    'Ignored Voice Transmission Start on TS {} and TG {}'.
                    format(_ts, _dst_sub))

    def outputFrames(self, _ambe_frames, _ambe_frame1, _ambe_frame2,
                     _ambe_frame3):
        if self._debug == True:
            logger.debug(_ambe_frames)
            logger.debug('Frame 1:', self.ByteToHex(_ambe_frame1.tobytes()))
            logger.debug('Frame 2:', self.ByteToHex(_ambe_frame2.tobytes()))
            logger.debug('Frame 3:', self.ByteToHex(_ambe_frame3.tobytes()))

        if self._outToFile == True:
            self._f.write(_ambe_frame1.tobytes())
            self._f.write(_ambe_frame2.tobytes())
            self._f.write(_ambe_frame3.tobytes())

        if self._outToUDP == True:
            self._sock.sendto(_ambe_frame1.tobytes(),
                              (self._gateway, self._gateway_port))
            self._sock.sendto(_ambe_frame2.tobytes(),
                              (self._gateway, self._gateway_port))
            self._sock.sendto(_ambe_frame3.tobytes(),
                              (self._gateway, self._gateway_port))

    def private_voice(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data):
        print('private voice')


#        __iLen = len(_data)
#        self._d.write(struct.pack("i", __iLen))
#        self._d.write(_data)

#
# Remote control thread
# Use netcat to dynamically change ambe_audio without a restart
# echo -n "tgs=x,y,z" | nc 127.0.0.1 31002
# echo -n "reread_subscribers" | nc 127.0.0.1 31002
# echo -n "reread_config" | nc 127.0.0.1 31002
# echo -n "txTg=##" | nc 127.0.0.1 31002
# echo -n "txTs=#" | nc 127.0.0.1 31002
# echo -n "section=XX" | nc 127.0.0.1 31002
#

    def remote_control(self, port):
        s = socket.socket()  # Create a socket object

        s.bind(('', port))  # Bind to the port
        s.listen(5)  # Now wait for client connection.
        logger.info('Remote control is listening on {}:{}'.format(
            socket.getfqdn(), port))

        while True:
            c, addr = s.accept()  # Establish connection with client.
            logger.info('Got connection from {}'.format(addr))
            self._dmrgui = addr[0]
            _tmp = c.recv(1024)
            _tmp = _tmp.split(None)[0]  #first get rid of whitespace
            _cmd = _tmp.split('=')[0]
            logger.info('Command:"{}"'.format(_cmd))
            if _cmd:
                if _cmd == 'reread_subscribers':
                    reread_subscribers()
                elif _cmd == 'reread_config':
                    self.readConfigFile(self._configFile, None,
                                        self._currentNetwork)
                elif _cmd == 'txTg':
                    self._tx_tg = hex_str_3(int(_tmp.split('=')[1]))
                    print('New txTg = ' + str(int_id(self._tx_tg)))
                elif _cmd == 'txTs':
                    self._tx_ts = int(_tmp.split('=')[1])
                    print('New txTs = ' + str(self._tx_ts))
                elif _cmd == 'section':
                    self.readConfigFile(self._configFile, _tmp.split('=')[1])
                elif _cmd == 'gateway_dmr_id':
                    self._gateway_dmr_id = int(_tmp.split('=')[1])
                    print('New gateway_dmr_id = ' + str(self._gateway_dmr_id))
                elif _cmd == 'gateway_peer_id':
                    peerID = int(_tmp.split('=')[1])
                    self._config['LOCAL']['RADIO_ID'] = hex_str_3(peerID)
                    print('New peer_id = ' + str(peerID))
                elif _cmd == 'restart':
                    reactor.callFromThread(reactor.stop)
                elif _cmd == 'playbackFromFile':
                    self.playbackFromFile('ambe.bin')
                elif _cmd == 'tgs':
                    _args = _tmp.split('=')[1]
                    self._tg_filter = map(int, _args.split(','))
                    logger.info('New TGs={}'.format(self._tg_filter))
                elif _cmd == 'dump_template':
                    self.dumpTemplate('PrivateVoice.bin')
                elif _cmd == 'get_alias':
                    self._sock.sendto(
                        'reply dmr_info {} {} {} {}'.format(
                            self._currentNetwork,
                            int_id(self._CONFIG[self._currentNetwork]['LOCAL']
                                   ['RADIO_ID']), self._gateway_dmr_id,
                            get_subscriber_info(hex_str_3(
                                self._gateway_dmr_id))), (self._dmrgui, 34003))
                elif _cmd == 'eval':
                    _sz = len(_tmp) - 5
                    _evalExpression = _tmp[-_sz:]
                    _evalResult = eval(_evalExpression)
                    print("eval of {} is {}".format(_evalExpression,
                                                    _evalResult))
                    self._sock.sendto('reply eval {}'.format(_evalResult),
                                      (self._dmrgui, 34003))
                elif _cmd == 'exec':
                    _sz = len(_tmp) - 5
                    _evalExpression = _tmp[-_sz:]
                    exec(_evalExpression)
                    print("exec of {}".format(_evalExpression))
                else:
                    logger.error('Unknown command')
            c.close()  # Close the connection

    #************************************************
    #     Debug: print IPSC frame on console
    #************************************************
    def dumpIPSCFrame(self, _frame):

        _packettype = int_id(
            _frame[0:1]
        )  # int8  GROUP_VOICE, PVT_VOICE, GROUP_DATA, PVT_DATA, CALL_MON_STATUS, CALL_MON_RPT, CALL_MON_NACK, XCMP_XNL, RPT_WAKE_UP, DE_REG_REQ
        _peerid = int_id(_frame[1:5])  # int32 peer who is sending us a packet
        _ipsc_seq = int_id(
            _frame[5:6])  # int8  looks like a sequence number for a packet
        _src_sub = int_id(_frame[6:9])  # int32 Id of source
        _dst_sub = int_id(_frame[9:12])  # int32 Id of destination
        _call_type = int_id(_frame[12:13])  # int8 Priority Voice/Data
        _call_ctrl_info = int_id(_frame[13:17])  # int32
        _call_info = int_id(
            _frame[17:18])  # int8  Bits 6 and 7 defined as TS and END

        # parse out the RTP values
        _rtp_byte_1 = int_id(_frame[18:19])  # Call Ctrl Src
        _rtp_byte_2 = int_id(_frame[19:20])  # Type
        _rtp_seq = int_id(_frame[20:22])  # Call Seq No
        _rtp_tmstmp = int_id(_frame[22:26])  # Timestamp
        _rtp_ssid = int_id(_frame[26:30])  # Sync Src Id

        _payload_type = _frame[
            30]  # int8  VOICE_HEAD, VOICE_TERM, SLOT1_VOICE, SLOT2_VOICE

        _ts = bool(_call_info & TS_CALL_MSK)
        _end = bool(_call_info & END_MSK)

        if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
            print('HEAD:', h(_frame))
        if _payload_type == BURST_DATA_TYPE['VOICE_TERM']:

            _ipsc_rssi_threshold_and_parity = int_id(_frame[31])
            _ipsc_length_to_follow = int_id(_frame[32:34])
            _ipsc_rssi_status = int_id(_frame[34])
            _ipsc_slot_type_sync = int_id(_frame[35])
            _ipsc_data_size = int_id(_frame[36:38])
            _ipsc_data = _frame[38:38 + (_ipsc_length_to_follow * 2) - 4]
            _ipsc_full_lc_byte1 = int_id(_frame[38])
            _ipsc_full_lc_fid = int_id(_frame[39])
            _ipsc_voice_pdu_service_options = int_id(_frame[40])
            _ipsc_voice_pdu_dst = int_id(_frame[41:44])
            _ipsc_voice_pdu_src = int_id(_frame[44:47])

            print('{} {} {} {} {} {} {} {} {} {} {}'.format(
                _ipsc_rssi_threshold_and_parity, _ipsc_length_to_follow,
                _ipsc_rssi_status, _ipsc_slot_type_sync, _ipsc_data_size,
                h(_ipsc_data), _ipsc_full_lc_byte1, _ipsc_full_lc_fid,
                _ipsc_voice_pdu_service_options, _ipsc_voice_pdu_dst,
                _ipsc_voice_pdu_src))
            print('TERM:', h(_frame))
        if _payload_type == BURST_DATA_TYPE['SLOT1_VOICE']:
            _rtp_len = _frame[31:32]
            _ambe = _frame[33:52]
            print('SLOT1:', h(_frame))
        if _payload_type == BURST_DATA_TYPE['SLOT2_VOICE']:
            _rtp_len = _frame[31:32]
            _ambe = _frame[33:52]
            print('SLOT2:', h(_frame))
        print(
            "pt={:02X} pid={} seq={:02X} src={} dst={} ct={:02X} uk={} ci={} rsq={}"
            .format(_packettype, _peerid, _ipsc_seq, _src_sub, _dst_sub,
                    _call_type, _call_ctrl_info, _call_info, _rtp_seq))
Ejemplo n.º 21
0
from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports
from dmr_utils.utils import int_id, hex_str_3

__author__ = 'Cortney T. Buffington, N0MJS'
__copyright__ = 'Copyright (c) 2014 Cortney T. Buffington, N0MJS and the K0USY Group'
__credits__ = 'Adam Fast, KC0YLK; Dave Kierzkowski, KD8EYF'
__license__ = 'GNU GPLv3'
__maintainer__ = 'Cort Buffington, N0MJS'
__email__ = '*****@*****.**'

try:
    from playback_config import *
except ImportError:
    sys.exit('Configuration file not found or invalid')

HEX_TGID = hex_str_3(TGID)
HEX_SUB = hex_str_3(SUB)
BOGUS_SUB = '\xFF\xFF\xFF'


class playbackIPSC(IPSC):
    def __init__(self, _name, _config, _logger, _report):
        IPSC.__init__(self, _name, _config, _logger, _report)
        self.CALL_DATA = []

        if GROUP_SRC_SUB:
            self._logger.info(
                'Playback: USING SUBSCRIBER ID: %s FOR GROUP REPEAT',
                GROUP_SRC_SUB)
            self.GROUP_SRC_SUB = hex_str_3(GROUP_SRC_SUB)
Ejemplo n.º 22
0
        # Parse out the TLV
        t = _data[0]
        if (t):
            l = _data[1]
            if (l):
                v = _data[2:]
                if (v):
                    t = ord(t)
                    if (t == TAG_BEGIN_TX) or (t == TAG_SET_INFO):

                        if ord(l) > 1:
                            _slot = int_id(v[10:11])
                            _rx_slot = self.rx[_slot]
                            _rx_slot.slot = _slot
                            _rx_slot.rf_src = hex_str_3(int_id(v[0:3]))
                            _rx_slot.repeater_id = self._parent.get_repeater_id(
                                hex_str_4(int_id(v[3:7])))
                            _rx_slot.dst_id = hex_str_3(int_id(v[7:10]))
                            _rx_slot.cc = int_id(v[11:12])

                        if t == TAG_BEGIN_TX:
                            _rx_slot.stream_id = hex_str_4(
                                randint(0, 0xFFFFFFFF)
                            )  # Every stream has a unique ID
                            self._logger.info('(%s) Begin AMBE encode STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \
                                          self._system, int_id(_rx_slot.stream_id), get_alias(_rx_slot.rf_src, subscriber_ids), int_id(_rx_slot.rf_src), get_alias(_rx_slot.repeater_id, peer_ids), int_id(_rx_slot.repeater_id), get_alias(_rx_slot.dst_id, talkgroup_ids), int_id(_rx_slot.dst_id), _slot)
                            self.send_voice_header(_rx_slot)
                        else:
                            self._logger.info('(%s) Set DMR Info SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \
                                          self._system, get_alias(_rx_slot.rf_src, subscriber_ids), int_id(_rx_slot.rf_src), get_alias(_rx_slot.repeater_id, peer_ids), int_id(_rx_slot.repeater_id), get_alias(_rx_slot.dst_id, talkgroup_ids), int_id(_rx_slot.dst_id), _slot)
Ejemplo n.º 23
0
from dmr_utils.utils import int_id, hex_str_3

__author__      = 'Cortney T. Buffington, N0MJS'
__copyright__   = 'Copyright (c) 2014 Cortney T. Buffington, N0MJS and the K0USY Group'
__credits__     = 'Adam Fast, KC0YLK; Dave Kierzkowski, KD8EYF'
__license__     = 'GNU GPLv3'
__maintainer__  = 'Cort Buffington, N0MJS'
__email__       = '*****@*****.**'


try:
    from playback_config import *
except ImportError:
    sys.exit('Configuration file not found or invalid')

HEX_TGID    = hex_str_3(TGID)
HEX_SUB     = hex_str_3(SUB)
BOGUS_SUB   = '\xFF\xFF\xFF'

class playbackIPSC(IPSC):
    def __init__(self, _name, _config, _logger, _report):
        IPSC.__init__(self, _name, _config, _logger, _report)
        self.CALL_DATA = []
        
        if GROUP_SRC_SUB:
            self._logger.info('Playback: USING SUBSCRIBER ID: %s FOR GROUP REPEAT', GROUP_SRC_SUB)
            self.GROUP_SRC_SUB = hex_str_3(GROUP_SRC_SUB)
        
        if GROUP_REPEAT:
            self._logger.info('Playback: GROUP REPEAT ENABLED')
            
Ejemplo n.º 24
0
 def remote_control(self, port):
     s = socket.socket()         # Create a socket object
     
     s.bind(('', port))          # Bind to the port
     s.listen(5)                 # Now wait for client connection.
     logger.info('Remote control is listening on {}:{}'.format(socket.getfqdn(), port))
     
     while True:
         c, addr = s.accept()     # Establish connection with client.
         logger.info( 'Got connection from {}'.format(addr) )
         self._dmrgui = addr[0]
         _tmp = c.recv(1024)
         _tmp = _tmp.split(None)[0] #first get rid of whitespace
         _cmd = _tmp.split('=')[0]
         logger.info('Command:"{}"'.format(_cmd))
         if _cmd:
             if _cmd == 'reread_subscribers':
                 reread_subscribers()
             elif _cmd == 'reread_config':
                 self.readConfigFile(self._configFile, None, self._currentNetwork)
             elif _cmd == 'txTg':
                 self._tx_tg = hex_str_3(int(_tmp.split('=')[1]))
                 print('New txTg = ' + str(int_id(self._tx_tg)))
             elif _cmd == 'txTs':
                 self._tx_ts = int(_tmp.split('=')[1])
                 print('New txTs = ' + str(self._tx_ts))
             elif _cmd == 'section':
                 self.readConfigFile(self._configFile, _tmp.split('=')[1])
             elif _cmd == 'gateway_dmr_id':
                 self._gateway_dmr_id = int(_tmp.split('=')[1])
                 print('New gateway_dmr_id = ' + str(self._gateway_dmr_id))
             elif _cmd == 'gateway_peer_id':
                 peerID = int(_tmp.split('=')[1])
                 self._config['LOCAL']['RADIO_ID'] = hex_str_3(peerID)
                 print('New peer_id = ' + str(peerID))
             elif _cmd == 'restart':
                 reactor.callFromThread(reactor.stop)
             elif _cmd == 'playbackFromFile':
                 self.playbackFromFile('ambe.bin')                
             elif _cmd == 'tgs':
                 _args = _tmp.split('=')[1]
                 self._tg_filter = map(int, _args.split(','))
                 logger.info( 'New TGs={}'.format(self._tg_filter) )
             elif _cmd == 'dump_template':
                 self.dumpTemplate('PrivateVoice.bin')
             elif _cmd == 'get_alias':
                 self._sock.sendto('reply dmr_info {} {} {} {}'.format(self._currentNetwork,
                                                                       int_id(self._CONFIG[self._currentNetwork]['LOCAL']['RADIO_ID']),
                                                                       self._gateway_dmr_id,
                                                                       get_subscriber_info(hex_str_3(self._gateway_dmr_id))), (self._dmrgui, 34003))
             elif _cmd == 'eval':
                 _sz = len(_tmp)-5
                 _evalExpression = _tmp[-_sz:]
                 _evalResult = eval(_evalExpression)
                 print("eval of {} is {}".format(_evalExpression, _evalResult))
                 self._sock.sendto('reply eval {}'.format(_evalResult), (self._dmrgui, 34003))
             elif _cmd == 'exec':
                 _sz = len(_tmp)-5
                 _evalExpression = _tmp[-_sz:]
                 exec(_evalExpression)
                 print("exec of {}".format(_evalExpression))
             else:
                 logger.error('Unknown command')
         c.close()                # Close the connection
Ejemplo n.º 25
0
while True:
    ts = raw_input('Which timeslot (1, 2 or \'both\')? ')
    if ts == '1' or ts == '2' or ts =='both':
        if ts == '1':
            ts = (1,)
        if ts == '2':
            ts = (2,)
        if ts == 'both':
            ts = (1,2)
        break
    print('...input must be \'1\', \'2\' or \'both\'')

id = raw_input('Which Group or Subscriber ID to record? ')
id = int(id)
id = hex_str_3(id)

filename = raw_input('Filename to use for this recording? ')

class recordIPSC(IPSC):
    def __init__(self, _name, _config, _logger, _report):
        IPSC.__init__(self, _name, _config, _logger, _report)
        self.CALL_DATA = []
        
    #************************************************
    #     CALLBACK FUNCTIONS FOR USER PACKET TYPES
    #************************************************
    #
    if tx_type == 'g':
	print('Initializing to record GROUP VOICE transmission')
        def group_voice(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data):
Ejemplo n.º 26
0
    def playbackFromUDP(self, _sock):
        _delay = 0.055  # Yes, I know it should be 0.06, but there seems to be some latency, so this is a hack
        _src_sub = hex_str_3(
            self._gateway_dmr_id)  # DMR ID to sign this transmission with
        _src_peer = self._config['LOCAL'][
            'RADIO_ID']  # Use this peers ID as the source repeater

        logger.info('Transmit from gateway to TG {}:'.format(
            int_id(self._tx_tg)))
        try:

            try:
                _t = open(
                    'template.bin',
                    'rb')  # Open the template file.  This was recorded OTA

                _tempHead = [
                    0
                ] * 3  # It appears that there 3 frames of HEAD (mostly the same)
                for i in range(0, 3):
                    _tempHead[i] = self.readRecord(
                        _t, BURST_DATA_TYPE['VOICE_HEAD'])

                _tempVoice = [0] * 6
                for i in range(
                        0, 6
                ):  # Then there are 6 frames of AMBE.  We will just use them in order
                    _tempVoice[i] = self.readRecord(
                        _t, BURST_DATA_TYPE['SLOT2_VOICE'])

                _tempTerm = self.readRecord(_t, BURST_DATA_TYPE['VOICE_TERM'])
                _t.close()
            except IOError:
                logger.error('Can not open template.bin file')
                return
            logger.debug('IPSC templates loaded')

            _eof = False
            self._seq = randint(
                0, 32767
            )  # A transmission uses a random number to begin its sequence (16 bit)

            for i in range(0, 3):  # Output the 3 HEAD frames to our peers
                self.rewriteFrame(_tempHead[i], self._tx_ts, self._tx_tg,
                                  _src_sub, _src_peer)
                #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempHead[i])
                sleep(_delay)

            i = 0  # Initialize the VOICE template index
            while (_eof == False):
                _ambe = self.readAmbeFrameFromUDP(
                    _sock)  # Read the 49*3 bit sample from the stream
                if _ambe:
                    i = (i + 1) % 6  # Round robbin with the 6 VOICE templates
                    _frame = _tempVoice[i][:33] + _ambe + _tempVoice[i][
                        52:]  # Insert the 3 49 bit AMBE frames

                    self.rewriteFrame(_frame, self._tx_ts, self._tx_tg,
                                      _src_sub, _src_peer)
                    #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _frame)

                    sleep(
                        _delay
                    )  # Since this comes from a file we have to add delay between IPSC frames
                else:
                    _eof = True  # There are no more AMBE frames, so terminate the loop

            self.rewriteFrame(_tempTerm, self._tx_ts, self._tx_tg, _src_sub,
                              _src_peer)
            #self.group_voice(self._system, _src_sub, self._tx_tg, True, '', hex_str_3(0), _tempTerm)

        except IOError:
            logger.error('Can not transmit to peers')
        logger.info('Transmit complete')