Added S-meter

This commit is contained in:
ha7ilm 2016-03-20 16:06:10 +01:00
parent 06bd8b92aa
commit 34bd5cceab
5 changed files with 183 additions and 73 deletions

View File

@ -108,8 +108,13 @@
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutOneStep();" title="Zoom out one step"> <img src="gfx/openwebrx-zoom-out.png" /></div> <div class="openwebrx-button openwebrx-square-button" onclick="zoomOutOneStep();" title="Zoom out one step"> <img src="gfx/openwebrx-zoom-out.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInTotal();" title="Zoom in totally"><img src="gfx/openwebrx-zoom-in-total.png" /></div> <div class="openwebrx-button openwebrx-square-button" onclick="zoomInTotal();" title="Zoom in totally"><img src="gfx/openwebrx-zoom-in-total.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutTotal();" title="Zoom out totally"><img src="gfx/openwebrx-zoom-out-total.png" /></div> <div class="openwebrx-button openwebrx-square-button" onclick="zoomOutTotal();" title="Zoom out totally"><img src="gfx/openwebrx-zoom-out-total.png" /></div>
<div id="openwebrx-smeter-db">0 dB</div>
</div>
<div class="openwebrx-panel-line">
<div id="openwebrx-smeter-outer">
<div id="openwebrx-smeter-bar"></div>
</div>
</div> </div>
</div> </div>
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" data-panel-pos="left" data-panel-order="1" data-panel-size="619,142"> <div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" data-panel-pos="left" data-panel-order="1" data-panel-size="619,142">

View File

@ -36,7 +36,7 @@ input
input[type=range] input[type=range]
{ {
-webkit-appearance: none; -webkit-appearance: none;
margin: 10px 0; margin: 0 0;
} }
input[type=range]:focus input[type=range]:focus
{ {
@ -745,3 +745,36 @@ img.openwebrx-mirror-img
{ {
padding-top: 5px; padding-top: 5px;
} }
#openwebrx-smeter-outer
{
border-color: #888;
border-style: solid;
border-width: 0px;
width: 255px;
height: 7px;
background-color: #373737;
border-radius: 3px;
position: relative;
}
#openwebrx-smeter-bar
{
transition: all 0.2s linear;
width: 0px;
height: 7px;
background: linear-gradient(to top, #ff5939 , #961700);
position: absolute;
margin: 0; padding: 0; left: 0;
border-radius: 3px;
}
#openwebrx-smeter-db
{
color: #aaa;
display: inline-block;
font-size: 10pt;
float: right;
margin-right: 5px;
margin-top: 29px;
font-family: 'expletus-sans-medium';
}

View File

@ -178,6 +178,36 @@ function waterfallColorsAuto()
updateWaterfallColors(0); updateWaterfallColors(0);
} }
function setSmeterRelativeValue(value)
{
if(value<0) value=0;
if(value>1.0) value=1.0;
var bar=e("openwebrx-smeter-bar");
var outer=e("openwebrx-smeter-outer");
bar.style.width=(outer.offsetWidth*value).toString()+"px";
bgRed="linear-gradient(to top, #ff5939 , #961700)";
bgGreen="linear-gradient(to top, #22ff2f , #008908)";
bgYellow="linear-gradient(to top, #fff720 , #a49f00)";
bar.style.background=(value>0.9)?bgRed:((value>0.7)?bgYellow:bgGreen);
//bar.style.backgroundColor=(value>0.9)?"#ff5939":((value>0.7)?"#fff720":"#22ff2f");
}
function getLogSmeterValue(value)
{
return 10*Math.log10(value);
}
function setSmeterAbsoluteValue(value) //the value that comes from `csdr squelch_and_smeter_cc`
{
var logValue=getLogSmeterValue(value);
var lowLevel=waterfall_min_level-20;
var highLevel=waterfall_max_level+20;
var percent=(logValue-lowLevel)/(highLevel-lowLevel);
setSmeterRelativeValue(percent);
e("openwebrx-smeter-db").innerHTML=logValue.toFixed(1)+" dB";
}
// ======================================================== // ========================================================
// ================= ANIMATION ROUTINES ================= // ================= ANIMATION ROUTINES =================
// ======================================================== // ========================================================
@ -1145,6 +1175,10 @@ function on_ws_recv(evt)
case "max_clients": case "max_clients":
max_clients_num=parseInt(param[1]); max_clients_num=parseInt(param[1]);
break; break;
case "s":
smeter_level=parseFloat(param[1]);
setSmeterAbsoluteValue(smeter_level);
break;
} }
} }
/*} /*}

View File

@ -2,7 +2,7 @@
print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py
""" """
This file is part of OpenWebRX, This file is part of OpenWebRX,
an open-source SDR receiver software with a web UI. an open-source SDR receiver software with a web UI.
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu> Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
@ -31,7 +31,7 @@ import thread
import time import time
import datetime import datetime
import subprocess import subprocess
import os import os
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn from SocketServer import ThreadingMixIn
import fcntl import fcntl
@ -72,7 +72,7 @@ def import_all_plugins(directory):
importlib.import_module(importname) importlib.import_module(importname)
class MultiThreadHTTPServer(ThreadingMixIn, HTTPServer): class MultiThreadHTTPServer(ThreadingMixIn, HTTPServer):
pass pass
def handle_signal(signal, frame): def handle_signal(signal, frame):
global spectrum_dsp global spectrum_dsp
@ -94,19 +94,19 @@ def main():
print print
print "OpenWebRX - Open Source SDR Web App for Everyone! | for license see LICENSE file in the package" print "OpenWebRX - Open Source SDR Web App for Everyone! | for license see LICENSE file in the package"
print "_________________________________________________________________________________________________" print "_________________________________________________________________________________________________"
print print
print "Author contact info: Andras Retzler, HA7ILM <randras@sdr.hu>" print "Author contact info: Andras Retzler, HA7ILM <randras@sdr.hu>"
print print
no_arguments=len(sys.argv)==1 no_arguments=len(sys.argv)==1
if no_arguments: print "[openwebrx-main] Configuration script not specified. I will use: \"config_webrx.py\"" if no_arguments: print "[openwebrx-main] Configuration script not specified. I will use: \"config_webrx.py\""
cfg=__import__("config_webrx" if no_arguments else sys.argv[1]) cfg=__import__("config_webrx" if no_arguments else sys.argv[1])
for option in ("access_log","csdr_dynamic_bufsize","csdr_print_bufsizes","csdr_through"): for option in ("access_log","csdr_dynamic_bufsize","csdr_print_bufsizes","csdr_through"):
if not option in dir(cfg): setattr(cfg, option, False) #initialize optional config parameters if not option in dir(cfg): setattr(cfg, option, False) #initialize optional config parameters
#Open log files #Open log files
logs = type("logs_class", (object,), {"access_log":open(cfg.access_log if cfg.access_log else "/dev/null","a"), "error_log":""})() logs = type("logs_class", (object,), {"access_log":open(cfg.access_log if cfg.access_log else "/dev/null","a"), "error_log":""})()
#Set signal handler #Set signal handler
signal.signal(signal.SIGINT, handle_signal) #http://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python signal.signal(signal.SIGINT, handle_signal) #http://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python
@ -129,7 +129,7 @@ def main():
#Start rtl thread #Start rtl thread
if os.system("ncat --version > /dev/null") == 32512: #check for ncat if os.system("ncat --version > /dev/null") == 32512: #check for ncat
print "[openwebrx-main] Error: ncat not detected, please install it! The ncat tool is a netcat alternative, used for distributing the I/Q data stream. It is usually available in the nmap package (sudo apt-get install nmap). For more explanation, look into the README.md" print "[openwebrx-main] Error: ncat not detected, please install it! The ncat tool is a netcat alternative, used for distributing the I/Q data stream. It is usually available in the nmap package (sudo apt-get install nmap). For more explanation, look into the README.md"
return return
if cfg.start_rtl_thread: if cfg.start_rtl_thread:
cfg.start_rtl_command += "| ncat -4l %d -k --send-only --allow 127.0.0.1" % cfg.iq_server_port cfg.start_rtl_command += "| ncat -4l %d -k --send-only --allow 127.0.0.1" % cfg.iq_server_port
rtl_thread=threading.Thread(target = lambda:subprocess.Popen(cfg.start_rtl_command, shell=True), args=()) rtl_thread=threading.Thread(target = lambda:subprocess.Popen(cfg.start_rtl_command, shell=True), args=())
@ -144,7 +144,7 @@ def main():
continue continue
testsock.close() testsock.close()
break break
print "[openwebrx-main] I/Q server started." print "[openwebrx-main] I/Q server started."
#Initialize clients #Initialize clients
clients=[] clients=[]
@ -157,7 +157,7 @@ def main():
mutex_test_thread.start() mutex_test_thread.start()
mutex_watchdog_thread=threading.Thread(target = mutex_watchdog_thread_function, args = ()) mutex_watchdog_thread=threading.Thread(target = mutex_watchdog_thread_function, args = ())
mutex_watchdog_thread.start() mutex_watchdog_thread.start()
#Start spectrum thread #Start spectrum thread
print "[openwebrx-main] Starting spectrum thread." print "[openwebrx-main] Starting spectrum thread."
@ -169,16 +169,16 @@ def main():
get_cpu_usage() get_cpu_usage()
bcastmsg_thread=threading.Thread(target = bcastmsg_thread_function, args = ()) bcastmsg_thread=threading.Thread(target = bcastmsg_thread_function, args = ())
bcastmsg_thread.start() bcastmsg_thread.start()
#threading.Thread(target = measure_thread_function, args = ()).start() #threading.Thread(target = measure_thread_function, args = ()).start()
#Start sdr.hu update thread #Start sdr.hu update thread
if sdrhu and cfg.sdrhu_key and cfg.sdrhu_public_listing: if sdrhu and cfg.sdrhu_key and cfg.sdrhu_public_listing:
print "[openwebrx-main] Starting sdr.hu update thread..." print "[openwebrx-main] Starting sdr.hu update thread..."
avatar_ctime=str(os.path.getctime("htdocs/gfx/openwebrx-avatar.png")) avatar_ctime=str(os.path.getctime("htdocs/gfx/openwebrx-avatar.png"))
sdrhu_thread=threading.Thread(target = sdrhu.run, args = ()) sdrhu_thread=threading.Thread(target = sdrhu.run, args = ())
sdrhu_thread.start() sdrhu_thread.start()
#Start HTTP thread #Start HTTP thread
httpd = MultiThreadHTTPServer(('', cfg.web_port), WebRXHandler) httpd = MultiThreadHTTPServer(('', cfg.web_port), WebRXHandler)
print('[openwebrx-main] Starting HTTP server.') print('[openwebrx-main] Starting HTTP server.')
@ -190,7 +190,7 @@ def main():
measure_value=0 measure_value=0
def measure_thread_function(): def measure_thread_function():
global measure_value global measure_value
while True: while True:
print "[openwebrx-measure] value is",measure_value print "[openwebrx-measure] value is",measure_value
measure_value=0 measure_value=0
time.sleep(1) time.sleep(1)
@ -232,17 +232,17 @@ def mutex_watchdog_thread_function():
global clients_mutex_locker global clients_mutex_locker
global clients_mutex global clients_mutex
while True: while True:
if lock_try_time != 0 and time.time()-lock_try_time > 3.0: if lock_try_time != 0 and time.time()-lock_try_time > 3.0:
#if 3 seconds pass without unlock #if 3 seconds pass without unlock
print "[openwebrx-mutex-watchdog] Mutex unlock timeout. Locker: \""+str(clients_mutex_locker)+"\" Now unlocking..." print "[openwebrx-mutex-watchdog] Mutex unlock timeout. Locker: \""+str(clients_mutex_locker)+"\" Now unlocking..."
clients_mutex.release() clients_mutex.release()
time.sleep(0.5) time.sleep(0.5)
def spectrum_watchdog_thread_function(): def spectrum_watchdog_thread_function():
global spectrum_thread_watchdog_last_tick, receiver_failed global spectrum_thread_watchdog_last_tick, receiver_failed
while True: while True:
time.sleep(60) time.sleep(60)
if spectrum_thread_watchdog_last_tick and time.time()-spectrum_thread_watchdog_last_tick > 60.0: if spectrum_thread_watchdog_last_tick and time.time()-spectrum_thread_watchdog_last_tick > 60.0:
print "[openwebrx-spectrum-watchdog] Spectrum timeout. Seems like no I/Q data is coming from the receiver.\nIf you're using RTL-SDR, the receiver hardware may randomly fail under some circumstances:\n1) high temperature,\n2) insufficient current available from the USB port." print "[openwebrx-spectrum-watchdog] Spectrum timeout. Seems like no I/Q data is coming from the receiver.\nIf you're using RTL-SDR, the receiver hardware may randomly fail under some circumstances:\n1) high temperature,\n2) insufficient current available from the USB port."
print "[openwebrx-spectrum-watchdog] Deactivating receiver." print "[openwebrx-spectrum-watchdog] Deactivating receiver."
receiver_failed="spectrum" receiver_failed="spectrum"
@ -250,7 +250,7 @@ def spectrum_watchdog_thread_function():
def check_server(): def check_server():
global spectrum_dsp, server_fail, rtl_thread global spectrum_dsp, server_fail, rtl_thread
if server_fail: return server_fail if server_fail: return server_fail
#print spectrum_dsp.process.poll() #print spectrum_dsp.process.poll()
if spectrum_dsp and spectrum_dsp.process.poll()!=None: server_fail = "spectrum_thread dsp subprocess failed" if spectrum_dsp and spectrum_dsp.process.poll()!=None: server_fail = "spectrum_thread dsp subprocess failed"
#if rtl_thread and not rtl_thread.is_alive(): server_fail = "rtl_thread failed" #if rtl_thread and not rtl_thread.is_alive(): server_fail = "rtl_thread failed"
@ -260,7 +260,7 @@ def check_server():
def apply_csdr_cfg_to_dsp(dsp): def apply_csdr_cfg_to_dsp(dsp):
dsp.csdr_dynamic_bufsize = cfg.csdr_dynamic_bufsize dsp.csdr_dynamic_bufsize = cfg.csdr_dynamic_bufsize
dsp.csdr_print_bufsizes = cfg.csdr_print_bufsizes dsp.csdr_print_bufsizes = cfg.csdr_print_bufsizes
dsp.csdr_through = cfg.csdr_through dsp.csdr_through = cfg.csdr_through
def spectrum_thread_function(): def spectrum_thread_function():
global clients, spectrum_dsp, spectrum_thread_watchdog_last_tick global clients, spectrum_dsp, spectrum_thread_watchdog_last_tick
@ -276,16 +276,16 @@ def spectrum_thread_function():
sleep_sec=0.87/cfg.fft_fps sleep_sec=0.87/cfg.fft_fps
print "[openwebrx-spectrum] Spectrum thread initialized successfully." print "[openwebrx-spectrum] Spectrum thread initialized successfully."
dsp.start() dsp.start()
if cfg.csdr_dynamic_bufsize: if cfg.csdr_dynamic_bufsize:
dsp.read(8) #dummy read to skip bufsize & preamble dsp.read(8) #dummy read to skip bufsize & preamble
print "[openwebrx-spectrum] Note: CSDR_DYNAMIC_BUFSIZE_ON = 1" print "[openwebrx-spectrum] Note: CSDR_DYNAMIC_BUFSIZE_ON = 1"
print "[openwebrx-spectrum] Spectrum thread started." print "[openwebrx-spectrum] Spectrum thread started."
bytes_to_read=int(dsp.get_fft_bytes_to_read()) bytes_to_read=int(dsp.get_fft_bytes_to_read())
spectrum_thread_counter=0 spectrum_thread_counter=0
while True: while True:
data=dsp.read(bytes_to_read) data=dsp.read(bytes_to_read)
#print "gotcha",len(data),"bytes of spectrum data via spectrum_thread_function()" #print "gotcha",len(data),"bytes of spectrum data via spectrum_thread_function()"
if spectrum_thread_counter >= cfg.fft_fps: if spectrum_thread_counter >= cfg.fft_fps:
spectrum_thread_counter=0 spectrum_thread_counter=0
spectrum_thread_watchdog_last_tick = time.time() #once every second spectrum_thread_watchdog_last_tick = time.time() #once every second
else: spectrum_thread_counter+=1 else: spectrum_thread_counter+=1
@ -301,7 +301,7 @@ def spectrum_thread_function():
else: else:
clients[i].spectrum_queue.put([data]) # add new string by "reference" to all clients clients[i].spectrum_queue.put([data]) # add new string by "reference" to all clients
cmr() cmr()
def get_client_by_id(client_id, use_mutex=True): def get_client_by_id(client_id, use_mutex=True):
global clients global clients
output=-1 output=-1
@ -337,7 +337,7 @@ def cleanup_clients(end_all=False):
def generate_client_id(ip): def generate_client_id(ip):
#add a client #add a client
global clients global clients
new_client=namedtuple("ClientStruct", "id gen_time ws_started sprectum_queue ip closed bcastmsg dsp") new_client=namedtuple("ClientStruct", "id gen_time ws_started sprectum_queue ip closed bcastmsg dsp")
new_client.id=md5.md5(str(random.random())).hexdigest() new_client.id=md5.md5(str(random.random())).hexdigest()
new_client.gen_time=time.time() new_client.gen_time=time.time()
new_client.ws_started=False # to check whether client has ever tried to open the websocket new_client.ws_started=False # to check whether client has ever tried to open the websocket
@ -371,7 +371,7 @@ def close_client(i, use_mutex=True):
# http://www.codeproject.com/Articles/462525/Simple-HTTP-Server-and-Client-in-Python # http://www.codeproject.com/Articles/462525/Simple-HTTP-Server-and-Client-in-Python
# some ideas are used from the artice above # some ideas are used from the artice above
class WebRXHandler(BaseHTTPRequestHandler): class WebRXHandler(BaseHTTPRequestHandler):
def proc_read_thread(): def proc_read_thread():
pass pass
@ -386,11 +386,11 @@ class WebRXHandler(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
global dsp_plugin, clients_mutex, clients, avatar_ctime, sw_version, receiver_failed global dsp_plugin, clients_mutex, clients, avatar_ctime, sw_version, receiver_failed
rootdir = 'htdocs' rootdir = 'htdocs'
self.path=self.path.replace("..","") self.path=self.path.replace("..","")
path_temp_parts=self.path.split("?") path_temp_parts=self.path.split("?")
self.path=path_temp_parts[0] self.path=path_temp_parts[0]
request_param=path_temp_parts[1] if(len(path_temp_parts)>1) else "" request_param=path_temp_parts[1] if(len(path_temp_parts)>1) else ""
access_log("GET "+self.path+" from "+self.client_address[0]) access_log("GET "+self.path+" from "+self.client_address[0])
try: try:
if self.path=="/": if self.path=="/":
@ -402,9 +402,9 @@ class WebRXHandler(BaseHTTPRequestHandler):
try: try:
# ========= WebSocket handshake ========= # ========= WebSocket handshake =========
ws_success=True ws_success=True
try: try:
rxws.handshake(self) rxws.handshake(self)
cma("do_GET /ws/") cma("do_GET /ws/")
client_i=get_client_by_id(self.path[4:], False) client_i=get_client_by_id(self.path[4:], False)
myclient=clients[client_i] myclient=clients[client_i]
except rxws.WebSocketException: ws_success=False except rxws.WebSocketException: ws_success=False
@ -439,11 +439,11 @@ class WebRXHandler(BaseHTTPRequestHandler):
dsp.nc_port=cfg.iq_server_port dsp.nc_port=cfg.iq_server_port
apply_csdr_cfg_to_dsp(dsp) apply_csdr_cfg_to_dsp(dsp)
myclient.dsp=dsp myclient.dsp=dsp
access_log("Started streaming to client: "+self.client_address[0]+"#"+myclient.id+" (users now: "+str(len(clients))+")") access_log("Started streaming to client: "+self.client_address[0]+"#"+myclient.id+" (users now: "+str(len(clients))+")")
while True: while True:
if myclient.closed[0]: if myclient.closed[0]:
print "[openwebrx-httpd:ws] client closed by other thread" print "[openwebrx-httpd:ws] client closed by other thread"
break break
@ -456,10 +456,20 @@ class WebRXHandler(BaseHTTPRequestHandler):
while not myclient.spectrum_queue.empty(): while not myclient.spectrum_queue.empty():
spectrum_data=myclient.spectrum_queue.get() spectrum_data=myclient.spectrum_queue.get()
#spectrum_data_mid=len(spectrum_data[0])/2 #spectrum_data_mid=len(spectrum_data[0])/2
#rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ") #rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ")
# (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it) # (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it)
rxws.send(self, spectrum_data[0],"FFT ") rxws.send(self, spectrum_data[0],"FFT ")
# ========= send smeter_level =========
smeter_level=None
while True:
try:
smeter_level=dsp.get_smeter_level()
if smeter_level == None: break
except:
break
if smeter_level!=None: rxws.send(self, "MSG s={0}".format(smeter_level))
# ========= send bcastmsg ========= # ========= send bcastmsg =========
if myclient.bcastmsg!="": if myclient.bcastmsg!="":
rxws.send(self,myclient.bcastmsg) rxws.send(self,myclient.bcastmsg)
@ -486,17 +496,19 @@ class WebRXHandler(BaseHTTPRequestHandler):
new_bpf[1]=int(param_value) new_bpf[1]=int(param_value)
elif param_name == "offset_freq" and -cfg.samp_rate/2 <= float(param_value) <= cfg.samp_rate/2: elif param_name == "offset_freq" and -cfg.samp_rate/2 <= float(param_value) <= cfg.samp_rate/2:
dsp.set_offset_freq(int(param_value)) dsp.set_offset_freq(int(param_value))
elif param_name == "squelch_level" and float(param_value) >= 0:
dsp.set_squelch_level(float(param_value))
elif param_name=="mod": elif param_name=="mod":
if (dsp.get_demodulator()!=param_value): if (dsp.get_demodulator()!=param_value):
if dsp_initialized: dsp.stop() if dsp_initialized: dsp.stop()
dsp.set_demodulator(param_value) dsp.set_demodulator(param_value)
if dsp_initialized: dsp.start() if dsp_initialized: dsp.start()
elif param_name == "output_rate": elif param_name == "output_rate":
if not dsp_initialized: if not dsp_initialized:
dsp.set_output_rate(int(param_value)) dsp.set_output_rate(int(param_value))
dsp.set_samp_rate(cfg.samp_rate) dsp.set_samp_rate(cfg.samp_rate)
elif param_name=="action" and param_value=="start": elif param_name=="action" and param_value=="start":
if not dsp_initialized: if not dsp_initialized:
dsp.start() dsp.start()
dsp_initialized=True dsp_initialized=True
else: else:
@ -508,13 +520,13 @@ class WebRXHandler(BaseHTTPRequestHandler):
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
if exc_value[0]==32: #"broken pipe", client disconnected if exc_value[0]==32: #"broken pipe", client disconnected
pass pass
elif exc_value[0]==11: #"resource unavailable" on recv, client disconnected elif exc_value[0]==11: #"resource unavailable" on recv, client disconnected
pass pass
else: else:
print "[openwebrx-httpd] error in /ws/ handler: ",exc_type,exc_value print "[openwebrx-httpd] error in /ws/ handler: ",exc_type,exc_value
traceback.print_tb(exc_traceback) traceback.print_tb(exc_traceback)
#stop dsp for the disconnected client #stop dsp for the disconnected client
try: try:
dsp.stop() dsp.stop()
del dsp del dsp
@ -537,7 +549,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
#self.send_header('Content-type','text/plain') #self.send_header('Content-type','text/plain')
getbands=lambda: str(int(cfg.shown_center_freq-cfg.samp_rate/2))+"-"+str(int(cfg.shown_center_freq+cfg.samp_rate/2)) getbands=lambda: str(int(cfg.shown_center_freq-cfg.samp_rate/2))+"-"+str(int(cfg.shown_center_freq+cfg.samp_rate/2))
self.wfile.write("status="+("inactive" if receiver_failed else "active")+"\nname="+cfg.receiver_name+"\nsdr_hw="+cfg.receiver_device+"\nop_email="+cfg.receiver_admin+"\nbands="+getbands()+"\nusers="+str(len(clients))+"\nusers_max="+str(cfg.max_clients)+"\navatar_ctime="+avatar_ctime+"\ngps="+str(cfg.receiver_gps)+"\nasl="+str(cfg.receiver_asl)+"\nloc="+cfg.receiver_location+"\nsw_version="+sw_version+"\nantenna="+cfg.receiver_ant+"\n") self.wfile.write("status="+("inactive" if receiver_failed else "active")+"\nname="+cfg.receiver_name+"\nsdr_hw="+cfg.receiver_device+"\nop_email="+cfg.receiver_admin+"\nbands="+getbands()+"\nusers="+str(len(clients))+"\nusers_max="+str(cfg.max_clients)+"\navatar_ctime="+avatar_ctime+"\ngps="+str(cfg.receiver_gps)+"\nasl="+str(cfg.receiver_asl)+"\nloc="+cfg.receiver_location+"\nsw_version="+sw_version+"\nantenna="+cfg.receiver_ant+"\n")
print "[openwebrx-httpd] GET /status/ from",self.client_address[0] print "[openwebrx-httpd] GET /status/ from",self.client_address[0]
else: else:
f=open(rootdir+self.path) f=open(rootdir+self.path)
data=f.read() data=f.read()
@ -560,7 +572,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
self.send_header('Content-type','text/javascript') self.send_header('Content-type','text/javascript')
elif(extension=="css"): elif(extension=="css"):
self.send_header('Content-type','text/css') self.send_header('Content-type','text/css')
self.end_headers() self.end_headers()
if extension == "wrx": if extension == "wrx":
replace_dictionary=( replace_dictionary=(
("%[RX_PHOTO_DESC]",cfg.photo_desc), ("%[RX_PHOTO_DESC]",cfg.photo_desc),
@ -594,7 +606,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
print "[openwebrx-httpd] error (@outside):", exc_type, exc_value print "[openwebrx-httpd] error (@outside):", exc_type, exc_value
traceback.print_tb(exc_traceback) traceback.print_tb(exc_traceback)
class ClientNotFoundException(Exception): class ClientNotFoundException(Exception):
pass pass
@ -622,4 +634,3 @@ def get_cpu_usage():
if __name__=="__main__": if __name__=="__main__":
main() main()

View File

@ -1,7 +1,7 @@
""" """
OpenWebRX csdr plugin: do the signal processing with csdr OpenWebRX csdr plugin: do the signal processing with csdr
This file is part of OpenWebRX, This file is part of OpenWebRX,
an open-source SDR receiver software with a web UI. an open-source SDR receiver software with a web UI.
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu> Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
@ -25,6 +25,7 @@ import time
import os import os
import code import code
import signal import signal
import fcntl
class dsp_plugin: class dsp_plugin:
@ -49,20 +50,21 @@ class dsp_plugin:
self.csdr_dynamic_bufsize = False self.csdr_dynamic_bufsize = False
self.csdr_print_bufsizes = False self.csdr_print_bufsizes = False
self.csdr_through = False self.csdr_through = False
self.squelch_level = 0
def chain(self,which): def chain(self,which):
any_chain_base="ncat -v 127.0.0.1 {nc_port} | " any_chain_base="ncat -v 127.0.0.1 {nc_port} | "
if self.csdr_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | " if self.csdr_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | "
if self.csdr_through: any_chain_base+="csdr through | " if self.csdr_through: any_chain_base+="csdr through | "
any_chain_base+=self.format_conversion+(" | " if self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | " any_chain_base+=self.format_conversion+(" | " if self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | "
if which == "fft": if which == "fft":
fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | csdr logpower_cf -70 | csdr fft_exchange_sides_ff {fft_size}" fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | csdr logpower_cf -70 | csdr fft_exchange_sides_ff {fft_size}"
if self.fft_compression=="adpcm": if self.fft_compression=="adpcm":
return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}" return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}"
else: else:
return fft_chain_base return fft_chain_base
chain_begin=any_chain_base+"csdr shift_addition_cc --fifo {shift_pipe} | csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING | csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING | " chain_begin=any_chain_base+"csdr shift_addition_cc --fifo {shift_pipe} | csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING | csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING | csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 1 | "
chain_end = "" chain_end = ""
if self.audio_compression=="adpcm": if self.audio_compression=="adpcm":
chain_end = " | csdr encode_ima_adpcm_i16_u8" chain_end = " | csdr encode_ima_adpcm_i16_u8"
if which == "nfm": return chain_begin + "csdr fmdemod_quadri_cf | csdr limit_ff | csdr fractional_decimator_ff {last_decimation} | csdr deemphasis_nfm_ff 11025 | csdr fastagc_ff 1024 | csdr convert_f_i16"+chain_end if which == "nfm": return chain_begin + "csdr fmdemod_quadri_cf | csdr limit_ff | csdr fractional_decimator_ff {last_decimation} | csdr deemphasis_nfm_ff 11025 | csdr fastagc_ff 1024 | csdr convert_f_i16"+chain_end
@ -92,7 +94,7 @@ class dsp_plugin:
def get_name(self): def get_name(self):
return self.name return self.name
def get_output_rate(self): def get_output_rate(self):
return self.output_rate return self.output_rate
@ -114,7 +116,7 @@ class dsp_plugin:
def set_fft_fps(self,fft_fps): def set_fft_fps(self,fft_fps):
#to change this, restart is required #to change this, restart is required
self.fft_fps=fft_fps self.fft_fps=fft_fps
def fft_block_size(self): def fft_block_size(self):
return self.samp_rate/self.fft_fps return self.samp_rate/self.fft_fps
@ -123,48 +125,66 @@ class dsp_plugin:
def set_offset_freq(self,offset_freq): def set_offset_freq(self,offset_freq):
self.offset_freq=offset_freq self.offset_freq=offset_freq
if self.running: if self.running:
self.shift_pipe_file.write("%g\n"%(-float(self.offset_freq)/self.samp_rate)) self.shift_pipe_file.write("%g\n"%(-float(self.offset_freq)/self.samp_rate))
self.shift_pipe_file.flush() self.shift_pipe_file.flush()
def set_bpf(self,low_cut,high_cut): def set_bpf(self,low_cut,high_cut):
self.low_cut=low_cut self.low_cut=low_cut
self.high_cut=high_cut self.high_cut=high_cut
if self.running: if self.running:
self.bpf_pipe_file.write( "%g %g\n"%(float(self.low_cut)/self.if_samp_rate(), float(self.high_cut)/self.if_samp_rate()) ) self.bpf_pipe_file.write( "%g %g\n"%(float(self.low_cut)/self.if_samp_rate(), float(self.high_cut)/self.if_samp_rate()) )
self.bpf_pipe_file.flush() self.bpf_pipe_file.flush()
def get_bpf(self): def get_bpf(self):
return [self.low_cut, self.high_cut] return [self.low_cut, self.high_cut]
def set_squelch_level(self, squelch_level):
self.squelch_level=squelch_level
if self.running:
self.squelch_pipe_file.write( "%g\n"%(float(self.squelch_level)) )
self.squelch_pipe_file.flush()
def get_smeter_level(self):
if self.running:
line=self.smeter_pipe_file.readline()
return float(line[:-1])
def mkfifo(self,path): def mkfifo(self,path):
try: try:
os.unlink(path) os.unlink(path)
except: except:
pass pass
os.mkfifo(path) os.mkfifo(path)
def ddc_transition_bw(self): def ddc_transition_bw(self):
return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate)) return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate))
def start(self): def start(self):
command_base=self.chain(self.demodulator) command_base=self.chain(self.demodulator)
#create control pipes for csdr #create control pipes for csdr
pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self)) pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self))
self.bpf_pipe = self.shift_pipe = None self.bpf_pipe = self.shift_pipe = self.squelch_pipe = self.smeter_pipe = None
if "{bpf_pipe}" in command_base: if "{bpf_pipe}" in command_base:
self.bpf_pipe=pipe_base_path+"bpf" self.bpf_pipe=pipe_base_path+"bpf"
self.mkfifo(self.bpf_pipe) self.mkfifo(self.bpf_pipe)
if "{shift_pipe}" in command_base: if "{shift_pipe}" in command_base:
self.shift_pipe=pipe_base_path+"shift" self.shift_pipe=pipe_base_path+"shift"
self.mkfifo(self.shift_pipe) self.mkfifo(self.shift_pipe)
if "{squelch_pipe}" in command_base:
self.squelch_pipe=pipe_base_path+"squelch"
self.mkfifo(self.squelch_pipe)
if "{smeter_pipe}" in command_base:
self.smeter_pipe=pipe_base_path+"smeter"
self.mkfifo(self.smeter_pipe)
#run the command #run the command
command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \ command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \
last_decimation=self.last_decimation, fft_size=self.fft_size, fft_block_size=self.fft_block_size(), \ last_decimation=self.last_decimation, fft_size=self.fft_size, fft_block_size=self.fft_block_size(), \
bpf_transition_bw=float(self.bpf_transition_bw)/self.if_samp_rate(), ddc_transition_bw=self.ddc_transition_bw(), \ bpf_transition_bw=float(self.bpf_transition_bw)/self.if_samp_rate(), ddc_transition_bw=self.ddc_transition_bw(), \
flowcontrol=int(self.samp_rate*2), start_bufsize=self.base_bufsize*self.decimation, nc_port=self.nc_port) flowcontrol=int(self.samp_rate*2), start_bufsize=self.base_bufsize*self.decimation, nc_port=self.nc_port, \
squelch_pipe=self.squelch_pipe, smeter_pipe=self.smeter_pipe )
print "[openwebrx-dsp-plugin:csdr] Command =",command print "[openwebrx-dsp-plugin:csdr] Command =",command
#code.interact(local=locals()) #code.interact(local=locals())
@ -175,35 +195,43 @@ class dsp_plugin:
self.running = True self.running = True
#open control pipes for csdr and send initialization data #open control pipes for csdr and send initialization data
if self.bpf_pipe != None: if self.bpf_pipe != None:
self.bpf_pipe_file=open(self.bpf_pipe,"w") self.bpf_pipe_file=open(self.bpf_pipe,"w")
self.set_bpf(self.low_cut,self.high_cut) self.set_bpf(self.low_cut,self.high_cut)
if self.shift_pipe != None: if self.shift_pipe != None:
self.shift_pipe_file=open(self.shift_pipe,"w") self.shift_pipe_file=open(self.shift_pipe,"w")
self.set_offset_freq(self.offset_freq) self.set_offset_freq(self.offset_freq)
if self.squelch_pipe != None:
self.squelch_pipe_file=open(self.squelch_pipe,"w")
self.set_squelch_level(self.squelch_level)
if self.smeter_pipe != None:
self.smeter_pipe_file=open(self.smeter_pipe,"r")
fcntl.fcntl(self.smeter_pipe_file, fcntl.F_SETFL, os.O_NONBLOCK)
def read(self,size): def read(self,size):
return self.process.stdout.read(size) return self.process.stdout.read(size)
def stop(self): def stop(self):
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM) os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
#if(self.process.poll()!=None):return # returns None while subprocess is running #if(self.process.poll()!=None):return # returns None while subprocess is running
#while(self.process.poll()==None): #while(self.process.poll()==None):
# #self.process.kill() # #self.process.kill()
# print "killproc",os.getpgid(self.process.pid),self.process.pid # print "killproc",os.getpgid(self.process.pid),self.process.pid
# os.killpg(self.process.pid, signal.SIGTERM) # os.killpg(self.process.pid, signal.SIGTERM)
# #
# time.sleep(0.1) # time.sleep(0.1)
if self.bpf_pipe: if self.bpf_pipe:
try: try: os.unlink(self.bpf_pipe)
os.unlink(self.bpf_pipe) except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe
except:
print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe
if self.shift_pipe: if self.shift_pipe:
try: try: os.unlink(self.shift_pipe)
os.unlink(self.shift_pipe) except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.shift_pipe
except: if self.squelch_pipe:
print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe try: os.unlink(self.squelch_pipe)
except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.squelch_pipe
if self.smeter_pipe:
try: os.unlink(self.smeter_pipe)
except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.smeter_pipe
self.running = False self.running = False
def restart(self): def restart(self):
@ -213,4 +241,3 @@ class dsp_plugin:
def __del__(self): def __del__(self):
self.stop() self.stop()
del(self.process) del(self.process)