Merge branch AMI

Add All Star Link control
ta
Simon 4 years ago
parent 2448469a11
commit 84e0978577

@ -0,0 +1,77 @@
import sys
from time import time
from twisted.internet import reactor,task
from twisted.internet.defer import Deferred
from twisted.internet.protocol import ClientFactory,ClientFactory,Protocol
from twisted.protocols.basic import LineReceiver
class AMI():
def __init__(self,host,port,username,secret,nodenum):
self._AMIClient = self.AMIClient
self.host = host
self.port = port
self.username = username.encode('utf-8')
self.secret = secret.encode('utf-8')
self.nodenum = str(nodenum)
def send_command(self,command):
self._AMIClient.command = command.encode('utf-8')
self._AMIClient.username = self.username
self._AMIClient.secret = self.secret
self._AMIClient.nodenum = self.nodenum.encode('utf-8')
self.command = command
self.CF = reactor.connectTCP(self.host, self.port, self.AMIClientFactory(self._AMIClient))
def closeConnection(self):
self.transport.loseConnection()
class AMIClient(LineReceiver):
delimiter = b'\r\n'
def connectionMade(self):
self.sendLine(b'Action: login')
self.sendLine(b''.join([b'Username: ',self.username]))
self.sendLine(b''.join([b'Secret: ',self.secret]))
self.sendLine(self.delimiter)
def lineReceived(self,line):
print(line)
if line == b'Asterisk Call Manager/1.0':
return
if line == b'Response: Success':
self.sendLine(b'Action: command')
#print(b''.join([b'Command: ',b'rpt cmd ',self.nodenum,b' ',self.command]))
self.sendLine(b''.join([b'Command: ',b'rpt cmd ',self.nodenum,b' ',self.command]))
#self.sendLine(b'Command: ' + b'rpt cmd 29177 ilink 3 2001')
self.sendLine(self.delimiter)
self.transport.loseConnection()
class AMIClientFactory(ClientFactory):
def __init__(self,AMIClient):
#self.command = command
self.done = Deferred()
self.protocol = AMIClient
#self.protocol.command = command
def clientConnectionFailed(self, connector, reason):
ClientFactory.clientConnectionLost(self, connector, reason)
def clientConnectionLost(self, connector, reason):
ClientFactory.clientConnectionLost(self, connector, reason)
if __name__ == '__main__':
a = AMI(sys.argv[1],int(sys.argv[2]),'admin','llcgi',29177)
#AMIOBJ.AMIClientFactory(AMIOBJ.AMIClient,'rpt cmd 29177 ilink 3 2001')
a.send_command(sys.argv[3])
reactor.run()

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
<EFBFBD>£œÝÌš¿…Bá}"¬û¼Ž¨ˆš  ÈD¼Ž¨ˆš  ÈD¼Ž¨ˆš  ÈD¼Ž¨ˆš  ÈD¼Ž¨ˆš  ÈDÜÌΊžè̈ÈÜÌΊžèÌˆÈ¼Ž¨ˆš  ÈDì¶ô†µ®.¯Ä+Ày“ÛÆâUxòÅ©³•H¤7[Ì4ÝIßD…PyãóÃTûÂg„!ÎܨX‡#+¢œx²

@ -80,6 +80,7 @@ import re
from binascii import b2a_hex as ahex from binascii import b2a_hex as ahex
from AMI import AMI
##from hmac import new as hmac_new, compare_digest ##from hmac import new as hmac_new, compare_digest
##from hashlib import sha256, hash ##from hashlib import sha256, hash
@ -1828,7 +1829,8 @@ class routerHBP(HBSYSTEM):
'lastSeq': False, 'lastSeq': False,
'lastData': False, 'lastData': False,
'packets': 0, 'packets': 0,
'crcs': set() 'crcs': set(),
'_allStarMode': False
}, },
2: { 2: {
'RX_START': time(), 'RX_START': time(),
@ -1858,7 +1860,8 @@ class routerHBP(HBSYSTEM):
'lastSeq': False, 'lastSeq': False,
'lastData': False, 'lastData': False,
'packets': 0, 'packets': 0,
'crcs': set() 'crcs': set(),
'_allStarMode': False
} }
} }
@ -2116,6 +2119,10 @@ class routerHBP(HBSYSTEM):
#Add system to SUB_MAP #Add system to SUB_MAP
SUB_MAP[_rf_src] = (self._system,_slot,pkt_time) SUB_MAP[_rf_src] = (self._system,_slot,pkt_time)
def resetallStarMode():
self.STATUS[_slot]['_allStarMode'] = False
logger.info('(%s) Reset all star mode -> dial mode',self._system)
#Rewrite GPS Data comming in as a group call to a unit call #Rewrite GPS Data comming in as a group call to a unit call
#if (_call_type == 'group' or _call_type == 'vcsbk') and _int_dst_id == 900999: #if (_call_type == 'group' or _call_type == 'vcsbk') and _int_dst_id == 900999:
#_bits = header(_slot,'unit',_bits) #_bits = header(_slot,'unit',_bits)
@ -2164,7 +2171,7 @@ class routerHBP(HBSYSTEM):
for system in systems: for system in systems:
if system == self._system: if system == self._system:
continue continue
#We only want to send data calls to individual IDs via OpenBridge #We only want to send data calls to individual IDs via FreeBridge (not OpenBridge)
if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000):
self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot) self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot)
@ -2226,10 +2233,41 @@ class routerHBP(HBSYSTEM):
else: else:
logger.info('(%s) UNIT Data not bridged to HBP on slot %s - target busy: %s DST_ID: %s',self._system,_d_slot,_d_system,_int_dst_id) logger.info('(%s) UNIT Data not bridged to HBP on slot %s - target busy: %s DST_ID: %s',self._system,_d_slot,_d_system,_int_dst_id)
#Handle AMI private calls
if _call_type == 'unit' and not _data_call and self.STATUS[_slot]['_allStarMode'] and CONFIG['ALLSTAR']['ENABLED']:
if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']):
logger.info('(%s) AMI: Private call from %s to %s',self._system, int_id(_rf_src), _int_dst_id)
if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM):
if _int_dst_id == 4000:
logger.info('(%s) AMI: Private call from %s to %s (Disconnect)',self._system, int_id(_rf_src), _int_dst_id)
AMIOBJ.send_command('ilink 6 0')
elif _int_dst_id == 5000:
logger.info('(%s) AMI: Private call from %s to %s (Status)',self._system, int_id(_rf_src), _int_dst_id)
AMIOBJ.send_command('ilink 5 0')
else:
logger.info('(%s) AMI: Private call from %s to %s (Link)',self._system, int_id(_rf_src), _int_dst_id)
AMIOBJ.send_command('ilink 6 0')
AMIOBJ.send_command('ilink 3 ' + str(_int_dst_id))
# 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
self.STATUS[_slot]['VOICE_STREAM'] = _voice_call
self.STATUS[_slot]['packets'] = self.STATUS[_slot]['packets'] +1
#Handle private voice calls (for reflectors) #Handle private voice calls (for reflectors)
if _call_type == 'unit' and not _data_call: elif _call_type == 'unit' and not _data_call and not self.STATUS[_slot]['_allStarMode']:
if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']):
self.STATUS[_slot]['packets'] = 0 self.STATUS[_slot]['packets'] = 0
@ -2238,7 +2276,7 @@ class routerHBP(HBSYSTEM):
self.STATUS[_slot]['_stopTgAnnounce'] = False self.STATUS[_slot]['_stopTgAnnounce'] = False
logger.info('(%s) Reflector: Private call from %s to %s',self._system, int_id(_rf_src), _int_dst_id) logger.info('(%s) Reflector: Private call from %s to %s',self._system, int_id(_rf_src), _int_dst_id)
if _int_dst_id >= 5 and _int_dst_id != 9 and _int_dst_id <= 999999: if _int_dst_id >= 5 and _int_dst_id != 8 and _int_dst_id != 9 and _int_dst_id <= 999999:
_bridgename = '#'+ str(_int_dst_id) _bridgename = '#'+ str(_int_dst_id)
if _bridgename not in BRIDGES and not (_int_dst_id >= 4000 and _int_dst_id <= 5000) and not (_int_dst_id >=9991 and _int_dst_id <= 9999): if _bridgename not in BRIDGES and not (_int_dst_id >= 4000 and _int_dst_id <= 5000) and not (_int_dst_id >=9991 and _int_dst_id <= 9999):
logger.info('(%s) [A] Reflector for TG %s does not exist. Creating as User Activated. Timeout: %s',self._system, _int_dst_id,CONFIG['SYSTEMS'][self._system]['DEFAULT_UA_TIMER']) logger.info('(%s) [A] Reflector for TG %s does not exist. Creating as User Activated. Timeout: %s',self._system, _int_dst_id,CONFIG['SYSTEMS'][self._system]['DEFAULT_UA_TIMER'])
@ -2304,6 +2342,15 @@ class routerHBP(HBSYSTEM):
_say.append(words[_lang]['busy']) _say.append(words[_lang]['busy'])
_say.append(words[_lang]['silence']) _say.append(words[_lang]['silence'])
self.STATUS[_slot]['_stopTgAnnounce'] = True self.STATUS[_slot]['_stopTgAnnounce'] = True
#Allstar mode switch
if CONFIG['ALLSTAR']['ENABLED'] and _int_dst_id == 8:
logger.info('(%s) Reflector: voice called - TG 8 AllStar"', self._system)
_say.append(words[_lang]['all-star-link-mode'])
_say.append(words[_lang]['silence'])
self.STATUS[_slot]['_stopTgAnnounce'] = True
self.STATUS[_slot]['_allStarMode'] = True
reactor.callLater(30,resetallStarMode)
#If disconnection called #If disconnection called
if _int_dst_id == 4000: if _int_dst_id == 4000:
@ -2375,7 +2422,7 @@ class routerHBP(HBSYSTEM):
self.STATUS[_slot]['VOICE_STREAM'] = _voice_call self.STATUS[_slot]['VOICE_STREAM'] = _voice_call
self.STATUS[_slot]['packets'] = self.STATUS[_slot]['packets'] +1 self.STATUS[_slot]['packets'] = self.STATUS[_slot]['packets'] +1
#Handle group calls #Handle group calls
if _call_type == 'group' or _call_type == 'vcsbk': if _call_type == 'group' or _call_type == 'vcsbk':
@ -2695,17 +2742,17 @@ if __name__ == '__main__':
#If MySQL is enabled, read master config from MySQL too #If MySQL is enabled, read master config from MySQL too
if CONFIG['MYSQL']['USE_MYSQL'] == True: if CONFIG['MYSQL']['USE_MYSQL'] == True:
logger.debug('(MYSQL) MySQL config enabled') logger.info('(MYSQL) MySQL config enabled')
SQLCONFIG = {} SQLCONFIG = {}
sql = useMYSQL(CONFIG['MYSQL']['SERVER'], CONFIG['MYSQL']['USER'], CONFIG['MYSQL']['PASS'], CONFIG['MYSQL']['DB'],CONFIG['MYSQL']['TABLE'],logger) sql = useMYSQL(CONFIG['MYSQL']['SERVER'], CONFIG['MYSQL']['USER'], CONFIG['MYSQL']['PASS'], CONFIG['MYSQL']['DB'],CONFIG['MYSQL']['TABLE'],logger)
#Run it once immediately #Run it once immediately
if sql.con(): if sql.con():
logger.debug('(MYSQL) reading config from database') logger.info('(MYSQL) reading config from database')
try: try:
SQLCONFIG = sql.getConfig() SQLCONFIG = sql.getConfig()
#Add MySQL config data to config dict #Add MySQL config data to config dict
except: except:
logger.debug('(MYSQL) problem with SQL query, aborting') logger.warning('(MYSQL) problem with SQL query, aborting')
sql.close() sql.close()
logger.debug('(MYSQL) building ACLs') logger.debug('(MYSQL) building ACLs')
# Build ACLs # Build ACLs
@ -2716,8 +2763,13 @@ if __name__ == '__main__':
CONFIG['SYSTEMS'].update(SQLCONFIG) CONFIG['SYSTEMS'].update(SQLCONFIG)
else: else:
logger.debug('(MYSQL) problem connecting to SQL server, aborting') logger.warning('(MYSQL) problem connecting to SQL server, aborting')
if CONFIG['ALLSTAR']['ENABLED']:
logger.info('(AMI) Setting up AMI: Server: %s, Port: %s, User: %s, Pass: %s, Node: %s',CONFIG['ALLSTAR']['SERVER'],CONFIG['ALLSTAR']['PORT'],CONFIG['ALLSTAR']['USER'],CONFIG['ALLSTAR']['PASS'],CONFIG['ALLSTAR']['NODE'])
AMIOBJ = AMI(CONFIG['ALLSTAR']['SERVER'],CONFIG['ALLSTAR']['PORT'],CONFIG['ALLSTAR']['USER'],CONFIG['ALLSTAR']['PASS'],CONFIG['ALLSTAR']['NODE'])
# Set up the signal handler # Set up the signal handler
def sig_handler(_signal, _frame): def sig_handler(_signal, _frame):

@ -129,6 +129,7 @@ def build_config(_config_file):
CONFIG['ALIASES'] = {} CONFIG['ALIASES'] = {}
CONFIG['SYSTEMS'] = {} CONFIG['SYSTEMS'] = {}
CONFIG['MYSQL'] = {} CONFIG['MYSQL'] = {}
CONFIG['ALLSTAR'] = {}
try: try:
for section in config.sections(): for section in config.sections():
@ -194,6 +195,17 @@ def build_config(_config_file):
'TABLE': config.get(section, 'TABLE') 'TABLE': config.get(section, 'TABLE')
}) })
elif section == 'ALLSTAR':
CONFIG['ALLSTAR'].update({
'ENABLED': config.getboolean(section, 'ENABLED'),
'USER': config.get(section, 'USER'),
'PASS': config.get(section, 'PASS'),
'SERVER': gethostbyname(config.get(section, 'SERVER')),
'PORT': config.getint(section,'PORT'),
'NODE' : config.getint(section,'NODE')
})
elif config.getboolean(section, 'ENABLED'): elif config.getboolean(section, 'ENABLED'):
if config.get(section, 'MODE') == 'PEER': if config.get(section, 'MODE') == 'PEER':

@ -109,13 +109,15 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'linkedto': 'linked-to',
'allstar-link-mode': 'alpha'
}, },
'en_US': { 'en_US': {
'to': '2', 'to': '2',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'alpha'
}, },
'es_ES': { 'es_ES': {
@ -156,7 +158,8 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'linkedto': 'linked-to',
'allstar-link-mode': 'alfa'
}, },
'es_ES_2': { 'es_ES_2': {
'1': 'one', '1': 'one',
@ -196,7 +199,8 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'linkedto': 'linked-to',
'allstar-link-mode': 'alpha'
}, },
'fr_FR': { 'fr_FR': {
@ -228,7 +232,8 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'linkedto': 'linked-to',
'allstar-link-mode': 'alpha'
}, },
'pt_PT': { 'pt_PT': {
@ -260,7 +265,8 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'linkedto': 'linked-to',
'allstar-link-mode': 'alpha'
}, },
'el_GR': { 'el_GR': {
@ -292,55 +298,63 @@ voiceMap = {
'Z': 'zulu', 'Z': 'zulu',
'to': 'silence', 'to': 'silence',
'notlinked': 'not-linked', 'notlinked': 'not-linked',
'linkedto': 'linked-to' 'allstar-link-mode': 'alpha'
}, },
'de_DE': { 'de_DE': {
'to': 'silence', 'to': 'silence',
'allstar-link-mode': 'A'
}, },
'dk_DK': { 'dk_DK': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'A'
}, },
'it_IT': { 'it_IT': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'A'
}, },
'no_NO': { 'no_NO': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'A'
}, },
'pl_PL': { 'pl_PL': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'A'
}, },
'se_SE': { 'se_SE': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence' 'this-is': 'silence',
'allstar-link-mode': 'A'
}, },
'CW': { 'CW': {
'to': 'silence', 'to': 'silence',
'freedmr': 'silence', 'freedmr': 'silence',
'this-is': 'silence', 'this-is': 'silence',
'linkedto': 'silence' 'linkedto': 'silence',
'allstar-link-mode': 'T'
}, },
'th_TH': { 'th_TH': {
'to': 'silence', 'to': 'silence',
'allstar-link-mode': 'A'
}, },

Loading…
Cancel
Save

Powered by TurnKey Linux.