2013-12-10 00:47:21 +00:00
2014-01-03 01:36:50 +00:00
# Copyright 2011, 2012, 2013, 2014 Max H. Parke KA1RBI
2013-12-10 00:47:21 +00:00
#
# This file is part of OP25
#
# OP25 is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# OP25 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with OP25; see the file COPYING. If not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Boston, MA
# 02110-1301, USA.
#
# FIXME: hideously mixes indentation, some is tabs and some is spaces
#
import time
def crc16 ( dat , len ) : # slow version
poly = ( 1 << 12 ) + ( 1 << 5 ) + ( 1 << 0 )
crc = 0
for i in range ( len ) :
bits = ( dat >> ( ( ( len - 1 ) - i ) * 8 ) ) & 0xff
for j in range ( 8 ) :
bit = ( bits >> ( 7 - j ) ) & 1
crc = ( ( crc << 1 ) | bit ) & 0x1ffff
if crc & 0x10000 :
crc = ( crc & 0xffff ) ^ poly
crc = crc ^ 0xffff
return crc
2014-02-07 02:54:59 +00:00
def get_frequency ( f ) : # return frequency in Hz
if f . find ( ' . ' ) == - 1 : # assume in Hz
return int ( f )
else : # assume in MHz due to '.'
return int ( float ( f ) * 1000000 )
2013-12-10 00:47:21 +00:00
class trunked_system ( object ) :
def __init__ ( self , debug = 0 , config = None ) :
self . debug = debug
self . freq_table = { }
self . stats = { }
self . stats [ ' tsbks ' ] = 0
self . stats [ ' crc ' ] = 0
self . tsbk_cache = { }
self . secondary = { }
self . adjacent = { }
self . rfss_syid = 0
self . rfss_rfid = 0
self . rfss_stid = 0
self . rfss_chan = 0
self . rfss_txchan = 0
self . ns_syid = 0
self . ns_wacn = 0
self . ns_chan = 0
self . voice_frequencies = { }
self . blacklist = { }
self . whitelist = None
self . tgid_map = None
self . offset = 0
self . sysname = 0
self . trunk_cc = 0
if config :
self . blacklist = config [ ' blacklist ' ]
self . whitelist = config [ ' whitelist ' ]
self . tgid_map = config [ ' tgid_map ' ]
self . offset = config [ ' offset ' ]
self . sysname = config [ ' sysname ' ]
self . trunk_cc = config [ ' cclist ' ] [ 0 ] # TODO: scan thru list
2014-02-07 02:54:59 +00:00
self . center_frequency = config [ ' center_frequency ' ]
2013-12-10 00:47:21 +00:00
def to_string ( self ) :
s = [ ]
s . append ( ' rf: syid %x rfid %d stid %d frequency %f uplink %f ' % ( self . rfss_syid , self . rfss_rfid , self . rfss_stid , float ( self . rfss_chan ) / 1000000.0 , float ( self . rfss_txchan ) / 1000000.0 ) )
s . append ( ' net: syid %x wacn %x frequency %f ' % ( self . ns_syid , self . ns_wacn , float ( self . ns_chan ) / 1000000.0 ) )
s . append ( ' secondary control channel(s): %s ' % ' , ' . join ( [ ' %f ' % ( float ( k ) / 1000000.0 ) for k in self . secondary . keys ( ) ] ) )
s . append ( ' stats: tsbks %d crc %d ' % ( self . stats [ ' tsbks ' ] , self . stats [ ' crc ' ] ) )
s . append ( ' ' )
t = time . time ( )
for f in self . voice_frequencies :
s . append ( ' voice frequency %f tgid %d %4.1f s ago count %d ' % ( f / 1000000.0 , self . voice_frequencies [ f ] [ ' tgid ' ] , t - self . voice_frequencies [ f ] [ ' time ' ] , self . voice_frequencies [ f ] [ ' counter ' ] ) )
s . append ( ' ' )
for table in self . freq_table :
a = self . freq_table [ table ] [ ' frequency ' ] / 1000000.0
b = self . freq_table [ table ] [ ' step ' ] / 1000000.0
c = self . freq_table [ table ] [ ' offset ' ] / 1000000.0
s . append ( ' tbl-id: %x frequency: %f step %f offset %f ' % ( table , a , b , c ) )
#self.freq_table[table]['frequency'] / 1000000.0, self.freq_table[table]['step'] / 1000000.0, self.freq_table[table]['offset']) / 1000000.0)
for f in self . adjacent :
s . append ( ' adjacent %f : %s ' % ( float ( f ) / 1000000.0 , self . adjacent [ f ] ) )
return ' \n ' . join ( s )
# return frequency in Hz
def channel_id_to_frequency ( self , id ) :
table = ( id >> 12 ) & 0xf
channel = id & 0xfff
if table not in self . freq_table :
return None
return self . freq_table [ table ] [ ' frequency ' ] + self . freq_table [ table ] [ ' step ' ] * channel
def channel_id_to_string ( self , id ) :
table = ( id >> 12 ) & 0xf
channel = id & 0xfff
if table not in self . freq_table :
return " %x - %d " % ( table , channel )
return " %f " % ( ( self . freq_table [ table ] [ ' frequency ' ] + self . freq_table [ table ] [ ' step ' ] * channel ) / 1000000.0 )
def get_tag ( self , tgid ) :
if not tgid :
return " "
if tgid not in self . tgid_map :
return " Talkgroup ID %d [0x %x ] " % ( tgid , tgid )
return self . tgid_map [ tgid ]
def update_voice_frequency ( self , frequency , tgid = None ) :
if frequency is None :
return
if frequency not in self . voice_frequencies :
self . voice_frequencies [ frequency ] = { ' counter ' : 0 }
self . voice_frequencies [ frequency ] [ ' tgid ' ] = tgid
self . voice_frequencies [ frequency ] [ ' counter ' ] + = 1
self . voice_frequencies [ frequency ] [ ' time ' ] = time . time ( )
def find_voice_frequency ( self , start_time , tgid = None ) :
for frequency in self . voice_frequencies :
if self . voice_frequencies [ frequency ] [ ' time ' ] < start_time :
continue
active_tgid = self . voice_frequencies [ frequency ] [ ' tgid ' ]
if active_tgid in self . blacklist :
continue
if self . whitelist and active_tgid not in self . whitelist :
continue
if tgid is None or tgid == active_tgid :
return frequency , active_tgid
return None , None
def add_blacklist ( self , tgid ) :
if not tgid :
return
self . blacklist [ tgid ] = 1
def decode_mbt_data ( self , opcode , header , mbt_data ) :
if self . debug > 10 :
print " decode_mbt_data: %x %x " % ( opcode , mbt_data )
if opcode == 0x0 : # grp voice channel grant
ch1 = ( mbt_data >> 64 ) & 0xffff
ch2 = ( mbt_data >> 48 ) & 0xffff
ga = ( mbt_data >> 32 ) & 0xffff
if self . debug > 10 :
print " mbt00 voice grant ch1 %x ch2 %x addr 0x %x " % ( ch1 , ch2 , ga )
elif opcode == 0x3c : # adjacent status
syid = ( header >> 48 ) & 0xfff
rfid = ( header >> 24 ) & 0xff
stid = ( header >> 16 ) & 0xff
ch1 = ( mbt_data >> 80 ) & 0xffff
ch2 = ( mbt_data >> 64 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
f2 = self . channel_id_to_frequency ( ch2 )
if f1 and f2 :
self . adjacent [ f1 ] = ' rfid: %d stid: %d uplink: %f ' % ( rfid , stid , f2 / 1000000.0 )
if self . debug > 10 :
print " mbt3c adjacent sys %x rfid %x stid %x ch1 %x ch2 %x f1 %s f2 %s " % ( syid , rfid , stid , ch1 , ch2 , self . channel_id_to_string ( ch1 ) , self . channel_id_to_string ( ch2 ) )
elif opcode == 0x3b : # network status
syid = ( header >> 48 ) & 0xfff
wacn = ( mbt_data >> 76 ) & 0xfffff
ch1 = ( mbt_data >> 56 ) & 0xffff
ch2 = ( mbt_data >> 40 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
f2 = self . channel_id_to_frequency ( ch2 )
if f1 and f2 :
self . ns_syid = syid
self . ns_wacn = wacn
self . ns_chan = f1
if self . debug > 10 :
print " mbt3b net stat sys %x wacn %x ch1 %s ch2 %s " % ( syid , wacn , self . channel_id_to_string ( ch1 ) , self . channel_id_to_string ( ch2 ) )
elif opcode == 0x3a : # rfss status
syid = ( header >> 48 ) & 0xfff
rfid = ( mbt_data >> 88 ) & 0xff
stid = ( mbt_data >> 80 ) & 0xff
ch1 = ( mbt_data >> 64 ) & 0xffff
ch2 = ( mbt_data >> 48 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
f2 = self . channel_id_to_frequency ( ch2 )
if f1 and f2 :
self . rfss_syid = syid
self . rfss_rfid = rfid
self . rfss_stid = stid
self . rfss_chan = f1
self . rfss_txchan = f2
if self . debug > 10 :
print " mbt3a rfss stat sys %x rfid %x stid %x ch1 %s ch2 %s " % ( syid , rfid , stid , self . channel_id_to_string ( ch1 ) , self . channel_id_to_string ( ch2 ) )
#else:
# print "mbt other %x" % opcode
def decode_tsbk ( self , tsbk ) :
self . stats [ ' tsbks ' ] + = 1
updated = 0
# if crc16(tsbk, 12) != 0:
# self.stats['crc'] += 1
# return # crc check failed
tsbk = tsbk << 16 # for missing crc
opcode = ( tsbk >> 88 ) & 0x3f
if self . debug > 10 :
print " TSBK: 0x %02x 0x %024x " % ( opcode , tsbk )
if opcode == 0x02 : # group voice chan grant update
mfrid = ( tsbk >> 80 ) & 0xff
ch1 = ( tsbk >> 64 ) & 0xffff
ga1 = ( tsbk >> 48 ) & 0xffff
ch2 = ( tsbk >> 32 ) & 0xffff
ga2 = ( tsbk >> 16 ) & 0xffff
if mfrid == 0x90 :
if self . debug > 10 :
ch1 = ( tsbk >> 56 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
if f1 == None : f1 = 0
print " tsbk02[90] %x %f " % ( ch1 , f1 / 1000000.0 )
else :
f1 = self . channel_id_to_frequency ( ch1 )
f2 = self . channel_id_to_frequency ( ch2 )
self . update_voice_frequency ( f1 , tgid = ga1 )
if f1 != f2 :
self . update_voice_frequency ( f2 , tgid = ga2 )
if f1 :
updated + = 1
if f2 :
updated + = 1
if self . debug > 10 :
print " tsbk02 grant update: chan %s %d %s %d " % ( self . channel_id_to_string ( ch1 ) , ga1 , self . channel_id_to_string ( ch2 ) , ga2 )
elif opcode == 0x16 : # sndcp data ch
ch1 = ( tsbk >> 48 ) & 0xffff
ch2 = ( tsbk >> 32 ) & 0xffff
if self . debug > 10 :
print " tsbk16 sndcp data ch: chan %x %x " % ( ch1 , ch2 )
elif opcode == 0x34 : # iden_up vhf uhf
iden = ( tsbk >> 76 ) & 0xf
bwvu = ( tsbk >> 72 ) & 0xf
toff0 = ( tsbk >> 58 ) & 0x3fff
spac = ( tsbk >> 48 ) & 0x3ff
freq = ( tsbk >> 16 ) & 0xffffffff
toff_sign = ( toff0 >> 13 ) & 1
toff = toff0 & 0x1fff
if toff_sign == 0 :
toff = 0 - toff
txt = [ " mob Tx- " , " mob Tx+ " ]
self . freq_table [ iden ] = { }
self . freq_table [ iden ] [ ' offset ' ] = toff * spac * 125
self . freq_table [ iden ] [ ' step ' ] = spac * 125
self . freq_table [ iden ] [ ' frequency ' ] = freq * 5
if self . debug > 10 :
print " tsbk34 iden vhf/uhf id %d toff %f spac %f freq %f [ %s ] " % ( iden , toff * spac * 0.125 * 1e-3 , spac * 0.125 , freq * 0.000005 , txt [ toff_sign ] )
elif opcode == 0x3d : # iden_up
iden = ( tsbk >> 76 ) & 0xf
bw = ( tsbk >> 67 ) & 0x1ff
toff0 = ( tsbk >> 58 ) & 0x1ff
spac = ( tsbk >> 48 ) & 0x3ff
freq = ( tsbk >> 16 ) & 0xffffffff
toff_sign = ( toff0 >> 8 ) & 1
toff = toff0 & 0xff
if toff_sign == 0 :
toff = 0 - toff
txt = [ " mob xmit < recv " , " mob xmit > recv " ]
self . freq_table [ iden ] = { }
self . freq_table [ iden ] [ ' offset ' ] = toff * 250000
self . freq_table [ iden ] [ ' step ' ] = spac * 125
self . freq_table [ iden ] [ ' frequency ' ] = freq * 5
if self . debug > 10 :
print " tsbk3d iden id %d toff %f spac %f freq %f " % ( iden , toff * 0.25 , spac * 0.125 , freq * 0.000005 )
elif opcode == 0x3a : # rfss status
syid = ( tsbk >> 56 ) & 0xfff
rfid = ( tsbk >> 48 ) & 0xff
stid = ( tsbk >> 40 ) & 0xff
chan = ( tsbk >> 24 ) & 0xffff
f1 = self . channel_id_to_frequency ( chan )
if f1 :
self . rfss_syid = syid
self . rfss_rfid = rfid
self . rfss_stid = stid
self . rfss_chan = f1
self . rfss_txchan = f1 + self . freq_table [ chan >> 12 ] [ ' offset ' ]
if self . debug > 10 :
print " tsbk3a rfss status: syid: %x rfid %x stid %d ch1 %x ( %s ) " % ( syid , rfid , stid , chan , self . channel_id_to_string ( chan ) )
elif opcode == 0x39 : # secondary cc
rfid = ( tsbk >> 72 ) & 0xff
stid = ( tsbk >> 64 ) & 0xff
ch1 = ( tsbk >> 48 ) & 0xffff
ch2 = ( tsbk >> 24 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
f2 = self . channel_id_to_frequency ( ch2 )
if f1 and f2 :
self . secondary [ f1 ] = 1
self . secondary [ f2 ] = 1
if self . debug > 10 :
print " tsbk39 secondary cc: rfid %x stid %d ch1 %x ( %s ) ch2 %x ( %s ) " % ( rfid , stid , ch1 , self . channel_id_to_string ( ch1 ) , ch2 , self . channel_id_to_string ( ch2 ) )
elif opcode == 0x3b : # network status
wacn = ( tsbk >> 52 ) & 0xfffff
syid = ( tsbk >> 40 ) & 0xfff
ch1 = ( tsbk >> 24 ) & 0xffff
f1 = self . channel_id_to_frequency ( ch1 )
if f1 :
self . ns_syid = syid
self . ns_wacn = wacn
self . ns_chan = f1
if self . debug > 10 :
print " tsbk3b net stat: wacn %x syid %x ch1 %x ( %s ) " % ( wacn , syid , ch1 , self . channel_id_to_string ( ch1 ) )
elif opcode == 0x3c : # adjacent status
rfid = ( tsbk >> 48 ) & 0xff
stid = ( tsbk >> 40 ) & 0xff
ch1 = ( tsbk >> 24 ) & 0xffff
table = ( ch1 >> 12 ) & 0xf
f1 = self . channel_id_to_frequency ( ch1 )
if f1 and table in self . freq_table :
self . adjacent [ f1 ] = ' rfid: %d stid: %d uplink: %f tbl: %d ' % ( rfid , stid , ( f1 + self . freq_table [ table ] [ ' offset ' ] ) / 1000000.0 , table )
if self . debug > 10 :
print " tsbk3c adjacent: rfid %x stid %d ch1 %x ( %s ) " % ( rfid , stid , ch1 , self . channel_id_to_string ( ch1 ) )
if table in self . freq_table :
print " tsbk3c : %s %s " % ( self . freq_table [ table ] [ ' frequency ' ] , self . freq_table [ table ] [ ' step ' ] )
#else:
# print "tsbk other %x" % opcode
return updated
class rx_ctl ( object ) :
def __init__ ( self , debug = 0 , frequency_set = None , conf_file = None ) :
class _states ( object ) :
ACQ = 0
CC = 1
TO_VC = 2
VC = 3
self . states = _states
self . state = self . states . CC
self . trunked_systems = { }
self . frequency_set = frequency_set
self . debug = debug
self . tgid_hold = None
self . tgid_hold_until = time . time ( )
self . TGID_HOLD_TIME = 2.0 # TODO: make more configurable
self . current_nac = None
self . current_id = 0
self . TSYS_HOLD_TIME = 3.0 # TODO: make more configurable
self . wait_until = time . time ( )
self . configs = { }
if conf_file :
2014-01-03 01:31:26 +00:00
if conf_file . endswith ( ' .tsv ' ) :
self . build_config_tsv ( conf_file )
else :
self . build_config ( conf_file )
2013-12-10 00:47:21 +00:00
self . nacs = self . configs . keys ( )
self . current_nac = self . nacs [ 0 ]
self . current_state = self . states . CC
def set_frequency ( self , params ) :
frequency = params [ ' freq ' ]
if frequency and self . frequency_set :
self . frequency_set ( params )
def add_trunked_system ( self , nac ) :
assert nac not in self . trunked_systems # duplicate nac not allowed
blacklist = { }
whitelist = None
tgid_map = { }
cfg = None
if nac in self . configs :
cfg = self . configs [ nac ]
self . trunked_systems [ nac ] = trunked_system ( debug = self . debug , config = cfg )
2014-01-03 01:31:26 +00:00
def build_config_tsv ( self , tsv_filename ) :
import csv
hdrmap = [ ]
configs = { }
with open ( tsv_filename , ' rb ' ) as csvfile :
sreader = csv . reader ( csvfile , delimiter = ' \t ' , quotechar = ' " ' , quoting = csv . QUOTE_ALL )
for row in sreader :
if not hdrmap :
# process first line of tsv file - header line
for hdr in row :
hdr = hdr . replace ( ' ' , ' _ ' )
hdr = hdr . lower ( )
hdrmap . append ( hdr )
continue
fields = { }
for i in xrange ( len ( row ) ) :
if row [ i ] :
fields [ hdrmap [ i ] ] = row [ i ]
if hdrmap [ i ] != ' sysname ' :
fields [ hdrmap [ i ] ] = fields [ hdrmap [ i ] ] . lower ( )
nac = int ( fields [ ' nac ' ] , 0 )
configs [ nac ] = fields
self . setup_config ( configs )
2013-12-10 00:47:21 +00:00
def build_config ( self , config_filename ) :
import ConfigParser
config = ConfigParser . ConfigParser ( )
config . read ( config_filename )
configs = { }
for section in config . sections ( ) :
nac = int ( config . get ( section , ' nac ' ) , 0 ) # nac required
assert nac != 0 # nac=0 not allowed
assert nac not in configs # duplicate nac not allowed
configs [ nac ] = { }
for option in config . options ( section ) :
configs [ nac ] [ option ] = config . get ( section , option ) . lower ( )
configs [ nac ] [ ' sysname ' ] = section
2014-01-03 01:31:26 +00:00
self . setup_config ( configs )
2013-12-10 00:47:21 +00:00
2014-01-03 01:31:26 +00:00
def setup_config ( self , configs ) :
2013-12-10 00:47:21 +00:00
for nac in configs :
2014-02-07 02:54:59 +00:00
self . configs [ nac ] = { ' cclist ' : [ ] , ' offset ' : 0 , ' whitelist ' : None , ' blacklist ' : { } , ' tgid_map ' : { } , ' sysname ' : configs [ nac ] [ ' sysname ' ] , ' center_frequency ' : None }
2013-12-10 00:47:21 +00:00
for f in configs [ nac ] [ ' control_channel_list ' ] . split ( ' , ' ) :
2014-02-07 02:54:59 +00:00
self . configs [ nac ] [ ' cclist ' ] . append ( get_frequency ( f ) )
2013-12-10 00:47:21 +00:00
if ' offset ' in configs [ nac ] :
self . configs [ nac ] [ ' offset ' ] = int ( configs [ nac ] [ ' offset ' ] )
if ' modulation ' in configs [ nac ] :
self . configs [ nac ] [ ' modulation ' ] = configs [ nac ] [ ' modulation ' ]
else :
self . configs [ nac ] [ ' modulation ' ] = ' cqpsk '
if ' whitelist ' in configs [ nac ] :
self . configs [ nac ] [ ' whitelist ' ] = dict . fromkeys ( [ int ( d ) for d in configs [ nac ] [ ' whitelist ' ] . split ( ' , ' ) ] )
if ' blacklist ' in configs [ nac ] :
self . configs [ nac ] [ ' blacklist ' ] = dict . fromkeys ( [ int ( d ) for d in configs [ nac ] [ ' blacklist ' ] . split ( ' , ' ) ] )
if ' tgid_tags_file ' in configs [ nac ] :
import csv
with open ( configs [ nac ] [ ' tgid_tags_file ' ] , ' rb ' ) as csvfile :
sreader = csv . reader ( csvfile , delimiter = ' \t ' , quotechar = ' " ' , quoting = csv . QUOTE_ALL )
for row in sreader :
tgid = int ( row [ 0 ] )
txt = row [ 1 ]
self . configs [ nac ] [ ' tgid_map ' ] [ tgid ] = txt
2014-02-07 02:54:59 +00:00
if ' center_frequency ' in configs [ nac ] :
self . configs [ nac ] [ ' center_frequency ' ] = get_frequency ( configs [ nac ] [ ' center_frequency ' ] )
2013-12-10 00:47:21 +00:00
self . add_trunked_system ( nac )
def find_next_tsys ( self ) :
self . current_id + = 1
if self . current_id > = len ( self . nacs ) :
self . current_id = 0
return self . nacs [ self . current_id ]
def to_string ( self ) :
s = ' '
for nac in self . trunked_systems :
s + = ' \n ====== NAC 0x %x ====== %s ====== \n ' % ( nac , self . trunked_systems [ nac ] . sysname )
s + = self . trunked_systems [ nac ] . to_string ( )
return s
def process_qmsg ( self , msg ) :
type = msg . type ( )
updated = 0
curr_time = time . time ( )
if type == - 2 :
cmd = msg . to_string ( )
if self . debug > 10 :
print " process_qmsg: command: %s " % cmd
self . update_state ( cmd , curr_time )
return
elif type == - 1 :
print " process_data_unit timeout "
self . update_state ( ' timeout ' , curr_time )
return
s = msg . to_string ( )
# nac is always 1st two bytes
nac = ( ord ( s [ 0 ] ) << 8 ) + ord ( s [ 1 ] )
s = s [ 2 : ]
if self . debug > 10 :
print " nac %x type %d at %f state %d len %d " % ( nac , type , time . time ( ) , self . state , len ( s ) )
if ( type == 7 or type == 12 ) and nac not in self . trunked_systems :
if not self . configs :
# TODO: allow whitelist/blacklist rather than blind automatic-add
self . add_trunked_system ( nac )
else :
return
if type == 7 : # trunk: TSBK
t = 0
for c in s :
t = ( t << 8 ) + ord ( c )
updated + = self . trunked_systems [ nac ] . decode_tsbk ( t )
elif type == 12 : # trunk: MBT
s1 = s [ : 10 ]
s2 = s [ 10 : ]
header = mbt_data = 0
for c in s1 :
header = ( header << 8 ) + ord ( c )
for c in s2 :
mbt_data = ( mbt_data << 8 ) + ord ( c )
opcode = ( header >> 16 ) & 0x3f
if self . debug > 10 :
print " type %d at %f state %d len %d / %d opcode %x [ %x / %x ] " % ( type , time . time ( ) , self . state , len ( s1 ) , len ( s2 ) , opcode , header , mbt_data )
self . trunked_systems [ nac ] . decode_mbt_data ( opcode , header << 16 , mbt_data << 32 )
if nac != self . current_nac :
return
if updated :
self . update_state ( ' update ' , curr_time )
else :
self . update_state ( ' duid %d ' % type , curr_time )
def update_state ( self , command , curr_time ) :
if not self . configs :
return # run in "manual mode" if no conf
nac = self . current_nac
tsys = self . trunked_systems [ nac ]
new_frequency = None
new_tgid = None
new_state = None
new_nac = None
if command == ' timeout ' or command == ' duid15 ' :
if self . current_state != self . states . CC :
new_state = self . states . CC
new_frequency = tsys . trunk_cc
elif command == ' update ' :
if self . current_state == self . states . CC :
desired_tgid = None
if self . tgid_hold_until > curr_time :
desired_tgid = self . tgid_hold
new_frequency , new_tgid = tsys . find_voice_frequency ( curr_time , tgid = desired_tgid )
if new_frequency :
new_state = self . states . TO_VC
self . current_tgid = new_tgid
elif command == ' duid3 ' :
if self . current_state != self . states . CC :
new_state = self . states . CC
new_frequency = tsys . trunk_cc
elif command == ' duid0 ' or command == ' duid5 ' or command == ' duid10 ' :
if self . state == self . states . TO_VC :
new_state = self . states . VC
self . tgid_hold = self . current_tgid
self . tgid_hold_until = max ( curr_time + self . TGID_HOLD_TIME , self . tgid_hold_until )
self . wait_until = curr_time + self . TSYS_HOLD_TIME
elif command == ' duid7 ' or command == ' duid12 ' :
pass
elif command == ' set_hold ' :
if self . current_tgid :
self . tgid_hold = self . current_tgid
self . tgid_hold_until = curr_time + 86400 * 10000
print ' set hold until %f ' % self . tgid_hold_until
elif command == ' unset_hold ' :
if self . current_tgid :
self . current_tgid = None
self . tgid_hold = None
self . tgid_hold_until = curr_time
elif command == ' skip ' :
pass # TODO
elif command == ' lockout ' :
if self . current_tgid :
tsys . add_blacklist ( self . current_tgid )
self . current_tgid = None
self . tgid_hold = None
self . tgid_hold_until = curr_time
if self . current_state != self . states . CC :
new_state = self . states . CC
new_frequency = tsys . trunk_cc
else :
print ' update_state: unknown command: %s \n ' % command
assert 0 == 1
if self . wait_until < = curr_time and self . tgid_hold_until < = curr_time :
self . wait_until = curr_time + self . TSYS_HOLD_TIME
new_nac = self . find_next_tsys ( )
2014-02-07 23:25:04 +00:00
new_state = self . states . CC
2013-12-10 00:47:21 +00:00
if new_nac :
nac = self . current_nac = new_nac
tsys = self . trunked_systems [ nac ]
new_frequency = tsys . trunk_cc
self . current_tgid = None
if new_frequency :
2014-02-07 02:54:59 +00:00
self . set_frequency ( { ' freq ' : new_frequency , ' tgid ' : self . current_tgid , ' offset ' : tsys . offset , ' tag ' : tsys . get_tag ( self . current_tgid ) , ' nac ' : nac , ' system ' : tsys . sysname , ' center_frequency ' : tsys . center_frequency } )
2013-12-10 00:47:21 +00:00
if new_state :
self . current_state = new_state
def main ( ) :
q = 0x3a000012ae01013348704a54
rc = crc16 ( q , 12 )
print " should be zero: %x " % rc
assert rc == 0
q = 0x3a001012ae01013348704a54
rc = crc16 ( q , 12 )
print " should be nonzero: %x " % rc
assert rc != 0
t = trunked_system ( debug = 255 )
q = 0x3a000012ae0101334870
t . decode_tsbk ( q )
q = 0x02900031210020018e7c
t . decode_tsbk ( q )
if __name__ == ' __main__ ' :
main ( )