configuration additions
This commit is contained in:
parent
5ea5186c5d
commit
abf9b4f06c
|
@ -1,3 +1,4 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
# Copyright 2017, 2018 Max H. Parke KA1RBI
|
# Copyright 2017, 2018 Max H. Parke KA1RBI
|
||||||
#
|
#
|
||||||
|
@ -26,14 +27,20 @@ import json
|
||||||
import socket
|
import socket
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
import threading
|
||||||
|
import glob
|
||||||
|
|
||||||
from gnuradio import gr
|
from gnuradio import gr
|
||||||
from waitress.server import create_server
|
from waitress.server import create_server
|
||||||
|
from optparse import OptionParser
|
||||||
|
from multi_rx import byteify
|
||||||
|
from rx import p25_rx_block
|
||||||
|
|
||||||
my_input_q = None
|
my_input_q = None
|
||||||
my_output_q = None
|
my_output_q = None
|
||||||
my_recv_q = None
|
my_recv_q = None
|
||||||
my_port = None
|
my_port = None
|
||||||
|
my_backend = None
|
||||||
|
CFG_DIR = '../www/config/'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
fake http and ajax server module
|
fake http and ajax server module
|
||||||
|
@ -63,20 +70,70 @@ def static_file(environ, start_response):
|
||||||
status = '200 OK'
|
status = '200 OK'
|
||||||
return status, content_type, output
|
return status, content_type, output
|
||||||
|
|
||||||
|
def valid_tsv(filename):
|
||||||
|
if not os.access(filename, os.R_OK):
|
||||||
|
return False
|
||||||
|
line = open(filename).readline()
|
||||||
|
for word in 'Sysname Offset NAC Modulation TGID Whitelist Blacklist'.split():
|
||||||
|
if word not in line:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_request(d):
|
||||||
|
global my_backend
|
||||||
|
TSV_DIR = './'
|
||||||
|
if d['command'].startswith('rx-'):
|
||||||
|
msg = gr.message().make_from_string(json.dumps(d), -2, 0, 0)
|
||||||
|
if not my_backend.input_q.full_p():
|
||||||
|
my_backend.input_q.insert_tail(msg)
|
||||||
|
return None
|
||||||
|
elif d['command'] == 'config-load':
|
||||||
|
filename = '%s%s.json' % (CFG_DIR, d['data'])
|
||||||
|
if not os.access(filename, os.R_OK):
|
||||||
|
return
|
||||||
|
js_msg = json.loads(open(filename).read())
|
||||||
|
return {'json_type':'config_data', 'data': js_msg}
|
||||||
|
elif d['command'] == 'config-list':
|
||||||
|
files = glob.glob('%s*.json' % CFG_DIR)
|
||||||
|
files = [x.replace('.json', '') for x in files]
|
||||||
|
files = [x.replace(CFG_DIR, '') for x in files]
|
||||||
|
if d['data'] == 'tsv':
|
||||||
|
tsvfiles = glob.glob('%s*.tsv' % TSV_DIR)
|
||||||
|
tsvfiles = [x for x in tsvfiles if valid_tsv(x)]
|
||||||
|
tsvfiles = [x.replace('.tsv', '[TSV]') for x in tsvfiles]
|
||||||
|
tsvfiles = [x.replace(TSV_DIR, '') for x in tsvfiles]
|
||||||
|
files += tsvfiles
|
||||||
|
return {'json_type':'config_list', 'data': files}
|
||||||
|
elif d['command'] == 'config-save':
|
||||||
|
name = d['data']['name']
|
||||||
|
if '..' in name or '.json' in name or '/' in name:
|
||||||
|
return None
|
||||||
|
filename = '%s%s.json' % (CFG_DIR, d['data']['name'])
|
||||||
|
open(filename, 'w').write(json.dumps(d['data']['value'], indent=4, separators=[',',':'], sort_keys=True))
|
||||||
|
return None
|
||||||
|
|
||||||
def post_req(environ, start_response, postdata):
|
def post_req(environ, start_response, postdata):
|
||||||
global my_input_q, my_output_q, my_recv_q, my_port
|
global my_input_q, my_output_q, my_recv_q, my_port
|
||||||
|
resp_msg = []
|
||||||
try:
|
try:
|
||||||
data = json.loads(postdata)
|
data = json.loads(postdata)
|
||||||
for d in data:
|
|
||||||
msg = gr.message().make_from_string(str(d['command']), -2, d['data'], 0)
|
|
||||||
my_output_q.insert_tail(msg)
|
|
||||||
time.sleep(0.2)
|
|
||||||
except:
|
except:
|
||||||
sys.stderr.write('post_req: error processing input: %s:\n' % (postdata))
|
sys.stderr.write('post_req: error processing input: %s:\n' % (postdata))
|
||||||
traceback.print_exc(limit=None, file=sys.stderr)
|
traceback.print_exc(limit=None, file=sys.stderr)
|
||||||
sys.stderr.write('*** end traceback ***\n')
|
sys.stderr.write('*** end traceback ***\n')
|
||||||
|
for d in data:
|
||||||
|
if d['command'].startswith('config-') or d['command'].startswith('rx-'):
|
||||||
|
resp = do_request(d)
|
||||||
|
if resp:
|
||||||
|
resp_msg.append(resp)
|
||||||
|
continue
|
||||||
|
msg = gr.message().make_from_string(str(d['command']), -2, d['data'], 0)
|
||||||
|
if my_output_q.full_p():
|
||||||
|
my_output_q.delete_head_nowait() # ignores result
|
||||||
|
if not my_output_q.full_p():
|
||||||
|
my_output_q.insert_tail(msg)
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
resp_msg = []
|
|
||||||
while not my_recv_q.empty_p():
|
while not my_recv_q.empty_p():
|
||||||
msg = my_recv_q.delete_head()
|
msg = my_recv_q.delete_head()
|
||||||
if msg.type() == -4:
|
if msg.type() == -4:
|
||||||
|
@ -124,9 +181,12 @@ def process_qmsg(msg):
|
||||||
class http_server(object):
|
class http_server(object):
|
||||||
def __init__(self, input_q, output_q, endpoint, **kwds):
|
def __init__(self, input_q, output_q, endpoint, **kwds):
|
||||||
global my_input_q, my_output_q, my_recv_q, my_port
|
global my_input_q, my_output_q, my_recv_q, my_port
|
||||||
host, port = endpoint.split(':')
|
if endpoint == 'internal':
|
||||||
if my_port is not None:
|
return
|
||||||
raise AssertionError('this server is already active on port %s' % my_port)
|
else:
|
||||||
|
host, port = endpoint.split(':')
|
||||||
|
if my_port is not None:
|
||||||
|
raise AssertionError('this server is already active on port %s' % my_port)
|
||||||
my_input_q = input_q
|
my_input_q = input_q
|
||||||
my_output_q = output_q
|
my_output_q = output_q
|
||||||
my_port = int(port)
|
my_port = int(port)
|
||||||
|
@ -152,3 +212,85 @@ class queue_watcher(threading.Thread):
|
||||||
while(self.keep_running):
|
while(self.keep_running):
|
||||||
msg = self.msgq.delete_head()
|
msg = self.msgq.delete_head()
|
||||||
self.callback(msg)
|
self.callback(msg)
|
||||||
|
|
||||||
|
class Backend(threading.Thread):
|
||||||
|
def __init__(self, options, input_q, output_q, **kwds):
|
||||||
|
threading.Thread.__init__ (self, **kwds)
|
||||||
|
self.setDaemon(1)
|
||||||
|
self.keep_running = True
|
||||||
|
self.rx_options = None
|
||||||
|
self.input_q = input_q
|
||||||
|
self.output_q = output_q
|
||||||
|
self.verbosity = options.verbosity
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def process_msg(self, msg):
|
||||||
|
msg = json.loads(msg.to_string())
|
||||||
|
if msg['command'] == 'rx-start':
|
||||||
|
options = rx_options(msg['data'])
|
||||||
|
options.verbosity = self.verbosity
|
||||||
|
options._js_config['config-rx-data'] = {'input_q': self.input_q, 'output_q': self.output_q}
|
||||||
|
self.tb = p25_rx_block(options)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.keep_running:
|
||||||
|
msg = self.input_q.delete_head()
|
||||||
|
self.process_msg(msg)
|
||||||
|
|
||||||
|
class rx_options(object):
|
||||||
|
def __init__(self, name):
|
||||||
|
def map_name(k):
|
||||||
|
return k.replace('-', '_')
|
||||||
|
|
||||||
|
filename = '%s%s.json' % (CFG_DIR, name)
|
||||||
|
if not os.access(filename, os.R_OK):
|
||||||
|
return
|
||||||
|
config = byteify(json.loads(open(filename).read()))
|
||||||
|
dev = [x for x in config['devices'] if x['active']][0]
|
||||||
|
if not dev:
|
||||||
|
return
|
||||||
|
chan = [x for x in config['channels'] if x['active']][0]
|
||||||
|
if not chan:
|
||||||
|
return
|
||||||
|
options = object()
|
||||||
|
for k in config['backend-rx'].keys():
|
||||||
|
setattr(self, map_name(k), config['backend-rx'][k])
|
||||||
|
for k in 'args frequency gains offset'.split():
|
||||||
|
setattr(self, k, dev[k])
|
||||||
|
for k in 'demod_type filter_type'.split():
|
||||||
|
setattr(self, k, chan[k])
|
||||||
|
self.freq_corr = dev['ppm']
|
||||||
|
self.sample_rate = dev['rate']
|
||||||
|
self.plot_mode = chan['plot']
|
||||||
|
self.phase2_tdma = chan['phase2_tdma']
|
||||||
|
self.trunk_conf_file = None
|
||||||
|
self.terminal_type = None
|
||||||
|
self._js_config = config
|
||||||
|
|
||||||
|
def http_main():
|
||||||
|
global my_backend
|
||||||
|
# command line argument parsing
|
||||||
|
parser = OptionParser()
|
||||||
|
parser.add_option("-c", "--config-file", type="string", default=None, help="specify config file name")
|
||||||
|
parser.add_option("-e", "--endpoint", type="string", default="127.0.0.1:8080", help="address:port to listen on (use addr 0.0.0.0 to enable external clients)")
|
||||||
|
parser.add_option("-v", "--verbosity", type="int", default=0, help="message debug level")
|
||||||
|
parser.add_option("-p", "--pause", action="store_true", default=False, help="block on startup")
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
# wait for gdb
|
||||||
|
if options.pause:
|
||||||
|
print 'Ready for GDB to attach (pid = %d)' % (os.getpid(),)
|
||||||
|
raw_input("Press 'Enter' to continue...")
|
||||||
|
|
||||||
|
input_q = gr.msg_queue(20)
|
||||||
|
output_q = gr.msg_queue(20)
|
||||||
|
backend_input_q = gr.msg_queue(20)
|
||||||
|
backend_output_q = gr.msg_queue(20)
|
||||||
|
|
||||||
|
my_backend = Backend(options, backend_input_q, backend_output_q)
|
||||||
|
server = http_server(input_q, output_q, options.endpoint)
|
||||||
|
|
||||||
|
server.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
http_main()
|
||||||
|
|
Loading…
Reference in New Issue