def dmrd_received(self, _radio_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) for _target in self._CONFIG['SYSTEMS']: if _target != self._system: systems[_target].send_system(_data) self._logger.debug('(%s) Packet routed to system: %s', self._system, _target) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC ) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and ( self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
def begin_call(self, _slot, _src_id, _dst_id, _repeater_id, _cc, _seq, _stream_id): subscriber_ids, talkgroup_ids, peer_ids = self._parent.get_globals() _src_alias = get_alias(_src_id, subscriber_ids) metadata = _src_id[0:3] + _repeater_id[0:4] + _dst_id[ 0:3] + struct.pack("b", _slot) + struct.pack("b", _cc) self.send_tlv(TAG_BEGIN_TX, metadata) # start transmission self._sock.sendto( 'reply log2 {} {}'.format(_src_alias, int_id(_dst_id)), (self._dmrgui, 34003)) self._logger.info( 'Voice Transmission Start on TS {} and TG {} ({}) from {}'.format( _slot, get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _src_alias)) _tx_slot = self.tx[_slot] _tx_slot.slot = _slot _tx_slot.rf_src = _src_id _tx_slot.repeater_id = _repeater_id _tx_slot.dst_id = _dst_id _tx_slot.cc = _cc _tx_slot.stream_id = _stream_id _tx_slot.start_time = time() _tx_slot.frame_count = 0 _tx_slot.lostFrame = 0 _tx_slot.lastSeq = _seq
def group_voice(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): if (_ts not in self.ACTIVE_CALLS) or _end: _time = time.strftime('%m/%d/%y %H:%M:%S') _dst_sub = get_alias(_dst_sub, talkgroup_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) if not _end: self.ACTIVE_CALLS.append(_ts) if _end: self.ACTIVE_CALLS.remove(_ts) if _end: _end = 'END' else: _end = 'START' print('{} ({}) Call {} Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t{}' .format(_time, self._system, _end, _peerid, _src_sub, _dst_sub, _ts))
def group_voice(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): if (_ts not in self.ACTIVE_CALLS) or _end: _time = time.strftime('%m/%d/%y %H:%M:%S') _dst_sub = get_alias(_dst_sub, talkgroup_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) if not _end: self.ACTIVE_CALLS.append(_ts) if _end: self.ACTIVE_CALLS.remove(_ts) if _end: _end = 'END' else: _end = 'START' print( '{} ({}) Call {} Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t{}' .format(_time, self._system, _end, _peerid, _src_sub, _dst_sub, _ts))
def call_mon_status(self, _data): if not status: return _source = _data[1:5] _ipsc_src = _data[5:9] _seq_num = _data[9:13] _ts = _data[13] _status = _data[15] # suspect [14:16] but nothing in leading byte? _rf_src = _data[16:19] _rf_tgt = _data[19:22] _type = _data[22] _prio = _data[23] _sec = _data[24] _source = str(int_id(_source)) + ', ' + str( get_alias(_source, peer_ids)) _ipsc_src = str(int_id(_ipsc_src)) + ', ' + str( get_alias(_ipsc_src, peer_ids)) _rf_src = str(int_id(_rf_src)) + ', ' + str( get_alias(_rf_src, subscriber_ids)) if _type == '\x4F' or '\x51': _rf_tgt = 'TGID: ' + str(int_id(_rf_tgt)) + ', ' + str( get_alias(_rf_tgt, talkgroup_ids)) else: _rf_tgt = 'SID: ' + str(int_id(_rf_tgt)) + ', ' + str( get_alias(_rf_tgt, subscriber_ids)) print('Call Monitor - Call Status') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) print('IPSC: ', self._system) print('IPSC Source: ', _ipsc_src) print('Timeslot: ', TS[_ts]) try: print('Status: ', STATUS[_status]) except KeyError: print('Status (unknown): ', ahex(_status)) try: print('Type: ', TYPE[_type]) except KeyError: print('Type (unknown): ', ahex(_type)) print('Source Sub: ', _rf_src) print('Target Sub: ', _rf_tgt) print()
def alias_string(_id, _dict): alias = get_alias(_id, _dict, 'CALLSIGN', 'CITY', 'STATE') if type(alias) == list: for x, item in enumerate(alias): if item == None: alias.pop(x) return ', '.join(alias) else: return alias
def alias_call(_id, _dict): alias = get_alias(_id, _dict, 'CALLSIGN') if type(alias) == list: for x,item in enumerate(alias): if item == None: alias.pop(x) return ', '.join(alias) else: return str(alias)
def dmrd_received(self, _radio_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC ) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and ( self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) self.CALL_DATA.append(_data) sleep(2) logger.info( '(%s) Playing back transmission from subscriber: %s', self._system, int_id(_rf_src)) for i in self.CALL_DATA: self.send_system(i) sleep(0.06) self.CALL_DATA = [] else: if not self.CALL_DATA: logger.info( '(%s) Receiving transmission to be played back from subscriber: %s', self._system, int_id(_rf_src)) self.CALL_DATA.append(_data) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
def end_call(self, _tx_slot): subscriber_ids, talkgroup_ids, peer_ids = self._parent.get_globals() self.send_tlv(TAG_END_TX, struct.pack("b",_tx_slot.slot)) # end transmission call_duration = time() - _tx_slot.start_time _lost_percentage = ((_tx_slot.lostFrame / float(_tx_slot.frame_count)) * 100.0) if _tx_slot.frame_count > 0 else 0.0 self._sock.sendto("reply log" + strftime(" %m/%d/%y %H:%M:%S", localtime(_tx_slot.start_time)) + ' {} {} "{}"'.format(get_alias(_tx_slot.rf_src, subscriber_ids), _tx_slot.slot, get_alias(_tx_slot.dst_id, talkgroup_ids)) + ' {:.2f}%'.format(_lost_percentage) + ' {:.2f}s'.format(call_duration), (self._dmrgui, 34003)) self._logger.info('Voice Transmission End {:.2f} seconds loss rate: {:.2f}% ({}/{})'.format(call_duration, _lost_percentage, _tx_slot.frame_count - _tx_slot.lostFrame, _tx_slot.frame_count))
def call_mon_status(self, _data): if not status: return _source = _data[1:5] _ipsc_src = _data[5:9] _seq_num = _data[9:13] _ts = _data[13] _status = _data[15] # suspect [14:16] but nothing in leading byte? _rf_src = _data[16:19] _rf_tgt = _data[19:22] _type = _data[22] _prio = _data[23] _sec = _data[24] _source = str(int_id(_source)) + ', ' + str(get_alias(_source, peer_ids)) _ipsc_src = str(int_id(_ipsc_src)) + ', ' + str(get_alias(_ipsc_src, peer_ids)) _rf_src = str(int_id(_rf_src)) + ', ' + str(get_alias(_rf_src, subscriber_ids)) if _type == '\x4F' or '\x51': _rf_tgt = 'TGID: ' + str(int_id(_rf_tgt)) + ', ' + str(get_alias(_rf_tgt, talkgroup_ids)) else: _rf_tgt = 'SID: ' + str(int_id(_rf_tgt)) + ', ' + str(get_alias(_rf_tgt, subscriber_ids)) print('Call Monitor - Call Status') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) print('IPSC: ', self._system) print('IPSC Source: ', _ipsc_src) print('Timeslot: ', TS[_ts]) try: print('Status: ', STATUS[_status]) except KeyError: print('Status (unknown): ', h(_status)) try: print('Type: ', TYPE[_type]) except KeyError: print('Type (unknown): ', h(_type)) print('Source Sub: ', _rf_src) print('Target Sub: ', _rf_tgt) print()
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) self.CALL_DATA.append(_data) sleep(2) logger.info('(%s) Playing back transmission from subscriber: %s', self._system, int_id(_rf_src)) for i in self.CALL_DATA: self.send_system(i) sleep(0.06) self.CALL_DATA = [] else: if not self.CALL_DATA: logger.info('(%s) Receiving transmission to be played back from subscriber: %s', self._system, int_id(_rf_src)) self.CALL_DATA.append(_data) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
def call_mon_nack(self, _data): if not nack: return _source = _data[1:5] _nack = _data[5] _source = get_alias(_source, peer_ids) print('Call Monitor - Transmission NACK') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) try: print('NACK Cause: ', NACK[_nack]) except KeyError: print('NACK Cause (unknown): ', h(_nack)) print()
def call_mon_nack(self, _data): if not nack: return _source = _data[1:5] _nack = _data[5] _source = get_alias(_source, peer_ids) print('Call Monitor - Transmission NACK') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) try: print('NACK Cause: ', NACK[_nack]) except KeyError: print('NACK Cause (unknown): ', ahex(_nack)) print()
def call_mon_rpt(self, _data): if not rpt: return _source = _data[1:5] _ts1_state = _data[5] _ts2_state = _data[6] _source = str(int_id(_source)) + ', ' + str(get_alias(_source, peer_ids)) print('Call Monitor - Repeater State') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) try: print('TS1 State: ', REPEAT[_ts1_state]) except KeyError: print('TS1 State (unknown): ', h(_ts1_state)) try: print('TS2 State: ', REPEAT[_ts2_state]) except KeyError: print('TS2 State (unknown): ', h(_ts2_state)) print()
def call_mon_rpt(self, _data): if not rpt: return _source = _data[1:5] _ts1_state = _data[5] _ts2_state = _data[6] _source = str(int_id(_source)) + ', ' + str( get_alias(_source, peer_ids)) print('Call Monitor - Repeater State') print('TIME: ', datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print('DATA SOURCE: ', _source) try: print('TS1 State: ', REPEAT[_ts1_state]) except KeyError: print('TS1 State (unknown): ', ahex(_ts1_state)) try: print('TS2 State: ', REPEAT[_ts2_state]) except KeyError: print('TS2 State (unknown): ', ahex(_ts2_state)) print()
def group_data(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): _dst_sub = get_alias(_dst_sub, talkgroup_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) print('({}) Group Data Packet Received From: {}' .format(self._system, _src_sub))
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Check for ACL match, and return if the subscriber is not allowed if allow_sub(_rf_src) == False: self._logger.warning('(%s) Group Voice Packet ***REJECTED BY ACL*** From: %s, HBP Peer %s, Destination TGID %s', self._system, int_id(_rf_src), int_id(_peer_id), int_id(_dst_id)) return # Is this a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): if (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM) and (pkt_time < (self.STATUS[_slot]['RX_TIME'] + hb_const.STREAM_TO)) and (_rf_src != self.STATUS[_slot]['RX_RFS']): self._logger.warning('(%s) Packet received with STREAM ID: %s <FROM> SUB: %s PEER: %s <TO> TGID %s, SLOT %s collided with existing call', self._system, int_id(_stream_id), int_id(_rf_src), int_id(_peer_id), int_id(_dst_id), _slot) return # This is a new call stream self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # If we can, use the LC from the voice header as to keep all options intact if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: decoded = decode.voice_head_term(dmrpkt) self.STATUS[_slot]['RX_LC'] = decoded['LC'] # If we don't have a voice header then don't wait to decode it from the Embedded LC # just make a new one from the HBP header. This is good enough, and it saves lots of time else: self.STATUS[_slot]['RX_LC'] = const.LC_OPT + _dst_id + _rf_src for rule in RULES[self._system]['GROUP_VOICE']: _target = rule['DST_NET'] _target_status = systems[_target].STATUS if (rule['SRC_GROUP'] == _dst_id and rule['SRC_TS'] == _slot and rule['ACTIVE'] == True): # BEGIN CONTENTION HANDLING # # The rules for each of the 4 "ifs" below are listed here for readability. The Frame To Send is: # From a different group than last RX from this HBSystem, but it has been less than Group Hangtime # From a different group than last TX to this HBSystem, but it has been less than Group Hangtime # From the same group as the last RX from this HBSystem, but from a different subscriber, and it has been less than stream timeout # From the same group as the last TX to this HBSystem, but from a different subscriber, and it has been less than stream timeout # The "continue" at the end of each means the next iteration of the for loop that tests for matching rules # if ((rule['DST_GROUP'] != _target_status[rule['DST_TS']]['RX_TGID']) and ((pkt_time - _target_status[rule['DST_TS']]['RX_TIME']) < RULES[_target]['GROUP_HANGTIME'])): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info('(%s) Call not routed to TGID%s, target active or in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id(_target_status[rule['DST_TS']]['RX_TGID'])) continue if ((rule['DST_GROUP'] != _target_status[rule['DST_TS']]['TX_TGID']) and ((pkt_time - _target_status[rule['DST_TS']]['TX_TIME']) < RULES[_target]['GROUP_HANGTIME'])): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info('(%s) Call not routed to TGID%s, target in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id(_target_status[rule['DST_TS']]['TX_TGID'])) continue if (rule['DST_GROUP'] == _target_status[rule['DST_TS']]['RX_TGID']) and ((pkt_time - _target_status[rule['DST_TS']]['RX_TIME']) < hb_const.STREAM_TO): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info('(%s) Call not routed to TGID%s, matching call already active on target: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id(_target_status[rule['DST_TS']]['RX_TGID'])) continue if (rule['DST_GROUP'] == _target_status[rule['DST_TS']]['TX_TGID']) and (_rf_src != _target_status[rule['DST_TS']]['TX_RFS']) and ((pkt_time - _target_status[rule['DST_TS']]['TX_TIME']) < hb_const.STREAM_TO): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info('(%s) Call not routed for subscriber %s, call route in progress on target: HBSystem: %s, TS: %s, TGID: %s, SUB: %s', self._system, int_id(_rf_src), _target, rule['DST_TS'], int_id(_target_status[rule['DST_TS']]['TX_TGID']), _target_status[rule['DST_TS']]['TX_RFS']) continue # Set values for the contention handler to test next time there is a frame to forward _target_status[rule['DST_TS']]['TX_TIME'] = pkt_time if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']) or (_target_status[rule['DST_TS']]['TX_RFS'] != _rf_src) or (_target_status[rule['DST_TS']]['TX_TGID'] != rule['DST_GROUP']): # Record the DST TGID and Stream ID _target_status[rule['DST_TS']]['TX_TGID'] = rule['DST_GROUP'] _target_status[rule['DST_TS']]['TX_STREAM_ID'] = _stream_id _target_status[rule['DST_TS']]['TX_RFS'] = _rf_src # Generate LCs (full and EMB) for the TX stream # if _dst_id != rule['DST_GROUP']: dst_lc = self.STATUS[_slot]['RX_LC'][0:3] + rule['DST_GROUP'] + _rf_src _target_status[rule['DST_TS']]['TX_H_LC'] = bptc.encode_header_lc(dst_lc) _target_status[rule['DST_TS']]['TX_T_LC'] = bptc.encode_terminator_lc(dst_lc) _target_status[rule['DST_TS']]['TX_EMB_LC'] = bptc.encode_emblc(dst_lc) self._logger.debug('(%s) Packet DST TGID (%s) does not match SRC TGID(%s) - Generating FULL and EMB LCs', self._system, int_id(rule['DST_GROUP']), int_id(_dst_id)) self._logger.info('(%s) Call routed to: System: %s TS: %s, TGID: %s', self._system, _target, rule['DST_TS'], int_id(rule['DST_GROUP'])) # Handle any necessary re-writes for the destination if rule['SRC_TS'] != rule['DST_TS']: _tmp_bits = _bits ^ 1 << 7 else: _tmp_bits = _bits # Assemble transmit HBP packet header _tmp_data = _data[:8] + rule['DST_GROUP'] + _data[11:15] + chr(_tmp_bits) + _data[16:20] # MUST TEST FOR NEW STREAM AND IF SO, RE-WRITE THE LC FOR THE TARGET # MUST RE-WRITE DESTINATION TGID IF DIFFERENT # if _dst_id != rule['DST_GROUP']: dmrbits = bitarray(endian='big') dmrbits.frombytes(dmrpkt) # Create a voice header packet (FULL LC) if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: dmrbits = _target_status[rule['DST_TS']]['TX_H_LC'][0:98] + dmrbits[98:166] + _target_status[rule['DST_TS']]['TX_H_LC'][98:197] # Create a voice terminator packet (FULL LC) elif _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VTERM: dmrbits = _target_status[rule['DST_TS']]['TX_T_LC'][0:98] + dmrbits[98:166] + _target_status[rule['DST_TS']]['TX_T_LC'][98:197] # Create a Burst B-E packet (Embedded LC) elif _dtype_vseq in [1,2,3,4]: dmrbits = dmrbits[0:116] + _target_status[rule['DST_TS']]['TX_EMB_LC'][_dtype_vseq] + dmrbits[148:264] dmrpkt = dmrbits.tobytes() _tmp_data = _tmp_data + dmrpkt + _data[53:55] # Transmit the packet to the destination system systems[_target].send_system(_tmp_data) self._logger.debug('(%s) Packet routed by rule: %s to %s system: %s', self._system, rule['NAME'], self._CONFIG['SYSTEMS'][_target]['MODE'], _target) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) # # Begin in-band signalling for call end. This has nothign to do with routing traffic directly. # # Iterate the rules dictionary for rule in RULES[self._system]['GROUP_VOICE']: _target = rule['DST_NET'] # TGID matches a rule source, reset its timer if _slot == rule['SRC_TS'] and _dst_id == rule['SRC_GROUP'] and ((rule['TO_TYPE'] == 'ON' and (rule['ACTIVE'] == True)) or (rule['TO_TYPE'] == 'OFF' and rule['ACTIVE'] == False)): rule['TIMER'] = pkt_time + rule['TIMEOUT'] self._logger.info('(%s) Source group transmission match for rule \"%s\". Reset timeout to %s', self._system, rule['NAME'], rule['TIMER']) # Scan for reciprocal rules and reset their timers as well. for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['TIMER'] = pkt_time + target_rule['TIMEOUT'] self._logger.info('(%s) Reciprocal group transmission match for rule \"%s\" on IPSC \"%s\". Reset timeout to %s', self._system, target_rule['NAME'], _target, rule['TIMER']) # TGID matches an ACTIVATION trigger if _dst_id in rule['ON']: # Set the matching rule as ACTIVE rule['ACTIVE'] = True rule['TIMER'] = pkt_time + rule['TIMEOUT'] self._logger.info('(%s) Primary routing Rule \"%s\" changed to state: %s', self._system, rule['NAME'], rule['ACTIVE']) # Set reciprocal rules for other IPSCs as ACTIVE for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['ACTIVE'] = True target_rule['TIMER'] = pkt_time + target_rule['TIMEOUT'] self._logger.info('(%s) Reciprocal routing Rule \"%s\" in IPSC \"%s\" changed to state: %s', self._system, target_rule['NAME'], _target, rule['ACTIVE']) # TGID matches an DE-ACTIVATION trigger if _dst_id in rule['OFF']: # Set the matching rule as ACTIVE rule['ACTIVE'] = False self._logger.info('(%s) Routing Rule \"%s\" changed to state: %s', self._system, rule['NAME'], rule['ACTIVE']) # Set reciprocal rules for other IPSCs as ACTIVE _target = rule['DST_NET'] for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['ACTIVE'] = False self._logger.info('(%s) Reciprocal routing Rule \"%s\" in IPSC \"%s\" changed to state: %s', self._system, target_rule['NAME'], _target, rule['ACTIVE']) # # END IN-BAND SIGNALLING # # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
def private_data(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): _dst_sub = get_alias(_dst_sub, subscriber_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) print('({}) Private Data Packet Received From: {} To: {}' .format(self._system, _src_sub, _dst_sub))
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Check for ACL match, and return if the subscriber is not allowed if allow_sub(_rf_src) == False: self._logger.warning( '(%s) Group Voice Packet ***REJECTED BY ACL*** From: %s, HBP Peer %s, Destination TGID %s', self._system, int_id(_rf_src), int_id(_peer_id), int_id(_dst_id)) return # Is this a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): if (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM ) and (pkt_time < (self.STATUS[_slot]['RX_TIME'] + hb_const.STREAM_TO) ) and (_rf_src != self.STATUS[_slot]['RX_RFS']): self._logger.warning( '(%s) Packet received with STREAM ID: %s <FROM> SUB: %s PEER: %s <TO> TGID %s, SLOT %s collided with existing call', self._system, int_id(_stream_id), int_id(_rf_src), int_id(_peer_id), int_id(_dst_id), _slot) return # This is a new call stream self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # If we can, use the LC from the voice header as to keep all options intact if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: decoded = decode.voice_head_term(dmrpkt) self.STATUS[_slot]['RX_LC'] = decoded['LC'] # If we don't have a voice header then don't wait to decode it from the Embedded LC # just make a new one from the HBP header. This is good enough, and it saves lots of time else: self.STATUS[_slot][ 'RX_LC'] = const.LC_OPT + _dst_id + _rf_src for rule in RULES[self._system]['GROUP_VOICE']: _target = rule['DST_NET'] _target_status = systems[_target].STATUS if (rule['SRC_GROUP'] == _dst_id and rule['SRC_TS'] == _slot and rule['ACTIVE'] == True): # BEGIN CONTENTION HANDLING # # The rules for each of the 4 "ifs" below are listed here for readability. The Frame To Send is: # From a different group than last RX from this HBSystem, but it has been less than Group Hangtime # From a different group than last TX to this HBSystem, but it has been less than Group Hangtime # From the same group as the last RX from this HBSystem, but from a different subscriber, and it has been less than stream timeout # From the same group as the last TX to this HBSystem, but from a different subscriber, and it has been less than stream timeout # The "continue" at the end of each means the next iteration of the for loop that tests for matching rules # if ((rule['DST_GROUP'] != _target_status[rule['DST_TS']]['RX_TGID']) and ((pkt_time - _target_status[rule['DST_TS']]['RX_TIME']) < RULES[_target]['GROUP_HANGTIME'])): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info( '(%s) Call not routed to TGID%s, target active or in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id( _target_status[rule['DST_TS']]['RX_TGID'])) continue if ((rule['DST_GROUP'] != _target_status[rule['DST_TS']]['TX_TGID']) and ((pkt_time - _target_status[rule['DST_TS']]['TX_TIME']) < RULES[_target]['GROUP_HANGTIME'])): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info( '(%s) Call not routed to TGID%s, target in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id( _target_status[rule['DST_TS']]['TX_TGID'])) continue if (rule['DST_GROUP'] == _target_status[rule['DST_TS']]['RX_TGID']) and ( (pkt_time - _target_status[rule['DST_TS']]['RX_TIME']) < hb_const.STREAM_TO): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info( '(%s) Call not routed to TGID%s, matching call already active on target: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(rule['DST_GROUP']), _target, rule['DST_TS'], int_id( _target_status[rule['DST_TS']]['RX_TGID'])) continue if (rule['DST_GROUP'] == _target_status[rule['DST_TS']]['TX_TGID']) and ( _rf_src != _target_status[rule['DST_TS']]['TX_RFS']) and ( (pkt_time - _target_status[rule['DST_TS']]['TX_TIME']) < hb_const.STREAM_TO): if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: self._logger.info( '(%s) Call not routed for subscriber %s, call route in progress on target: HBSystem: %s, TS: %s, TGID: %s, SUB: %s', self._system, int_id(_rf_src), _target, rule['DST_TS'], int_id( _target_status[rule['DST_TS']]['TX_TGID']), _target_status[rule['DST_TS']]['TX_RFS']) continue # Set values for the contention handler to test next time there is a frame to forward _target_status[rule['DST_TS']]['TX_TIME'] = pkt_time if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']) or ( _target_status[rule['DST_TS']]['TX_RFS'] != _rf_src ) or (_target_status[rule['DST_TS']]['TX_TGID'] != rule['DST_GROUP']): # Record the DST TGID and Stream ID _target_status[ rule['DST_TS']]['TX_TGID'] = rule['DST_GROUP'] _target_status[ rule['DST_TS']]['TX_STREAM_ID'] = _stream_id _target_status[rule['DST_TS']]['TX_RFS'] = _rf_src # Generate LCs (full and EMB) for the TX stream # if _dst_id != rule['DST_GROUP']: dst_lc = self.STATUS[_slot]['RX_LC'][0:3] + rule[ 'DST_GROUP'] + _rf_src _target_status[rule['DST_TS']][ 'TX_H_LC'] = bptc.encode_header_lc(dst_lc) _target_status[rule['DST_TS']][ 'TX_T_LC'] = bptc.encode_terminator_lc(dst_lc) _target_status[rule['DST_TS']][ 'TX_EMB_LC'] = bptc.encode_emblc(dst_lc) self._logger.debug( '(%s) Packet DST TGID (%s) does not match SRC TGID(%s) - Generating FULL and EMB LCs', self._system, int_id(rule['DST_GROUP']), int_id(_dst_id)) self._logger.info( '(%s) Call routed to: System: %s TS: %s, TGID: %s', self._system, _target, rule['DST_TS'], int_id(rule['DST_GROUP'])) # Handle any necessary re-writes for the destination if rule['SRC_TS'] != rule['DST_TS']: _tmp_bits = _bits ^ 1 << 7 else: _tmp_bits = _bits # Assemble transmit HBP packet header _tmp_data = _data[:8] + rule['DST_GROUP'] + _data[ 11:15] + chr(_tmp_bits) + _data[16:20] # MUST TEST FOR NEW STREAM AND IF SO, RE-WRITE THE LC FOR THE TARGET # MUST RE-WRITE DESTINATION TGID IF DIFFERENT # if _dst_id != rule['DST_GROUP']: dmrbits = bitarray(endian='big') dmrbits.frombytes(dmrpkt) # Create a voice header packet (FULL LC) if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: dmrbits = _target_status[rule['DST_TS']]['TX_H_LC'][ 0:98] + dmrbits[98:166] + _target_status[ rule['DST_TS']]['TX_H_LC'][98:197] # Create a voice terminator packet (FULL LC) elif _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VTERM: dmrbits = _target_status[rule['DST_TS']]['TX_T_LC'][ 0:98] + dmrbits[98:166] + _target_status[ rule['DST_TS']]['TX_T_LC'][98:197] # Create a Burst B-E packet (Embedded LC) elif _dtype_vseq in [1, 2, 3, 4]: dmrbits = dmrbits[0:116] + _target_status[ rule['DST_TS']]['TX_EMB_LC'][ _dtype_vseq] + dmrbits[148:264] dmrpkt = dmrbits.tobytes() _tmp_data = _tmp_data + dmrpkt + _data[53:55] # Transmit the packet to the destination system systems[_target].send_system(_tmp_data) self._logger.debug( '(%s) Packet routed by rule: %s to %s system: %s', self._system, rule['NAME'], self._CONFIG['SYSTEMS'][_target]['MODE'], _target) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC ) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and ( self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) # # Begin in-band signalling for call end. This has nothign to do with routing traffic directly. # # Iterate the rules dictionary for rule in RULES[self._system]['GROUP_VOICE']: _target = rule['DST_NET'] # TGID matches a rule source, reset its timer if _slot == rule['SRC_TS'] and _dst_id == rule[ 'SRC_GROUP'] and ((rule['TO_TYPE'] == 'ON' and (rule['ACTIVE'] == True)) or (rule['TO_TYPE'] == 'OFF' and rule['ACTIVE'] == False)): rule['TIMER'] = pkt_time + rule['TIMEOUT'] self._logger.info( '(%s) Source group transmission match for rule \"%s\". Reset timeout to %s', self._system, rule['NAME'], rule['TIMER']) # Scan for reciprocal rules and reset their timers as well. for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['TIMER'] = pkt_time + target_rule[ 'TIMEOUT'] self._logger.info( '(%s) Reciprocal group transmission match for rule \"%s\" on IPSC \"%s\". Reset timeout to %s', self._system, target_rule['NAME'], _target, rule['TIMER']) # TGID matches an ACTIVATION trigger if _dst_id in rule['ON']: # Set the matching rule as ACTIVE rule['ACTIVE'] = True rule['TIMER'] = pkt_time + rule['TIMEOUT'] self._logger.info( '(%s) Primary routing Rule \"%s\" changed to state: %s', self._system, rule['NAME'], rule['ACTIVE']) # Set reciprocal rules for other IPSCs as ACTIVE for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['ACTIVE'] = True target_rule['TIMER'] = pkt_time + target_rule[ 'TIMEOUT'] self._logger.info( '(%s) Reciprocal routing Rule \"%s\" in IPSC \"%s\" changed to state: %s', self._system, target_rule['NAME'], _target, rule['ACTIVE']) # TGID matches an DE-ACTIVATION trigger if _dst_id in rule['OFF']: # Set the matching rule as ACTIVE rule['ACTIVE'] = False self._logger.info( '(%s) Routing Rule \"%s\" changed to state: %s', self._system, rule['NAME'], rule['ACTIVE']) # Set reciprocal rules for other IPSCs as ACTIVE _target = rule['DST_NET'] for target_rule in RULES[_target]['GROUP_VOICE']: if target_rule['NAME'] == rule['NAME']: target_rule['ACTIVE'] = False self._logger.info( '(%s) Reciprocal routing Rule \"%s\" in IPSC \"%s\" changed to state: %s', self._system, target_rule['NAME'], _target, rule['ACTIVE']) # # END IN-BAND SIGNALLING # # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
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, self._system, 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))
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) elif ( (t == TAG_AMBE) or (t == TAG_AMBE_72)): # generic AMBE or specific AMBE72 _slot = int_id(v[0]) _rx_slot = self.rx[_slot] if _rx_slot.frame_count > 0: self.send_voice72(_rx_slot, v[1:]) elif (t == TAG_AMBE_49): # AMBE49 _slot = int_id(v[0]) _rx_slot = self.rx[_slot] if _rx_slot.frame_count > 0:
def alias_tgid(_id, _dict): alias = get_alias(_id, _dict, 'NAME') if type(alias) == list: return str(alias[0]) else: return str(alias)
def alias_call(_id, _dict): alias = get_alias(_id, _dict, 'CALLSIGN') if type(alias) == list: return str(alias[0]) else: return str(alias)
def repeater_wake_up(self, _data): _source = _data[1:5] _source_name = get_alias(_source, peer_ids) print('({}) Repeater Wake-Up Packet Received: {} ({})' .format(self._system, _source_name, int_id(_source)))
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Check for GLOBAL Subscriber ID ACL Match if acl_check(_rf_src, ACL['SID']['GLOBAL'][_slot]) == False: if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY INGRESS GLOBAL ACL*** SID: %s SLOT: %s HBP Peer %s', self._system, int_id(_rf_src), _slot, int_id(_peer_id)) self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id return # Check for SYSTEM Subscriber ID ACL Match if acl_check(_rf_src, ACL['SID'][self._system][_slot]) == False: if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY INGRESS SYSTEM ACL*** SID: %s SLOT: %s HBP Peer %s', self._system, int_id(_rf_src), _slot, int_id(_peer_id)) self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id return # Check for GLOBAL Talkgroup ID ACL Match if acl_check(_dst_id, ACL['TGID']['GLOBAL'][_slot]) == False: if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY INGRESS GLOBAL ACL*** TGID: %s SLOT: %s HBP Peer %s', self._system, int_id(_dst_id), _slot, int_id(_peer_id)) self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id return # Check for SYSTEM Talkgroup ID ID ACL Match if acl_check(_dst_id, ACL['TGID'][self._system][_slot]) == False: if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY INGRESS SYSTEM ACL*** TGID: %s SLOT: %s HBP Peer %s', self._system, int_id(_dst_id), _slot, int_id(_peer_id)) self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id return # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC ) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and ( self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id for _target in self._CONFIG['SYSTEMS']: if _target != self._system: _target_status = systems[_target].STATUS _target_system = self._CONFIG['SYSTEMS'][_target] # Check for GLOBAL Subscriber ID ACL Match if acl_check(_rf_src, ACL['SID']['GLOBAL'][_slot]) == False: if (_stream_id != _target_status[_slot]['TX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY EGRESS GLOBAL ACL*** SID: %s SLOT: %s HBP Peer %s', _target, int_id(_rf_src), _slot, int_id(_peer_id)) _target_status[_slot]['TX_STREAM_ID'] = _stream_id return # Check for SYSTEM Subscriber ID ACL Match if acl_check(_rf_src, ACL['SID'][_target][_slot]) == False: if (_stream_id != _target_status[_slot]['TX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY EGRESS SYSTEM ACL*** SID: %s SLOT: %s HBP Peer %s', _target, int_id(_rf_src), _slot, int_id(_peer_id)) _target_status[_slot]['TX_STREAM_ID'] = _stream_id return # Check for GLOBAL Talkgroup ID ACL Match if acl_check(_dst_id, ACL['TGID']['GLOBAL'][_slot]) == False: if (_stream_id != _target_status[_slot]['TX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY EGRESS GLOBAL ACL*** TGID: %s SLOT: %s HBP Peer %s', _target, int_id(_dst_id), _slot, int_id(_peer_id)) _target_status[_slot]['TX_STREAM_ID'] = _stream_id return # Check for SYSTEM Talkgroup ID ID ACL Match if acl_check(_dst_id, ACL['TGID'][_target][_slot]) == False: if (_stream_id != _target_status[_slot]['TX_STREAM_ID']): self._logger.warning( '(%s) Group Voice Call ***REJECTED BY EGRESS SYSTEM ACL*** TGID: %s HBP Peer %s', _target, int_id(_dst_id), int_id(_peer_id)) _target_status[_slot]['TX_STREAM_ID'] = _stream_id return systems[_target].send_system(_data)
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 repeater_wake_up(self, _data): _source = _data[1:5] _source_name = get_alias(_source, peer_ids) print('({}) Repeater Wake-Up Packet Received: {} ({})'.format( self._system, _source_name, int_id(_source)))
def group_data(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): _dst_sub = get_alias(_dst_sub, talkgroup_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) print('({}) Group Data Packet Received From: {}'.format( self._system, _src_sub))
def private_data(self, _src_sub, _dst_sub, _ts, _end, _peerid, _data): _dst_sub = get_alias(_dst_sub, subscriber_ids) _peerid = get_alias(_peerid, peer_ids) _src_sub = get_alias(_src_sub, subscriber_ids) print('({}) Private Data Packet Received From: {} To: {}'.format( self._system, _src_sub, _dst_sub))
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) # Final actions - Is this a voice terminator? if (_frame_type == hb_const.HBPF_DATA_SYNC) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS['RX_START'] logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id for _target in self._CONFIG['SYSTEMS']: if _target != self._system: _target_status = systems[_target].STATUS _target_system = self._CONFIG['SYSTEMS'][_target] _target_status[_slot]['TX_STREAM_ID'] = _stream_id # ACL Processing if self._CONFIG['GLOBAL']['USE_ACL']: if not acl_check(_rf_src, self._CONFIG['GLOBAL']['SUB_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL ACL', _target_system, int_id(_stream_id), int_id(_rf_src)) self._laststrid = _stream_id return if _slot == 1 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG1_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL', _target_system, int_id(_stream_id), int_id(_dst_id)) self._laststrid = _stream_id return if _slot == 2 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG2_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY GLOBAL TS2 ACL', _target_system, int_id(_stream_id), int_id(_dst_id)) self._laststrid = _stream_id return if self._target_system['USE_ACL']: if not acl_check(_rf_src, _target_system['SUB_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s FROM SUBSCRIBER %s BY SYSTEM ACL', _target_system, int_id(_stream_id), int_id(_rf_src)) self._laststrid = _stream_id return if _slot == 1 and not acl_check(_dst_id, _target_system['TG1_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY SYSTEM TS1 ACL', _target_system, int_id(_stream_id), int_id(_dst_id)) self._laststrid = _stream_id return if _slot == 2 and not acl_check(_dst_id, _target_system['TG2_ACL']): if self._laststrid != _stream_id: logger.debug('(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY SYSTEM TS2 ACL', _target_system, int_id(_stream_id), int_id(_dst_id)) self._laststrid = _stream_id return self._laststrid = _stream_id systems[_target].send_system(_data)