Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
06054b1291 | |||
7ecab27d56 | |||
d04e9180d2 |
@ -70,7 +70,7 @@ Example DSP commands:
|
|||||||
* Decompress FLAC-coded I/Q data:
|
* Decompress FLAC-coded I/Q data:
|
||||||
flac --force-raw-format --decode --endian=little --sign=unsigned - -
|
flac --force-raw-format --decode --endian=little --sign=unsigned - -
|
||||||
'''
|
'''
|
||||||
watchdog_interval=1.5
|
watchdog_interval=0
|
||||||
reconnect_interval=10
|
reconnect_interval=10
|
||||||
'''
|
'''
|
||||||
If there's no input I/Q data after N seconds, input will be filled with zero samples,
|
If there's no input I/Q data after N seconds, input will be filled with zero samples,
|
||||||
|
@ -24,6 +24,7 @@ This file is part of OpenWebRX.
|
|||||||
#Server settings
|
#Server settings
|
||||||
web_port=8073
|
web_port=8073
|
||||||
server_hostname="localhost" # If this contains an incorrect value, the web UI may freeze on load (it can't open websocket)
|
server_hostname="localhost" # If this contains an incorrect value, the web UI may freeze on load (it can't open websocket)
|
||||||
|
max_clients=20
|
||||||
|
|
||||||
#Web GUI configuration
|
#Web GUI configuration
|
||||||
receiver_name="[Callsign]"
|
receiver_name="[Callsign]"
|
||||||
@ -53,7 +54,7 @@ center_freq = 145525000
|
|||||||
rf_gain = 5
|
rf_gain = 5
|
||||||
|
|
||||||
start_rtl_thread=True #rtl_sdr is more stable than rtl_tcp...
|
start_rtl_thread=True #rtl_sdr is more stable than rtl_tcp...
|
||||||
start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} - | nc -vvl 127.0.0.1 -p 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate)
|
start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} - | nc -vvl 127.0.0.1 -p 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate)
|
||||||
#start_rtl_tcp_command="rtl_tcp -s 250000 -f 145525000 -g 0 -p 8888"
|
#start_rtl_tcp_command="rtl_tcp -s 250000 -f 145525000 -g 0 -p 8888"
|
||||||
#You can use other SDR hardware as well, but if the command above outputs samples in a format other than [unsigned char], then the dsp plugin has to be slightly modified (at the csdr convert_u8_f part).
|
#You can use other SDR hardware as well, but if the command above outputs samples in a format other than [unsigned char], then the dsp plugin has to be slightly modified (at the csdr convert_u8_f part).
|
||||||
|
|
||||||
|
@ -1297,8 +1297,8 @@ var color_scale=[0x2e6893ff, 0x69a5d0ff, 0x214b69ff, 0x9dc4e0ff, 0xfff775ff, 0x
|
|||||||
|
|
||||||
function waterfall_mkcolor(db_value)
|
function waterfall_mkcolor(db_value)
|
||||||
{
|
{
|
||||||
min_value=-100; //in dB
|
min_value=-115; //in dB
|
||||||
max_value=10
|
max_value=0
|
||||||
if(db_value<min_value) db_value=min_value
|
if(db_value<min_value) db_value=min_value
|
||||||
if(db_value>max_value) db_value=max_value
|
if(db_value>max_value) db_value=max_value
|
||||||
full_scale=max_value-min_value;
|
full_scale=max_value-min_value;
|
||||||
|
92
htdocs/retry.html
Normal file
92
htdocs/retry.html
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
OpenWebRX (c) Copyright 2013 Andras Retzler <ha7ilm@sdr.hu>
|
||||||
|
|
||||||
|
This file is part of OpenWebRX.
|
||||||
|
|
||||||
|
OpenWebRX 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 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenWebRX 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 OpenWebRX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<head><title>OpenWebRX</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<style>
|
||||||
|
html, body
|
||||||
|
{
|
||||||
|
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
img.logo
|
||||||
|
{
|
||||||
|
margin-top: 120px;
|
||||||
|
}
|
||||||
|
div.frame
|
||||||
|
{
|
||||||
|
text-align: left;
|
||||||
|
margin:0px auto;
|
||||||
|
width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.panel
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
background-color:#777777;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: White;
|
||||||
|
font-size: 13pt;
|
||||||
|
/*text-shadow: 1px 1px 4px #444;*/
|
||||||
|
font-family: sans;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.alt
|
||||||
|
{
|
||||||
|
font-size: 10pt;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body div a
|
||||||
|
{
|
||||||
|
color: #5ca8ff;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.browser
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
var irt = function (s,n) {return s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c>="a"?97:65)<=(c=c.charCodeAt(0)-n)?c:c+26);});}
|
||||||
|
var sendmail2 = function (s) { window.location.href="mailto:"+irt(s.replace("=",String.fromCharCode(0100)).replace("$","."),8); }
|
||||||
|
window.addEventListener("load",function(){rs=document.getElementById("reconnect-secs"); rt=document.getElementById("reconnect-text"); cnt=29;window.setInterval(function(){if(cnt<=-1) window.location.href=window.location.href.split("retry.")[0]; else if(cnt==0) {rt.innerHTML="Reconnecting..."; cnt--;} else rs.innerHTML=(cnt--).toString();},1000);},false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="frame">
|
||||||
|
<img class="logo" src="gfx/openwebrx-logo-big.png" style="height: 60px;"/>
|
||||||
|
<div class="panel">
|
||||||
|
There are no client slots left on this server.
|
||||||
|
<div class="alt">
|
||||||
|
Please wait until a client disconnects.<br /><span id="reconnect-text">We will try to reconnect in <span id="reconnect-secs">30</span> seconds...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
18
openwebrx.py
18
openwebrx.py
@ -202,7 +202,7 @@ def cleanup_clients():
|
|||||||
for i in range(0,len(clients)):
|
for i in range(0,len(clients)):
|
||||||
i-=correction
|
i-=correction
|
||||||
#print "cleanup_clients:: len(clients)=", len(clients), "i=", i
|
#print "cleanup_clients:: len(clients)=", len(clients), "i=", i
|
||||||
if (not clients[i].ws_started) and (time.time()-clients[i].gen_time)>180:
|
if (not clients[i].ws_started) and (time.time()-clients[i].gen_time)>45:
|
||||||
print "[openwebrx] cleanup_clients :: client timeout to open WebSocket"
|
print "[openwebrx] cleanup_clients :: client timeout to open WebSocket"
|
||||||
close_client(i, False)
|
close_client(i, False)
|
||||||
correction+=1
|
correction+=1
|
||||||
@ -219,6 +219,7 @@ def generate_client_id(ip):
|
|||||||
new_client.spectrum_queue=Queue.Queue(1000)
|
new_client.spectrum_queue=Queue.Queue(1000)
|
||||||
new_client.ip=ip
|
new_client.ip=ip
|
||||||
new_client.closed=[False] #byref, not exactly sure if required
|
new_client.closed=[False] #byref, not exactly sure if required
|
||||||
|
new_client.dsp=None
|
||||||
clients_mutex.acquire()
|
clients_mutex.acquire()
|
||||||
clients.append(new_client)
|
clients.append(new_client)
|
||||||
log_client(new_client,"client added. Clients now: {0}".format(len(clients)))
|
log_client(new_client,"client added. Clients now: {0}".format(len(clients)))
|
||||||
@ -231,6 +232,12 @@ def close_client(i, use_mutex=True):
|
|||||||
global clients
|
global clients
|
||||||
log_client(clients[i],"client being closed.")
|
log_client(clients[i],"client being closed.")
|
||||||
if use_mutex: clients_mutex.acquire()
|
if use_mutex: clients_mutex.acquire()
|
||||||
|
try:
|
||||||
|
clients[i].dsp.stop()
|
||||||
|
except:
|
||||||
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
|
print "[openwebrx] close_client dsp.stop() :: error -",exc_type,exc_value
|
||||||
|
traceback.print_tb(exc_traceback)
|
||||||
clients[i].closed[0]=True
|
clients[i].closed[0]=True
|
||||||
del clients[i]
|
del clients[i]
|
||||||
if use_mutex: clients_mutex.release()
|
if use_mutex: clients_mutex.release()
|
||||||
@ -289,6 +296,7 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
dsp.set_offset_freq(0)
|
dsp.set_offset_freq(0)
|
||||||
dsp.set_bpf(-4000,4000)
|
dsp.set_bpf(-4000,4000)
|
||||||
dsp.start()
|
dsp.start()
|
||||||
|
myclient.dsp=dsp
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if myclient.closed[0]:
|
if myclient.closed[0]:
|
||||||
@ -377,6 +385,14 @@ class WebRXHandler(BaseHTTPRequestHandler):
|
|||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write("<html><body><h1>Object moved</h1>Please <a href=\"/upgrade.html\">click here</a> to continue.</body></html>")
|
self.wfile.write("<html><body><h1>Object moved</h1>Please <a href=\"/upgrade.html\">click here</a> to continue.</body></html>")
|
||||||
return
|
return
|
||||||
|
if extension == "wrx": cleanup_clients()
|
||||||
|
if extension == "wrx" and cfg.max_clients<=len(clients):
|
||||||
|
self.send_response(302) #backported max_clients fix
|
||||||
|
self.send_header('Content-type','text/html')
|
||||||
|
self.send_header("Location", "http://{0}:{1}/retry.html".format(cfg.server_hostname,cfg.web_port))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write("<html><body><h1>Object moved</h1>Please <a href=\"/retry.html\">click here</a> to continue.</body></html>")
|
||||||
|
return
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
if(("wrx","html","htm").count(extension)):
|
if(("wrx","html","htm").count(extension)):
|
||||||
self.send_header('Content-type','text/html')
|
self.send_header('Content-type','text/html')
|
||||||
|
@ -2,6 +2,7 @@ import subprocess
|
|||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import code
|
import code
|
||||||
|
import signal
|
||||||
|
|
||||||
class dsp_plugin:
|
class dsp_plugin:
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ class dsp_plugin:
|
|||||||
self.demodulator = "nfm"
|
self.demodulator = "nfm"
|
||||||
self.name = "csdr"
|
self.name = "csdr"
|
||||||
try:
|
try:
|
||||||
subprocess.Popen("nc",stdout=subprocess.PIPE,stderr=subprocess.PIPE)
|
subprocess.Popen("nc",stdout=subprocess.PIPE,stderr=subprocess.PIPE).kill()
|
||||||
except:
|
except:
|
||||||
print "[openwebrx-plugin:csdr] error: netcat not found, please install netcat!"
|
print "[openwebrx-plugin:csdr] error: netcat not found, please install netcat!"
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ class dsp_plugin:
|
|||||||
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(),bpf_transition_bw=float(self.bpf_transition_bw)/self.if_samp_rate(),ddc_transition_bw=self.ddc_transition_bw())
|
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(),bpf_transition_bw=float(self.bpf_transition_bw)/self.if_samp_rate(),ddc_transition_bw=self.ddc_transition_bw())
|
||||||
print "[openwebrx-dsp-plugin:csdr] Command =",command
|
print "[openwebrx-dsp-plugin:csdr] Command =",command
|
||||||
#code.interact(local=locals())
|
#code.interact(local=locals())
|
||||||
self.process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
|
self.process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp)
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
#open control pipes for csdr and send initialization data
|
#open control pipes for csdr and send initialization data
|
||||||
@ -121,10 +122,7 @@ class dsp_plugin:
|
|||||||
return self.process.stdout.read(size)
|
return self.process.stdout.read(size)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if(self.process!=None):return # returns None while subprocess is running
|
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
|
||||||
while(self.process.poll()==None):
|
|
||||||
self.process.kill()
|
|
||||||
time.sleep(0.1)
|
|
||||||
os.unlink(self.bpf_pipe)
|
os.unlink(self.bpf_pipe)
|
||||||
os.unlink(self.shift_pipe)
|
os.unlink(self.shift_pipe)
|
||||||
self.running = False
|
self.running = False
|
||||||
|
21
rtl_mus.py
21
rtl_mus.py
@ -87,7 +87,7 @@ def add_data_to_clients(new_data):
|
|||||||
elif cfg.cache_full_behaviour == 1:
|
elif cfg.cache_full_behaviour == 1:
|
||||||
#rather closing client:
|
#rather closing client:
|
||||||
log.error("client cache full, dropping client: "+str(client[0].ident)+"@"+client[0].socket[1][0])
|
log.error("client cache full, dropping client: "+str(client[0].ident)+"@"+client[0].socket[1][0])
|
||||||
client[0].close()
|
client[0].close(False)
|
||||||
elif cfg.cache_full_behaviour == 2:
|
elif cfg.cache_full_behaviour == 2:
|
||||||
pass #client cache full, just not taking care
|
pass #client cache full, just not taking care
|
||||||
else: log.error("invalid value for cfg.cache_full_behaviour")
|
else: log.error("invalid value for cfg.cache_full_behaviour")
|
||||||
@ -131,6 +131,7 @@ class client_handler(asyncore.dispatcher):
|
|||||||
self.sent_dongle_id=False
|
self.sent_dongle_id=False
|
||||||
self.last_waiting_buffer=""
|
self.last_waiting_buffer=""
|
||||||
asyncore.dispatcher.__init__(self, self.client[0].socket[0])
|
asyncore.dispatcher.__init__(self, self.client[0].socket[0])
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
|
|
||||||
def handle_read(self):
|
def handle_read(self):
|
||||||
global commands
|
global commands
|
||||||
@ -174,6 +175,7 @@ class server_asyncore(asyncore.dispatcher):
|
|||||||
self.set_reuse_addr()
|
self.set_reuse_addr()
|
||||||
self.bind((cfg.my_ip, cfg.my_listening_port))
|
self.bind((cfg.my_ip, cfg.my_listening_port))
|
||||||
self.listen(5)
|
self.listen(5)
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
log.info("Server listening on port: "+str(cfg.my_listening_port))
|
log.info("Server listening on port: "+str(cfg.my_listening_port))
|
||||||
|
|
||||||
def handle_accept(self):
|
def handle_accept(self):
|
||||||
@ -188,7 +190,7 @@ class server_asyncore(asyncore.dispatcher):
|
|||||||
my_client[0].ident=max_client_id
|
my_client[0].ident=max_client_id
|
||||||
max_client_id+=1
|
max_client_id+=1
|
||||||
my_client[0].start_time=time.time()
|
my_client[0].start_time=time.time()
|
||||||
my_client[0].waiting_data=multiprocessing.Queue(250)
|
my_client[0].waiting_data=multiprocessing.Queue(500)
|
||||||
clients_mutex.acquire()
|
clients_mutex.acquire()
|
||||||
clients.append(my_client)
|
clients.append(my_client)
|
||||||
clients_mutex.release()
|
clients_mutex.release()
|
||||||
@ -278,9 +280,9 @@ class rtl_tcp_asyncore(asyncore.dispatcher):
|
|||||||
if(len(rtl_dongle_identifier)==0):
|
if(len(rtl_dongle_identifier)==0):
|
||||||
rtl_dongle_identifier=self.recv(12)
|
rtl_dongle_identifier=self.recv(12)
|
||||||
return
|
return
|
||||||
new_data_buffer=self.recv(16348)
|
new_data_buffer=self.recv(1024*16)
|
||||||
if cfg.watchdog_interval:
|
if cfg.watchdog_interval:
|
||||||
watchdog_data_count+=16348
|
watchdog_data_count+=1024*16
|
||||||
if cfg.use_dsp_command:
|
if cfg.use_dsp_command:
|
||||||
dsp_input_queue.put(new_data_buffer)
|
dsp_input_queue.put(new_data_buffer)
|
||||||
#print "did put anyway"
|
#print "did put anyway"
|
||||||
@ -418,11 +420,13 @@ class client:
|
|||||||
socket=None
|
socket=None
|
||||||
asyncore=None
|
asyncore=None
|
||||||
|
|
||||||
def close(self):
|
def close(self, use_mutex=True):
|
||||||
global clients_mutex
|
global clients_mutex
|
||||||
global clients
|
global clients
|
||||||
clients_mutex.acquire()
|
if use_mutex: clients_mutex.acquire()
|
||||||
|
correction=0
|
||||||
for i in range(0,len(clients)):
|
for i in range(0,len(clients)):
|
||||||
|
i-=correction
|
||||||
if clients[i][0].ident==self.ident:
|
if clients[i][0].ident==self.ident:
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
@ -433,8 +437,9 @@ class client:
|
|||||||
del self.asyncore
|
del self.asyncore
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
break
|
del clients[i]
|
||||||
clients_mutex.release()
|
correction+=1
|
||||||
|
if use_mutex: clients_mutex.release()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
Reference in New Issue
Block a user