Official Version V0.1 Release

This commit is contained in:
Cort Buffington 2014-01-02 11:16:23 -06:00
parent 2375162f30
commit 97246370c5
2 changed files with 128 additions and 41 deletions

View File

@ -24,6 +24,15 @@ from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet import task
__author__ = 'Cortney T. Buffington, N0MJS'
__copyright__ = 'Copyright (c) 2013 Cortney T. Buffington, N0MJS and the K0USY Group'
__credits__ = 'Adam Fast, KC0YLK, Dave K, and he who wishes not to be named'
__license__ = 'Creative Commons Attribution-ShareAlike 3.0 Unported'
__version__ = '0.1'
__maintainer__ = 'Cort Buffington, N0MJS'
__email__ = 'n0mjs@me.com'
__status__ = 'Production'
#************************************************
# PARSE THE CONFIG FILE AND BUILD STRUCTURE
#************************************************
@ -40,9 +49,11 @@ except:
try:
for section in config.sections():
if section == 'GLOBAL':
# Process GLOBAL items in the configuration
PATH = config.get(section, 'PATH')
elif section == 'REPORTS':
# Process REPORTS items in the configuration
REPORTS = {
'REPORT_PEERS': config.getboolean(section, 'REPORT_PEERS'),
'PEER_REPORT_INC_MODE': config.getboolean(section, 'PEER_REPORT_INC_MODE'),
@ -50,32 +61,49 @@ try:
}
elif section == 'LOGGER':
# Process LOGGER items in the configuration
LOGGER = {
'LOG_FILE': config.get(section, 'LOG_FILE'),
'LOG_HANDLERS': config.get(section, 'LOG_HANDLERS'),
'LOG_LEVEL': config.get(section, 'LOG_LEVEL')
}
else:
# All other sections define indiviual IPSC Networks we connect to
# Each IPSC network config will contain the following three sections
NETWORK.update({section: {'LOCAL': {}, 'MASTER': {}, 'PEERS': {}}})
# LOCAL means we need to know this stuff to be a peer in the network
NETWORK[section]['LOCAL'].update({
# In case we want to keep config, but not actually connect to the network
'ENABLED': config.getboolean(section, 'ENABLED'),
# These items are used to create the MODE byte
'PEER_OPER': config.getboolean(section, 'PEER_OPER'),
'IPSC_MODE': config.get(section, 'IPSC_MODE'),
'TS1_LINK': config.getboolean(section, 'TS1_LINK'),
'TS2_LINK': config.getboolean(section, 'TS2_LINK'),
'MODE': '',
'PEER_OPER': True,
'PEER_MODE': 'DIGITAL',
'FLAGS': '',
'MAX_MISSED': 20,
'NUM_PEERS': 0,
'STATUS': {
'ACTIVE': False
},
'ENABLED': config.getboolean(section, 'ENABLED'),
'TS1_LINK': config.getboolean(section, 'TS1_LINK'),
'TS2_LINK': config.getboolean(section, 'TS2_LINK'),
# These items are used to create the multi-byte FLAGS field
'AUTH_ENABLED': config.getboolean(section, 'AUTH_ENABLED'),
'RADIO_ID': hex(int(config.get(section, 'RADIO_ID')))[2:].rjust(8,'0').decode('hex'),
'PORT': config.getint(section, 'PORT'),
'ALIVE_TIMER': config.getint(section, 'ALIVE_TIMER'),
'AUTH_KEY': (config.get(section, 'AUTH_KEY').rjust(40,'0')).decode('hex'),
'CSBK_CALL': config.getboolean(section, 'CSBK_CALL'),
'RCM': config.getboolean(section, 'RCM'),
'CON_APP': config.getboolean(section, 'CON_APP'),
'XNL_CALL': config.getboolean(section, 'XNL_CALL'),
'XNL_MASTER': config.getboolean(section, 'XNL_MASTER'),
'DATA_CALL': config.getboolean(section, 'DATA_CALL'),
'VOICE_CALL': config.getboolean(section, 'VOICE_CALL'),
'MASTER_PEER': config.getboolean(section, 'MASTER_PEER'),
'FLAGS': '',
# Things we need to know to connect and be a peer in this IPSC
'RADIO_ID': hex(int(config.get(section, 'RADIO_ID')))[2:].rjust(8,'0').decode('hex'),
'PORT': config.getint(section, 'PORT'),
'ALIVE_TIMER': config.getint(section, 'ALIVE_TIMER'),
'MAX_MISSED': config.getint(section, 'MAX_MISSED'),
'AUTH_KEY': (config.get(section, 'AUTH_KEY').rjust(40,'0')).decode('hex'),
'NUM_PEERS': 0,
})
# Master means things we need to know about the master peer of the network
NETWORK[section]['MASTER'].update({
'RADIO_ID': '\x00\x00\x00\x00',
'MODE': '\x00',
@ -92,22 +120,51 @@ try:
'IP': config.get(section, 'MASTER_IP'),
'PORT': config.getint(section, 'MASTER_PORT')
})
# Temporary locations for building MODE and FLAG data
MODE_BYTE = 0
FLAG_1 = 0
FLAG_2 = 0
# Construct and store the MODE field
if NETWORK[section]['LOCAL']['PEER_OPER']:
MODE_BYTE |= 1 << 6
if NETWORK[section]['LOCAL']['IPSC_MODE'] == 'ANALOG':
MODE_BYTE |= 1 << 4
elif NETWORK[section]['LOCAL']['IPSC_MODE'] == 'DIGITAL':
MODE_BYTE |= 1 << 5
if NETWORK[section]['LOCAL']['TS1_LINK']:
MODE_BYTE |= 1 << 3
else:
MODE_BYTE |= 1 << 2
if NETWORK[section]['LOCAL']['TS2_LINK']:
MODE_BYTE |= 1 << 1
else:
MODE_BYTE |= 1 << 0
NETWORK[section]['LOCAL']['MODE'] = chr(MODE_BYTE)
# Construct and store the FLAGS field
if NETWORK[section]['LOCAL']['CSBK_CALL']:
FLAG_1 |= 1 << 7
if NETWORK[section]['LOCAL']['RCM']:
FLAG_1 |= 1 << 6
if NETWORK[section]['LOCAL']['CON_APP']:
FLAG_1 |= 1 << 5
if NETWORK[section]['LOCAL']['XNL_CALL']:
FLAG_2 |= 1 << 7
if NETWORK[section]['LOCAL']['XNL_CALL'] and NETWORK[section]['LOCAL']['XNL_MASTER']:
FLAG_2 |= 1 << 6
elif NETWORK[section]['LOCAL']['XNL_CALL'] and not NETWORK[section]['LOCAL']['XNL_MASTER']:
FLAG_2 |= 1 << 5
if NETWORK[section]['LOCAL']['AUTH_ENABLED']:
#0x60 - 3rd Party App & Repeater Monitoring, 0x1C - Voice and Data calls only, 0xDC - Voice, Data and XCMP/XNL
NETWORK[section]['LOCAL']['FLAGS'] = '\x00\x00\x60\x1C'
#NETWORK[section]['LOCAL']['FLAGS'] = '\x00\x00\x60\xDC'
else:
NETWORK[section]['LOCAL']['FLAGS'] = '\x00\x00\x60\x0C'
if not NETWORK[section]['LOCAL']['TS1_LINK'] and not NETWORK[section]['LOCAL']['TS2_LINK']:
NETWORK[section]['LOCAL']['MODE'] = '\x65'
elif NETWORK[section]['LOCAL']['TS1_LINK'] and not NETWORK[section]['LOCAL']['TS2_LINK']:
NETWORK[section]['LOCAL']['MODE'] = '\x66'
elif not NETWORK[section]['LOCAL']['TS1_LINK'] and NETWORK[section]['LOCAL']['TS2_LINK']:
NETWORK[section]['LOCAL']['MODE'] = '\x69'
else:
NETWORK[section]['LOCAL']['MODE'] = '\x6A'
FLAG_2 |= 1 << 4
if NETWORK[section]['LOCAL']['DATA_CALL']:
FLAG_2 |= 1 << 3
if NETWORK[section]['LOCAL']['VOICE_CALL']:
FLAG_2 |= 1 << 2
if NETWORK[section]['LOCAL']['MASTER_PEER']:
FLAG_2 |= 1 << 0
NETWORK[section]['LOCAL']['FLAGS'] = '\x00\x00'+chr(FLAG_1)+chr(FLAG_2)
except:
sys.exit('Could not parse configuration file, exiting...')
@ -395,7 +452,7 @@ def process_peer_list(_data, _network):
for peerid in NETWORK[_network]['PEERS'].keys():
if peerid not in _temp_peers:
de_register_peer(_network, peerid)
logger.warning('(%s) Peer Deleted (not in new peer list): %s', _network, peerid)
logger.warning('(%s) Peer Deleted (not in new peer list): %s', _network, h(peerid))
# Gratuitous print-out of the peer list.. Pretty much debug stuff.
@ -479,7 +536,6 @@ class IPSC(DatagramProtocol):
self._config = NETWORK[self._network]
#
self._local = self._config['LOCAL']
self._local_stat = self._local['STATUS']
self._local_id = self._local['RADIO_ID']
#
self._master = self._config['MASTER']
@ -946,4 +1002,4 @@ if __name__ == '__main__':
else:
networks[ipsc_network] = UnauthIPSC(ipsc_network)
reactor.listenUDP(NETWORK[ipsc_network]['LOCAL']['PORT'], networks[ipsc_network])
reactor.run()
reactor.run()

View File

@ -41,6 +41,8 @@ LOG_LEVEL: CRITICAL
# CONFIGURATION FOR IPSC NETWORKS
# Please read these closely - catastrophic results could result by setting
# certain flags for things DMRlink cannot do.
#
# [NAME] The name you want to use to identify the IPSC instance (use
# something better than "IPSC1"...)
@ -49,7 +51,25 @@ LOG_LEVEL: CRITICAL
# RADIO_ID: This is the radio ID that DMRLink should use to communicate
# PORT: This is the UDP source port for DMRLink to use for this
# IPSC network, must be unique!!!
# ALIVE_TIMER: How many missed keep-alives before we remove a peer
# ALIVE_TIMER: Seconds between keep-alive transmissions
# MAX_MISSED: How many missed keep-alives before we remove a peer
# PEER_OPER: This signals the master and peers whether or not we are
# operational. True is the only thing that makes sense.
# IPSC_MODE: May be 'DIGITAL', 'ANALOG', or 'NONE'. Digital is really the
# only thing that makes sense.
# TSx_LINK: Is this time slot linked?
# CSBK_CALL: Should be False, we cannot process these, but may be useful
# for debugging.
# RCM: Repeater Call Monitoring - don't unable unless you plan to
# actually use it, this craetes extra network traffic.
# CON_APP: Third Party Console App - exactly what DMRlink is, should
# be set to True.
# XNL_CALL: Can cause problems if not set to False, DMRlink does not
# process XCMP/XNL calls.
# XNL_MASTER: Obviously, should also be False, see XNL_CALL.
# DATA_CALL: Process data calls. True if you want to process data calls
# VOICE_CALL: Process voice calls. True if you want to process voice calls
# MASTER_PEER: Must be False, we cannot yet act as a master peer.
# AUTH_ENABLED: Do we use authenticated IPSC?
# AUTH_KEY: The Authentication key (up to 40 hex characters)
# MASTER_IP: IP address of the IPSC master
@ -69,14 +89,25 @@ AUTH_KEY: 1
MASTER_IP: 1.2.3.4
MASTER_PORT: 50000
[IPSC2]
[IPSC1]
ENABLED: True
RADIO_ID: 2
PORT: 50001
RADIO_ID: 12345
PORT: 50000
ALIVE_TIMER: 5
MAX_MISSED: 20
PEER_OPER = True
IPSC_MODE = DIGITAL
TS1_LINK: True
TS2_LINK: True
AUTH_ENABLED: True
AUTH_KEY: 2
MASTER_IP: 5.6.7.8
MASTER_PORT: 50000
CSBK_CALL = False
RCM = True
CON_APP = True
XNL_CALL = False
XNL_MASTER = False
DATA_CALL = True
VOICE_CALL = True
MASTER_PEER = False
AUTH_ENABLED = True
AUTH_KEY: 1A2B3C
MASTER_IP: 1.2.3.4
MASTER_PORT: 50000