aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <ikj1234i@yahoo.com>2018-03-16 16:26:42 -0400
committerMax <ikj1234i@yahoo.com>2018-03-16 16:26:42 -0400
commitabf9b4f06c95f864187c7a2f01141bfadfe46191 (patch)
tree551b47efe70b6b3be855f11f4cece6627ef505dc
parent5ea5186c5dcf02280848b5cba91fc37d39f8dcc4 (diff)
configuration additions
-rwxr-xr-x[-rw-r--r--]op25/gr-op25_repeater/apps/http.py158
1 files changed, 150 insertions, 8 deletions
diff --git a/op25/gr-op25_repeater/apps/http.py b/op25/gr-op25_repeater/apps/http.py
index 9196005..2af7e96 100644..100755
--- a/op25/gr-op25_repeater/apps/http.py
+++ b/op25/gr-op25_repeater/apps/http.py
@@ -1,3 +1,4 @@
+#! /usr/bin/env python
# Copyright 2017, 2018 Max H. Parke KA1RBI
#
@@ -26,14 +27,20 @@ import json
import socket
import traceback
import threading
+import glob
from gnuradio import gr
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_output_q = None
my_recv_q = None
my_port = None
+my_backend = None
+CFG_DIR = '../www/config/'
"""
fake http and ajax server module
@@ -63,20 +70,70 @@ def static_file(environ, start_response):
status = '200 OK'
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):
global my_input_q, my_output_q, my_recv_q, my_port
+ resp_msg = []
try:
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:
sys.stderr.write('post_req: error processing input: %s:\n' % (postdata))
traceback.print_exc(limit=None, file=sys.stderr)
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():
msg = my_recv_q.delete_head()
if msg.type() == -4:
@@ -124,9 +181,12 @@ def process_qmsg(msg):
class http_server(object):
def __init__(self, input_q, output_q, endpoint, **kwds):
global my_input_q, my_output_q, my_recv_q, my_port
- host, port = endpoint.split(':')
- if my_port is not None:
- raise AssertionError('this server is already active on port %s' % my_port)
+ if endpoint == 'internal':
+ return
+ 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_output_q = output_q
my_port = int(port)
@@ -152,3 +212,85 @@ class queue_watcher(threading.Thread):
while(self.keep_running):
msg = self.msgq.delete_head()
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()