diff --git a/bridge.py b/bridge.py index 8beb76a..4a5942d 100755 --- a/bridge.py +++ b/bridge.py @@ -246,7 +246,7 @@ class routerOBP(OPENBRIDGE): self.STATUS[_stream_id]['LC'] = LC_OPT + _dst_id + _rf_src - logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ + logger.info('(%s) *GROUP 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 CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) @@ -402,14 +402,14 @@ class routerOBP(OPENBRIDGE): # Final actions - Is this a voice terminator? if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS[_stream_id]['START'] - logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %.2f', \ + logger.info('(%s) *GROUP CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %.2f', \ 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) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,END,RX,{},{},{},{},{},{},{:.2f}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), call_duration).encode(encoding='utf-8', errors='ignore')) removed = self.STATUS.pop(_stream_id) logger.debug('(%s) OpenBridge sourced call stream end, remove terminated Stream ID: %s', self._system, int_id(_stream_id)) if not removed: - selflogger.error('(%s) *CALL END* STREAM ID: %s NOT IN LIST -- THIS IS A REAL PROBLEM', self._system, int_id(_stream_id)) + selflogger.error('(%s) *GROUP CALL END* STREAM ID: %s NOT IN LIST -- THIS IS A REAL PROBLEM', self._system, int_id(_stream_id)) def unit_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _frame_type, _dtype_vseq, _stream_id, _data): @@ -496,9 +496,16 @@ class routerHBP(HBSYSTEM): def group_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _frame_type, _dtype_vseq, _stream_id, _data): + global UNIT_MAP pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] + + # Make an entry in the UNIT_MAP for this subscriber + if _rf_src not in UNIT_MAP: + UNIT_MAP[_rf_src] = [self.name, pkt_time] + else: + UNIT_MAP[_rf_src][1] = pkt_time # Is this a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): @@ -508,7 +515,7 @@ class routerHBP(HBSYSTEM): # This is a new call stream self.STATUS[_slot]['RX_START'] = pkt_time - logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ + logger.info('(%s) *GROUP 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 CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) @@ -640,9 +647,6 @@ class routerHBP(HBSYSTEM): # Assemble transmit HBP packet header _tmp_data = b''.join([_data[:8], _target['TGID'], _data[11:15], _tmp_bits.to_bytes(1, 'big'), _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) @@ -669,7 +673,7 @@ class routerHBP(HBSYSTEM): # Final actions - Is this a voice terminator? if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM): call_duration = pkt_time - self.STATUS[_slot]['RX_START'] - logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %.2f', \ + logger.info('(%s) *GROUP CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Duration: %.2f', \ 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) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,END,RX,{},{},{},{},{},{},{:.2f}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), call_duration).encode(encoding='utf-8', errors='ignore')) @@ -744,12 +748,88 @@ class routerHBP(HBSYSTEM): pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] - print(UNIT_MAP) + if _rf_src not in UNIT_MAP: UNIT_MAP[_rf_src] = [self.name, pkt_time] else: UNIT_MAP[_rf_src][1] = pkt_time + # Is this a new call stream? + if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): + if (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM) and (pkt_time < (self.STATUS[_slot]['RX_TIME'] + STREAM_TO)) and (_rf_src != self.STATUS[_slot]['RX_RFS']): + logger.warning('(%s) Packet received with STREAM ID: %s SUB: %s PEER: %s UNIT %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[_slot]['RX_START'] = pkt_time + logger.info('(%s) *UNIT CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) UNIT %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 CONFIG['REPORTS']['REPORT']: + self._report.send_bridgeEvent('UNIT VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) + + # If we can, use the LC from the voice header as to keep all options intact + if _frame_type == HBPF_DATA_SYNC and _dtype_vseq == 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'] = LC_OPT + _dst_id + _rf_src + + + #if _dst_id in UNIT_MAP: + if True: + _target = UNIT_MAP[_dst_id][0] + + #if _target != self._system: + if True: + _target_status = systems[_target].STATUS + _target_system = self._CONFIG['SYSTEMS'][_target] + + + # Is this a new call stream? + if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): + # Record the DST TGID and Stream ID + _target_status[_slot]['TX_START'] = pkt_time + _target_status[_slot]['TX_TGID'] = _dst_id + _target_status[_slot]['TX_STREAM_ID'] = _stream_id + _target_status[_slot]['TX_RFS'] = _rf_src + _target_status[_slot]['TX_PEER'] = _peer_id + + # Set other values for the contention handler to test next time there is a frame to forward + _target_status[_slot]['TX_TIME'] = pkt_time + _target_status[_slot]['TX_TYPE'] = _dtype_vseq + + #send the call: + + systems[_target].send_system(_data) + + + else: + pass + #for target in systems: + # systems[target].send_system(_data) + + + + # Final actions - Is this a voice terminator? + if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM): + call_duration = pkt_time - self.STATUS[_slot]['RX_START'] + logger.info('(%s) *UNIT CALL END* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) UNIT %s (%s), TS %s, Duration: %.2f', \ + 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) + if CONFIG['REPORTS']['REPORT']: + self._report.send_bridgeEvent('UNIT VOICE,END,RX,{},{},{},{},{},{},{:.2f}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id), call_duration).encode(encoding='utf-8', errors='ignore')) + + # Mark status variables for use later + self.STATUS[_slot]['RX_PEER'] = _peer_id + self.STATUS[_slot]['RX_SEQ'] = _seq + 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 dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):