TIMESLOT TRANSLATION WORKS!
This commit is contained in:
parent
324c16660c
commit
648569eb91
61
bridge.py
61
bridge.py
|
@ -47,6 +47,13 @@ __email__ = 'n0mjs@me.com'
|
||||||
__status__ = 'beta'
|
__status__ = 'beta'
|
||||||
|
|
||||||
|
|
||||||
|
BURST_DATA_TYPE = {
|
||||||
|
'VOICE_HEAD': '\x01',
|
||||||
|
'VOICE_TERM': '\x02',
|
||||||
|
'SLOT1_VOICE': '\x0A',
|
||||||
|
'SLOT2_VOICE': '\x8A'
|
||||||
|
}
|
||||||
|
|
||||||
# Notes and pieces of next steps...
|
# Notes and pieces of next steps...
|
||||||
# RPT_WAKE_UP = b'\x85' + NETWORK[_network]['LOCAL']['RADIO_ID] + b'\x00\x00\x00\x01' + b'\x01' + b'\x01'
|
# RPT_WAKE_UP = b'\x85' + NETWORK[_network]['LOCAL']['RADIO_ID] + b'\x00\x00\x00\x01' + b'\x01' + b'\x01'
|
||||||
# TS1 = 0, TS2 = 1
|
# TS1 = 0, TS2 = 1
|
||||||
|
@ -70,7 +77,9 @@ for _ipsc in RULES:
|
||||||
for _rule in RULES[_ipsc]['GROUP_VOICE']:
|
for _rule in RULES[_ipsc]['GROUP_VOICE']:
|
||||||
_rule['SRC_GROUP'] = hex_str_3(_rule['SRC_GROUP'])
|
_rule['SRC_GROUP'] = hex_str_3(_rule['SRC_GROUP'])
|
||||||
_rule['DST_GROUP'] = hex_str_3(_rule['DST_GROUP'])
|
_rule['DST_GROUP'] = hex_str_3(_rule['DST_GROUP'])
|
||||||
print()
|
_rule['SRC_TS'] = _rule['SRC_TS'] - 1
|
||||||
|
_rule['DST_TS'] = _rule['DST_TS'] - 1
|
||||||
|
|
||||||
|
|
||||||
# Import List of Bridges
|
# Import List of Bridges
|
||||||
# This is how we identify known bridges. If one of these is present
|
# This is how we identify known bridges. If one of these is present
|
||||||
|
@ -155,6 +164,30 @@ if BRIDGES:
|
||||||
# Re-Write the destination Group ID
|
# Re-Write the destination Group ID
|
||||||
_tmp_data = _tmp_data.replace(_dst_group, rule['DST_GROUP'])
|
_tmp_data = _tmp_data.replace(_dst_group, rule['DST_GROUP'])
|
||||||
|
|
||||||
|
# Re-Write IPSC timeslot value
|
||||||
|
_call_info = int_id(_data[17:18])
|
||||||
|
if rule['DST_TS'] == 0:
|
||||||
|
_call_info &= ~(1 << 5)
|
||||||
|
elif rule['DST_TS'] == 1:
|
||||||
|
_call_info |= 1 << 5
|
||||||
|
_call_info = chr(_call_info)
|
||||||
|
_tmp_data = _tmp_data[:17] + _call_info + _tmp_data[18:]
|
||||||
|
|
||||||
|
# Re-Write DMR timeslot value
|
||||||
|
# Determine if the slot is present, so we can translate if need be
|
||||||
|
_burst_data_type = _data[30]
|
||||||
|
if _burst_data_type == BURST_DATA_TYPE['SLOT1_VOICE'] or _burst_data_type == BURST_DATA_TYPE['SLOT2_VOICE']:
|
||||||
|
_slot_valid = True
|
||||||
|
else:
|
||||||
|
_slot_valid = False
|
||||||
|
# Re-Write timeslot if necessary...
|
||||||
|
if _slot_valid:
|
||||||
|
if rule['DST_TS'] == 0:
|
||||||
|
_burst_data_type = BURST_DATA_TYPE['SLOT1_VOICE']
|
||||||
|
elif rule['DST_TS'] == 1:
|
||||||
|
_burst_data_type = BURST_DATA_TYPE['SLOT2_VOICE']
|
||||||
|
_tmp_data = _tmp_data[:30] + _burst_data_type + _tmp_data[31:]
|
||||||
|
|
||||||
# Calculate and append the authentication hash for the target network... if necessary
|
# Calculate and append the authentication hash for the target network... if necessary
|
||||||
if NETWORK[_target]['LOCAL']['AUTH_ENABLED']:
|
if NETWORK[_target]['LOCAL']['AUTH_ENABLED']:
|
||||||
_tmp_data = self.hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
|
_tmp_data = self.hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
|
||||||
|
@ -184,15 +217,39 @@ else:
|
||||||
# timer = time()
|
# timer = time()
|
||||||
|
|
||||||
for rule in RULES[_network]['GROUP_VOICE']:
|
for rule in RULES[_network]['GROUP_VOICE']:
|
||||||
|
_target = rule['DST_NET']
|
||||||
# Matching for rules is against the Destination Group in the SOURCE packet (SRC_GROUP)
|
# Matching for rules is against the Destination Group in the SOURCE packet (SRC_GROUP)
|
||||||
if rule['SRC_GROUP'] == _dst_group and rule['SRC_TS'] == _ts:
|
if rule['SRC_GROUP'] == _dst_group and rule['SRC_TS'] == _ts:
|
||||||
_tmp_data = _data
|
_tmp_data = _data
|
||||||
_target = rule['DST_NET']
|
|
||||||
# Re-Write the IPSC SRC to match the target network's ID
|
# Re-Write the IPSC SRC to match the target network's ID
|
||||||
_tmp_data = _tmp_data.replace(_peerid, NETWORK[_target]['LOCAL']['RADIO_ID'])
|
_tmp_data = _tmp_data.replace(_peerid, NETWORK[_target]['LOCAL']['RADIO_ID'])
|
||||||
# Re-Write the destination Group ID
|
# Re-Write the destination Group ID
|
||||||
_tmp_data = _tmp_data.replace(_dst_group, rule['DST_GROUP'])
|
_tmp_data = _tmp_data.replace(_dst_group, rule['DST_GROUP'])
|
||||||
|
|
||||||
|
# Re-Write IPSC timeslot value
|
||||||
|
_call_info = int_id(_data[17:18])
|
||||||
|
if rule['DST_TS'] == 0:
|
||||||
|
_call_info &= ~(1 << 5)
|
||||||
|
elif rule['DST_TS'] == 1:
|
||||||
|
_call_info |= 1 << 5
|
||||||
|
_call_info = chr(_call_info)
|
||||||
|
_tmp_data = _tmp_data[:17] + _call_info + _tmp_data[18:]
|
||||||
|
|
||||||
|
# Re-Write DMR timeslot value
|
||||||
|
# Determine if the slot is present, so we can translate if need be
|
||||||
|
_burst_data_type = _data[30]
|
||||||
|
if _burst_data_type == BURST_DATA_TYPE['SLOT1_VOICE'] or _burst_data_type == BURST_DATA_TYPE['SLOT2_VOICE']:
|
||||||
|
_slot_valid = True
|
||||||
|
else:
|
||||||
|
_slot_valid = False
|
||||||
|
# Re-Write timeslot if necessary...
|
||||||
|
if _slot_valid:
|
||||||
|
if rule['DST_TS'] == 0:
|
||||||
|
_burst_data_type = BURST_DATA_TYPE['SLOT1_VOICE']
|
||||||
|
elif rule['DST_TS'] == 1:
|
||||||
|
_burst_data_type = BURST_DATA_TYPE['SLOT2_VOICE']
|
||||||
|
_tmp_data = _tmp_data[:30] + _burst_data_type + _tmp_data[31:]
|
||||||
|
|
||||||
# Calculate and append the authentication hash for the target network... if necessary
|
# Calculate and append the authentication hash for the target network... if necessary
|
||||||
if NETWORK[_target]['LOCAL']['AUTH_ENABLED']:
|
if NETWORK[_target]['LOCAL']['AUTH_ENABLED']:
|
||||||
_tmp_data = self.hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
|
_tmp_data = self.hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
|
||||||
|
|
|
@ -10,14 +10,14 @@ The IPSC name must match an IPSC name from dmrlink.cfg, and any IPSC network def
|
||||||
as "active" in the dmrlink.cfg *MUST* have an entry here. It may be an empty entry,
|
as "active" in the dmrlink.cfg *MUST* have an entry here. It may be an empty entry,
|
||||||
but there must be one so that the data structure can be parsed.
|
but there must be one so that the data structure can be parsed.
|
||||||
|
|
||||||
The example below cross-patches TGID 1 on an IPSC network named "IPSC_FOO" with TGID 2
|
The example below cross-patches TS 1/TGID 1 on an IPSC network named "IPSC_FOO" with
|
||||||
on an IPSC network named "IPSC_BAR". Note, one entry must be made on EACH IPSC network
|
TS 2/TGID 2 on an IPSC network named "IPSC_BAR". Note, one entry must be made on EACH
|
||||||
(IPSC_FOO and IPSC_BAR in this example) for bridging to occur in both directions.
|
IPSC network (IPSC_FOO and IPSC_BAR in this example) for bridging to occur in both
|
||||||
|
directions.
|
||||||
|
|
||||||
THIS EXAMPLE WILL NOT WORK AS IT IS - YOU MUST SPECIFY NAMES AND GROUP IDS!!!
|
THIS EXAMPLE WILL NOT WORK AS IT IS - YOU MUST SPECIFY NAMES AND GROUP IDS!!!
|
||||||
|
|
||||||
NOTES:
|
NOTES:
|
||||||
* Timeslot transcoding does not yet work (SRC_TS) and (DST_TS) are ignored.
|
|
||||||
* Only GROUP_VOICE is currently used by the bridge.py appication, the other
|
* Only GROUP_VOICE is currently used by the bridge.py appication, the other
|
||||||
types are placeholders for when it does more.
|
types are placeholders for when it does more.
|
||||||
'''
|
'''
|
||||||
|
@ -25,7 +25,7 @@ NOTES:
|
||||||
RULES = {
|
RULES = {
|
||||||
'IPSC_FOO': {
|
'IPSC_FOO': {
|
||||||
'GROUP_VOICE': [
|
'GROUP_VOICE': [
|
||||||
{'SRC_GROUP': 1, 'SRC_TS': 1, 'DST_NET': 'IPSC_BAR', 'DST_GROUP': 2, 'DST_TS': 1},
|
{'SRC_GROUP': 1, 'SRC_TS': 1, 'DST_NET': 'IPSC_BAR', 'DST_GROUP': 2, 'DST_TS': 2},
|
||||||
# Repeat the above line for as many rules for this IPSC network as you want.
|
# Repeat the above line for as many rules for this IPSC network as you want.
|
||||||
],
|
],
|
||||||
'PRIVATE_VOICE': [
|
'PRIVATE_VOICE': [
|
||||||
|
@ -37,7 +37,7 @@ RULES = {
|
||||||
},
|
},
|
||||||
'IPSC_BAR': {
|
'IPSC_BAR': {
|
||||||
'GROUP_VOICE': [
|
'GROUP_VOICE': [
|
||||||
{'SRC_GROUP': 2, 'SRC_TS': 1, 'DST_NET': 'IPSC_FOO', 'DST_GROUP': 1, 'DST_TS': 1},
|
{'SRC_GROUP': 2, 'SRC_TS': 2, 'DST_NET': 'IPSC_FOO', 'DST_GROUP': 1, 'DST_TS': 1},
|
||||||
# Repeat the above line for as many rules for this IPSC network as you want.
|
# Repeat the above line for as many rules for this IPSC network as you want.
|
||||||
],
|
],
|
||||||
'PRIVATE_VOICE': [
|
'PRIVATE_VOICE': [
|
||||||
|
|
|
@ -111,41 +111,11 @@ REPEAT = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Conditions for accepting certain types of messages... the cornerstone of a secure IPSC system :)
|
# DMR IPSC Contants (in the RTP Payload)
|
||||||
'''
|
|
||||||
REQ_VALID_PEER = [
|
|
||||||
PEER_REG_REQ,
|
|
||||||
PEER_REG_REPLY
|
|
||||||
]
|
|
||||||
|
|
||||||
REQ_VALID_MASTER = [
|
BURST_DATA_TYPE = {
|
||||||
MASTER_REG_REQ,
|
'VOICE_HEAD': '\x01',
|
||||||
MASTER_REG_REPLY
|
'VOICE_TERM': '\x02',
|
||||||
]
|
'SLOT1_VOICE': '\x0A',
|
||||||
|
'SLOT2_VOICE': '\x8A'
|
||||||
REQ_MASTER_CONNECTED = [
|
}
|
||||||
CALL_MON_STATUS,
|
|
||||||
CALL_MON_RPT,
|
|
||||||
CALL_MON_NACK,
|
|
||||||
XCMP_XNL,
|
|
||||||
GROUP_VOICE,
|
|
||||||
PVT_VOICE,
|
|
||||||
GROUP_DATA,
|
|
||||||
GROUP_VOICE,
|
|
||||||
PVT_DATA,
|
|
||||||
RPT_WAKE_UP,
|
|
||||||
MASTER_ALIVE_REQ,
|
|
||||||
MASTER_ALIVE_REPLY,
|
|
||||||
DE_REG_REQ,
|
|
||||||
DE_REG_REPLY
|
|
||||||
]
|
|
||||||
|
|
||||||
REQ_PEER_CONNECTED = [
|
|
||||||
PEER_ALIVE_REQ,
|
|
||||||
PEER_ALIVE_REPLY
|
|
||||||
]
|
|
||||||
|
|
||||||
REQ_VALID_MASTER_OR_PEER = [
|
|
||||||
REQ_VALID_PEER, REQ_VALID_MASTER
|
|
||||||
]
|
|
||||||
'''
|
|
||||||
|
|
Loading…
Reference in New Issue