|
|
|
|
@ -1011,6 +1011,61 @@ def SubMapTrimmer():
|
|
|
|
|
subMapWrite()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def dataGatewayEnabled():
|
|
|
|
|
"""Return true when the dedicated native Data Gateway link is active."""
|
|
|
|
|
return (
|
|
|
|
|
CONFIG['GLOBAL'].get('DATA_GATEWAY', False)
|
|
|
|
|
and 'DATA-GATEWAY' in CONFIG['SYSTEMS']
|
|
|
|
|
and CONFIG['SYSTEMS']['DATA-GATEWAY']['MODE'] == 'OPENBRIDGE'
|
|
|
|
|
and CONFIG['SYSTEMS']['DATA-GATEWAY']['ENABLED']
|
|
|
|
|
and 'DATA-GATEWAY' in systems
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def isHdstackSubscriberObservation(_system, _hops, _source_server, _source_rptr):
|
|
|
|
|
"""Return true for HBP-originated traffic relayed by this HDStack."""
|
|
|
|
|
_instances = CONFIG['GLOBAL'].get('HDSTACK_INSTANCES', 0)
|
|
|
|
|
_base_server_id = CONFIG['GLOBAL'].get('HDSTACK_BASE_SERVER_ID', 0)
|
|
|
|
|
if not _instances or not _base_server_id:
|
|
|
|
|
return False
|
|
|
|
|
if _system != 'OBP-HDSTACK-AGGREGATOR':
|
|
|
|
|
return False
|
|
|
|
|
if not isinstance(_hops, bytes) or len(_hops) != 1 or int_id(_hops) != 3:
|
|
|
|
|
return False
|
|
|
|
|
if not isinstance(_source_rptr, bytes) or len(_source_rptr) != 4 or not int_id(_source_rptr):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
_source_server_id = int_id(_source_server)
|
|
|
|
|
_local_server_id = int_id(CONFIG['GLOBAL']['SERVER_ID'])
|
|
|
|
|
return (
|
|
|
|
|
_base_server_id < _source_server_id <= _base_server_id + _instances
|
|
|
|
|
and _source_server_id != _local_server_id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def subMapTarget(_subscriber):
|
|
|
|
|
"""Resolve a subscriber's last observed access peer on this process."""
|
|
|
|
|
if _subscriber not in SUB_MAP:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
(_location, _slot, _observed) = SUB_MAP[_subscriber]
|
|
|
|
|
if isinstance(_location, bytes) and len(_location) == 4:
|
|
|
|
|
for _system in systems:
|
|
|
|
|
_system_config = CONFIG['SYSTEMS'][_system]
|
|
|
|
|
if (
|
|
|
|
|
_system_config['MODE'] == 'MASTER'
|
|
|
|
|
and _location in _system_config['PEERS']
|
|
|
|
|
):
|
|
|
|
|
return (_system, _slot, _observed)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# Retain old single-process persisted maps. HDStack system names are local
|
|
|
|
|
# to each worker and therefore cannot safely identify another worker's peer.
|
|
|
|
|
if not CONFIG['GLOBAL'].get('HDSTACK_INSTANCES', 0) and _location in systems:
|
|
|
|
|
return (_location, _slot, _observed)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# run this every 10 seconds to trim stream ids
|
|
|
|
|
def stream_trimmer_loop():
|
|
|
|
|
logger.debug('(ROUTER) Trimming inactive stream IDs from system lists')
|
|
|
|
|
@ -2020,6 +2075,9 @@ class routerOBP(OPENBRIDGE):
|
|
|
|
|
|
|
|
|
|
log_dmr_data_observation(self, self._system, 'FBP/OBP', _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, dmrpkt)
|
|
|
|
|
|
|
|
|
|
if isHdstackSubscriberObservation(self._system, _hops, _source_server, _source_rptr):
|
|
|
|
|
SUB_MAP[_rf_src] = (_source_rptr, _slot, pkt_time)
|
|
|
|
|
|
|
|
|
|
#pkt_crc = Crc32.calc(_data[4:53])
|
|
|
|
|
#_pkt_crc = Crc32.calc(dmrpkt)
|
|
|
|
|
|
|
|
|
|
@ -2121,12 +2179,6 @@ class routerOBP(OPENBRIDGE):
|
|
|
|
|
logger.info('(%s) *UNKNOWN DATA TYPE* STREAM ID: %s, RPTR: %s, SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, RPTR: %s', \
|
|
|
|
|
self._system, int_id(_stream_id), self.get_rptr(_source_rptr), 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,int_id(_source_server),int_id(_source_rptr))
|
|
|
|
|
|
|
|
|
|
#Send all data to DATA-GATEWAY if enabled and valid
|
|
|
|
|
if CONFIG['GLOBAL']['DATA_GATEWAY'] and 'DATA-GATEWAY' in CONFIG['SYSTEMS'] and CONFIG['SYSTEMS']['DATA-GATEWAY']['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS']['DATA-GATEWAY']['ENABLED']:
|
|
|
|
|
logger.debug('(%s) DATA packet sent to DATA-GATEWAY',self._system)
|
|
|
|
|
self.sendDataToOBP('DATA-GATEWAY',_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_source_rptr,_ber,_rssi)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Send other openbridges
|
|
|
|
|
for system in systems:
|
|
|
|
|
if system == self._system:
|
|
|
|
|
@ -2139,8 +2191,9 @@ class routerOBP(OPENBRIDGE):
|
|
|
|
|
self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops,_source_server,_ber,_rssi,_source_rptr)
|
|
|
|
|
|
|
|
|
|
#If destination ID is in the Subscriber Map
|
|
|
|
|
if _dst_id in SUB_MAP:
|
|
|
|
|
(_d_system,_d_slot,_d_time) = SUB_MAP[_dst_id]
|
|
|
|
|
_sub_map_target = subMapTarget(_dst_id)
|
|
|
|
|
if _sub_map_target:
|
|
|
|
|
(_d_system,_d_slot,_d_time) = _sub_map_target
|
|
|
|
|
_dst_slot = systems[_d_system].STATUS[_d_slot]
|
|
|
|
|
logger.info('(%s) SUB_MAP matched, System: %s Slot: %s, Time: %s',self._system, _d_system,_d_slot,_d_time)
|
|
|
|
|
#If slot is idle for RX and TX
|
|
|
|
|
@ -2669,7 +2722,7 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
if CONFIG['REPORTS']['REPORT']:
|
|
|
|
|
systems[_d_system]._report.send_bridgeEvent('UNIT DATA,DATA,TX,{},{},{},{},{},{}'.format(_d_system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _d_slot, _int_dst_id).encode(encoding='utf-8', errors='ignore'))
|
|
|
|
|
|
|
|
|
|
def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00', _source_rptr = b'\x00\x00\x00\x00'):
|
|
|
|
|
def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00', _source_rptr = b'\x00\x00\x00\x00', _report_data = True):
|
|
|
|
|
# _sysIgnore = sysIgnore
|
|
|
|
|
_source_server = self._CONFIG['GLOBAL']['SERVER_ID']
|
|
|
|
|
_source_rptr = _peer_id
|
|
|
|
|
@ -2680,9 +2733,13 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
#We want to ignore this system and TS combination if it's called again for this packet
|
|
|
|
|
# _sysIgnore.append((_target,_target['TS']))
|
|
|
|
|
|
|
|
|
|
#If target has quenched us, don't send
|
|
|
|
|
if ('_bcsq' in _target_system) and (_dst_id in _target_system['_bcsq']) and (_target_system['_bcsq'][_dst_id] == _stream_id):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
#If target has missed 6 (in 1 min) of keepalives, don't send
|
|
|
|
|
if _target_system['ENHANCED_OBP'] and ('_bcka' not in _target_system or _target_system['_bcka'] < pkt_time - 60):
|
|
|
|
|
return
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
if (_stream_id not in _target_status):
|
|
|
|
|
# This is a new call stream on the target
|
|
|
|
|
@ -2707,10 +2764,38 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
_tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]])
|
|
|
|
|
_tmp_data = b''.join([_tmp_data, dmrpkt])
|
|
|
|
|
systems[_target].send_system(_tmp_data,b'',_ber,_rssi,_source_server,_source_rptr)
|
|
|
|
|
logger.debug('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id)
|
|
|
|
|
if CONFIG['REPORTS']['REPORT']:
|
|
|
|
|
if _report_data:
|
|
|
|
|
logger.debug('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id)
|
|
|
|
|
if _report_data and CONFIG['REPORTS']['REPORT']:
|
|
|
|
|
systems[_target]._report.send_bridgeEvent('UNIT DATA,DATA,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore'))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def sendToDataGateway(self,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_ber,_rssi):
|
|
|
|
|
if not dataGatewayEnabled():
|
|
|
|
|
return
|
|
|
|
|
if self.sendDataToOBP(
|
|
|
|
|
'DATA-GATEWAY',
|
|
|
|
|
_data,
|
|
|
|
|
dmrpkt,
|
|
|
|
|
pkt_time,
|
|
|
|
|
_stream_id,
|
|
|
|
|
_dst_id,
|
|
|
|
|
_peer_id,
|
|
|
|
|
_rf_src,
|
|
|
|
|
_bits,
|
|
|
|
|
_slot,
|
|
|
|
|
_ber=_ber,
|
|
|
|
|
_rssi=_rssi,
|
|
|
|
|
_report_data=False,
|
|
|
|
|
):
|
|
|
|
|
logger.debug(
|
|
|
|
|
'(%s) Locally originated HBP packet sent to DATA-GATEWAY, '
|
|
|
|
|
'STREAM ID: %s DST_ID: %s',
|
|
|
|
|
self._system,
|
|
|
|
|
int_id(_stream_id),
|
|
|
|
|
int_id(_dst_id),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
|
|
|
|
|
|
|
|
|
|
@ -2753,8 +2838,24 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
_data_call = False
|
|
|
|
|
_voice_call = False
|
|
|
|
|
|
|
|
|
|
#Add system to SUB_MAP
|
|
|
|
|
SUB_MAP[_rf_src] = (self._system,_slot,pkt_time)
|
|
|
|
|
# Record the access peer so the location remains valid across HDStack workers.
|
|
|
|
|
SUB_MAP[_rf_src] = (_peer_id,_slot,pkt_time)
|
|
|
|
|
|
|
|
|
|
# The Data Gateway observes locally originated HBP traffic only. It owns
|
|
|
|
|
# data decoding and any consent or application policy above this link.
|
|
|
|
|
self.sendToDataGateway(
|
|
|
|
|
_data,
|
|
|
|
|
dmrpkt,
|
|
|
|
|
pkt_time,
|
|
|
|
|
_stream_id,
|
|
|
|
|
_dst_id,
|
|
|
|
|
_peer_id,
|
|
|
|
|
_rf_src,
|
|
|
|
|
_bits,
|
|
|
|
|
_slot,
|
|
|
|
|
_ber,
|
|
|
|
|
_rssi,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def resetallStarMode():
|
|
|
|
|
self.STATUS[_slot]['_allStarMode'] = False
|
|
|
|
|
@ -2804,11 +2905,6 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Send all data to DATA-GATEWAY if enabled and valid
|
|
|
|
|
if CONFIG['GLOBAL']['DATA_GATEWAY'] and 'DATA-GATEWAY' in CONFIG['SYSTEMS'] and CONFIG['SYSTEMS']['DATA-GATEWAY']['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS']['DATA-GATEWAY']['ENABLED']:
|
|
|
|
|
logger.debug('(%s) DATA packet sent to DATA-GATEWAY',self._system)
|
|
|
|
|
self.sendDataToOBP('DATA-GATEWAY',_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_ber=_ber,_rssi=_rssi)
|
|
|
|
|
|
|
|
|
|
#Send to all openbridges
|
|
|
|
|
# sysIgnore = []
|
|
|
|
|
for system in systems:
|
|
|
|
|
@ -2821,8 +2917,9 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_ber=_ber,_rssi=_rssi)
|
|
|
|
|
|
|
|
|
|
#If destination ID is in the Subscriber Map
|
|
|
|
|
if _dst_id in SUB_MAP:
|
|
|
|
|
(_d_system,_d_slot,_d_time) = SUB_MAP[_dst_id]
|
|
|
|
|
_sub_map_target = subMapTarget(_dst_id)
|
|
|
|
|
if _sub_map_target:
|
|
|
|
|
(_d_system,_d_slot,_d_time) = _sub_map_target
|
|
|
|
|
_dst_slot = systems[_d_system].STATUS[_d_slot]
|
|
|
|
|
logger.info('(%s) SUB_MAP matched, System: %s Slot: %s, Time: %s',self._system, _d_system,_d_slot,_d_time)
|
|
|
|
|
#If slot is idle for RX and TX
|
|
|
|
|
@ -2837,7 +2934,7 @@ class routerHBP(HBSYSTEM):
|
|
|
|
|
else:
|
|
|
|
|
logger.debug('(%s) UNIT Data not bridged to HBP on slot 1 - target busy: %s DST_ID: %s',self._system,_d_system,_int_dst_id)
|
|
|
|
|
|
|
|
|
|
elif _int_dst_id == 900999:
|
|
|
|
|
elif _int_dst_id == 900999 and not dataGatewayEnabled():
|
|
|
|
|
if 'D-APRS' in systems and CONFIG['SYSTEMS']['D-APRS']['MODE'] == 'MASTER':
|
|
|
|
|
_d_system = 'D-APRS'
|
|
|
|
|
_d_slot = _slot
|
|
|
|
|
|