add functions
224
UHRR
Executable file
@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import alsaaudio
|
||||
import threading
|
||||
import time
|
||||
import numpy
|
||||
import gc
|
||||
import Hamlib
|
||||
|
||||
############ Global variables ##################################
|
||||
CTRX=None
|
||||
|
||||
############ websocket for send RX audio from TRX ##############
|
||||
flagWavstart = False
|
||||
AudioRXHandlerClients = []
|
||||
|
||||
class loadWavdata(threading.Thread):
|
||||
|
||||
def __init__(self):
|
||||
global flagWavstart
|
||||
threading.Thread.__init__(self)
|
||||
device = 'plughw:CARD=U0x41e0x30d3,DEV=0'
|
||||
self.inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, channels=1, rate=8000, format=alsaaudio.PCM_FORMAT_FLOAT_LE, periodsize=256, device=device)
|
||||
print('recording...')
|
||||
|
||||
def run(self):
|
||||
global Wavframes, flagWavstart
|
||||
ret=b''
|
||||
while True:
|
||||
while not flagWavstart:
|
||||
time.sleep(0.5)
|
||||
l, ret = self.inp.read()
|
||||
if l > 0:
|
||||
for c in AudioRXHandlerClients:
|
||||
c.Wavframes.append(ret)
|
||||
else:
|
||||
print("overrun")
|
||||
|
||||
class AudioRXHandler(tornado.websocket.WebSocketHandler):
|
||||
|
||||
def open(self):
|
||||
self.set_nodelay(True)
|
||||
global flagWavstart
|
||||
if self not in AudioRXHandlerClients:
|
||||
AudioRXHandlerClients.append(self)
|
||||
self.Wavframes = []
|
||||
print('new connection on AudioRXHandler socket.')
|
||||
flagWavstart = True
|
||||
self.tailstream()
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def tailstream(self):
|
||||
while flagWavstart:
|
||||
while len(self.Wavframes)==0:
|
||||
yield tornado.gen.sleep(0.1)
|
||||
yield self.write_message(self.Wavframes[0],binary=True)
|
||||
del self.Wavframes[0]
|
||||
|
||||
def on_close(self):
|
||||
if self in AudioRXHandlerClients:
|
||||
AudioRXHandlerClients.remove(self)
|
||||
global flagWavstart
|
||||
print('connection closed for audioRX')
|
||||
if len(AudioRXHandlerClients)<=0:
|
||||
flagWavstart = False
|
||||
self.Wavframes = []
|
||||
gc.collect()
|
||||
|
||||
############ websocket for control TRX ##############
|
||||
ControlTRXHandlerClients = []
|
||||
|
||||
class TRXRIG:
|
||||
def __init__(self):
|
||||
self.infos = {}
|
||||
self.serialport = Hamlib.hamlib_port_parm_serial
|
||||
self.serialport.rate=38400
|
||||
try:
|
||||
self.rig_model = "RIG_MODEL_FT817"
|
||||
self.rig_pathname = "/dev/ttyUSB0"
|
||||
self.rig = Hamlib.Rig(Hamlib.__dict__[self.rig_model]) # Look up the model's numerical index in Hamlib's symbol dictionary.
|
||||
self.rig.set_conf("rig_pathname", self.rig_pathname)
|
||||
self.rig.set_conf("retry", "5")
|
||||
self.rig.open()
|
||||
except:
|
||||
logging.error("Could not open a communication channel to the rig via Hamlib!")
|
||||
|
||||
self.getvfo()
|
||||
self.getFreq()
|
||||
self.getMode()
|
||||
|
||||
def getvfo(self):
|
||||
try:
|
||||
self.infos["VFO"] = (self.rig.get_vfo())
|
||||
except:
|
||||
logging.error("Could not obtain the current VFO via Hamlib!")
|
||||
return self.infos["VFO"]
|
||||
|
||||
def setFreq(self,frequency):
|
||||
try:
|
||||
self.rig.set_freq(Hamlib.RIG_VFO_CURR, float(frequency))
|
||||
self.getFreq()
|
||||
except:
|
||||
logging.error("Could not set the frequency via Hamlib!")
|
||||
return self.infos["FREQ"]
|
||||
|
||||
def getFreq(self):
|
||||
try:
|
||||
self.infos["FREQ"] = (int(self.rig.get_freq()))
|
||||
except:
|
||||
logging.error("Could not obtain the current frequency via Hamlib!")
|
||||
return self.infos["FREQ"]
|
||||
|
||||
def setMode(self,MODE):
|
||||
try:
|
||||
|
||||
self.rig.set_mode(Hamlib.rig_parse_mode(MODE))
|
||||
self.getMode()
|
||||
except:
|
||||
logging.error("Could not set the mode via Hamlib!")
|
||||
return self.infos["MODE"]
|
||||
|
||||
def setPTT(self,status):
|
||||
try:
|
||||
if status:
|
||||
self.rig.set_ptt(Hamlib.RIG_VFO_CURR,Hamlib.RIG_PTT_ON)
|
||||
self.infos["PTT"]="PTT_OFF"
|
||||
else:
|
||||
self.rig.set_ptt(Hamlib.RIG_VFO_CURR,Hamlib.RIG_PTT_OFF)
|
||||
self.infos["PTT"]="PTT_ON"
|
||||
except:
|
||||
logging.error("Could not set the mode via Hamlib!")
|
||||
return self.infos["PTT"]
|
||||
|
||||
def getMode(self):
|
||||
try:
|
||||
(mode, width) = self.rig.get_mode()
|
||||
self.infos["MODE"] = Hamlib.rig_strrmode(mode).upper()
|
||||
self.infos["WIDTH"] = width
|
||||
except:
|
||||
logging.error("Could not obtain the current Mode via Hamlib!")
|
||||
return self.infos["MODE"]
|
||||
|
||||
def getStrgLVL(self):
|
||||
try:
|
||||
self.infos["StrgLVL"] = self.rig.get_level_i(Hamlib.RIG_LEVEL_STRENGTH)
|
||||
except:
|
||||
logging.error("Could not obtain the current Strength signal RX level via Hamlib!")
|
||||
return self.infos["StrgLVL"]
|
||||
|
||||
def setPower(self,status=1):
|
||||
try:
|
||||
if status:
|
||||
self.rig.set_powerstat(Hamlib.RIG_POWER_ON)
|
||||
else:
|
||||
self.rig.set_powerstat(Hamlib.RIG_POWER_OFF)
|
||||
self.infos["powerstat"] = status
|
||||
except:
|
||||
logging.error("Could not set power status via Hamlib!")
|
||||
return self.infos["powerstat"]
|
||||
|
||||
class ControlTRX(tornado.websocket.WebSocketHandler):
|
||||
def open(self):
|
||||
if self not in ControlTRXHandlerClients:
|
||||
ControlTRXHandlerClients.append(self)
|
||||
print('new connection on ControlTRX socket.')
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def on_message(self, data) :
|
||||
print(data)
|
||||
|
||||
try:
|
||||
(action, datato) = data.split(':')
|
||||
except ValueError:
|
||||
action = data
|
||||
pass
|
||||
|
||||
if(action == "PING"):
|
||||
self.write_message("PONG")
|
||||
elif(action == "getFreq"):
|
||||
yield self.write_message("getFreq:"+str(CTRX.getFreq())) #CTRX()[data]()
|
||||
elif(action == "setFreq"):
|
||||
yield self.write_message("getFreq:"+str(CTRX.setFreq(datato)))
|
||||
|
||||
|
||||
def on_close(self):
|
||||
if self in ControlTRXHandlerClients:
|
||||
ControlTRXHandlerClients.remove(self)
|
||||
gc.collect()
|
||||
|
||||
############ Main ##############
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
self.application.settings.get("compiled_template_cache", False)
|
||||
self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
self.render("www/index.html")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
threadloadWavdata = loadWavdata()
|
||||
threadloadWavdata.start()
|
||||
|
||||
CTRX = TRXRIG()
|
||||
CTRX.setPower(1)
|
||||
|
||||
app = tornado.web.Application([
|
||||
(r'/CTRX', ControlTRX),
|
||||
(r'/audioRX', AudioRXHandler),
|
||||
(r'/', MainHandler),
|
||||
(r'/(.*)', tornado.web.StaticFileHandler, { 'path' : './www' })
|
||||
],debug=True)
|
||||
|
||||
http_server = tornado.httpserver.HTTPServer(app, ssl_options={
|
||||
"certfile": os.path.join("selfsign.crt"),
|
||||
"keyfile": os.path.join("selfsign.key"),
|
||||
})
|
||||
http_server.listen(8888)
|
||||
print('http server started')
|
||||
tornado.ioloop.IOLoop.instance().start()
|
21
selfsign.crt
Normal file
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUFZazUUKBBIYvF+HJuDNOXN1FQewwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA1MjAxODA2MjhaFw0yMDA2
|
||||
MTkxODA2MjhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCcydQ7PQ2q9mh0RxiQ7D0xYpLmUrsWq6J1oEMzT1Q0
|
||||
Cglib2cRkwE4gWx67tHmL+IqA0HdYyZQkvc81T4z8DFgchQY997uhCFZvmtEvJln
|
||||
KvJIS8wPXuZqQCJAKSfmyGGS+WBiMb7l1nrM0kDVGgllWFxleTWkjn+dKJHlcTQs
|
||||
ankV2SmPKSBbp96tid5oLF9Po9l3A7HoCTGSiV+CnNPsr0ptAx7wYjx+FXZiwBx3
|
||||
zBfiprtCyfja0bQZLkCZOkRjNn6Px5g8vuN8O/NO6UdEKJdoNwfn40nQ+ledOwca
|
||||
/TgcbHwzFvZD1cMXceScZDQxhzaVlOYUxxEKgxlxOXSzAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBRFcsDAW0GZCgiFES0Yfr8ITkCtnjAfBgNVHSMEGDAWgBRFcsDAW0GZCgiF
|
||||
ES0Yfr8ITkCtnjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBb
|
||||
F1Lq/K8MYtQ8co9QY4C/sRiFpxh+gSZan4N7wdpCupqlphsN58G0zw/YxjrqLu8k
|
||||
wdmv4nV95zFqzpBH+eit3dIrGSRdO3rln+fMLiNMhvK23v1BsfWbwgqd513RTTlQ
|
||||
mUloWsPIca2S6PiMcfTnZRTyyZOg6ciVsKv1b+NyMfnFDHc90+WNz6dZG2TjgdCJ
|
||||
mC5oV52KG+Ju3sQYnv/1a8zUsAeB6uG/gjFbbg/ANPdWh7jvmY8wXSd22jYVzWxZ
|
||||
YTkPLIBf+GegWvWLkNTbydmDdmAROzlJVLVhfMaOQuvAnrdKpd0oFqDs+uNiPMgB
|
||||
b7H5eusoH7uXuOD8NQNK
|
||||
-----END CERTIFICATE-----
|
27
selfsign.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAnMnUOz0NqvZodEcYkOw9MWKS5lK7FquidaBDM09UNAoJYm9n
|
||||
EZMBOIFseu7R5i/iKgNB3WMmUJL3PNU+M/AxYHIUGPfe7oQhWb5rRLyZZyrySEvM
|
||||
D17makAiQCkn5shhkvlgYjG+5dZ6zNJA1RoJZVhcZXk1pI5/nSiR5XE0LGp5Fdkp
|
||||
jykgW6ferYneaCxfT6PZdwOx6AkxkolfgpzT7K9KbQMe8GI8fhV2YsAcd8wX4qa7
|
||||
Qsn42tG0GS5AmTpEYzZ+j8eYPL7jfDvzTulHRCiXaDcH5+NJ0PpXnTsHGv04HGx8
|
||||
Mxb2Q9XDF3HknGQ0MYc2lZTmFMcRCoMZcTl0swIDAQABAoIBAHD+Z6x1mKcQREEg
|
||||
h8zR5Fv1/YZuMxTohwGciTGuRzHl1dOSE8avmh6d7489FBp/gc/jXxFtBkzlTbcS
|
||||
u2x0+zDVpjREVu6wXNSvjeEQxsF6SvfdYGfnbck/BTAWOQJygReKD3NVBI3hn8iC
|
||||
8mRiCkl2f8hFrWo1pDSf611e00n6JRg2YPlH/gBqV2T0mDJL7CXTP6Tggaa6jInQ
|
||||
Ux7OgPz8djEvk5jFm0lGVxHzo/kbTGfBTLbKfJv/NTxiHH7Qt8NeaFzzJo7sH1eM
|
||||
E8JT8sZZdCiBtlEmmgp/vX+r9M1gqi2i/evOzJxayx6J+CaGiS/j/VuXC5sQJB8L
|
||||
jaorwikCgYEAyc1YZ0uxWoCy2M6fYG3ClJ9P3n2rfwdBwzhXaPm6B8EI7UCPR/0/
|
||||
EcckGe34QGc2XmtwgxHIJ+hiidzLTn5hMDHYO82JOKa8cQppIKdGGnRwGhyiZhaf
|
||||
tRyUD5ySPEFL8GR+Mau19NYy5bic5mDrFmSiCtgsxf3kzgAPmxF/BZcCgYEAxuWe
|
||||
yRsLX5XZHZJRdrGt6lrSnr0BosKIjNxJDwh9VUVh49bzWa1Kvp7u+XMlN48A335I
|
||||
Aukicujtoe0gIGS9btFOPX5seBs+lReWFpVn0Xa0OJQby7oX3Fp1XDTsbvtrcDHV
|
||||
vXsZLNv3ip0OGKRh1p1va/idTpajeqPRDB5HBUUCgYACu/2OqL/mcgf6WBJgxBv2
|
||||
15HFef5w4jBJ7OGCUp/qqvrr/Av09cF9BC3BDDBo7v0Vmm8T15HWuJddNtiqX5wB
|
||||
gyti5A4P7nJvNazm/F0+zoUWVXz91SCk25ZF/+EbX+cfgr0S/zif8KcP5ch6dqW4
|
||||
z/RCIVu58w6+m9GaUEpgUQKBgQCX7E60GBdA5MnZn6jf++n3B3a3z3EPbH428hBQ
|
||||
DlEFsCCMkuSAjDB6mBW7rmswG+gzzlac+ozYrvjMZb7TX3+exPt5VzbtKwpLgZ+g
|
||||
EnEhewU/7kmo/LU7GFFqo/Yw85RmN3qm5/8b180mML7SrcUZ1FmGZHlrzP6EL9r+
|
||||
4aWn7QKBgFXxU/vI5RVpvG35dt5BwomBMIx0W2UtXIG+/u8j7S9GBUXFXUyUVr9W
|
||||
rPsI1TpIZKR9r95RIaj8B25DyUApJVlH7jf2DDoASqr5dR77fmQVaANrrDhgMjNl
|
||||
QmPd4kw52/wr5KLJukLK9dg8kmwDIMGvHy9rBGo5uoKk4+daUjTW
|
||||
-----END RSA PRIVATE KEY-----
|
271
www/controls.js
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
//Extra Generals///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//document.addEventListener('contextmenu', event => event.preventDefault());
|
||||
function bodyload(){
|
||||
disableScroll();
|
||||
}
|
||||
|
||||
function disableScroll() {
|
||||
// Get the current page scroll position
|
||||
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
|
||||
|
||||
// if any scroll is attempted, set this to the previous value
|
||||
window.onscroll = function() {
|
||||
window.scrollTo(scrollLeft, scrollTop);
|
||||
};
|
||||
}
|
||||
|
||||
//Generals routines///////////////////////////////////////////////////////////////////////////
|
||||
poweron = false;
|
||||
function powertogle()
|
||||
{
|
||||
if(event.srcElement.src.replace(/^.*[\\\/]/, '')=="poweroff.png"){
|
||||
event.srcElement.src="img/poweron.png";
|
||||
|
||||
document.getElementById("ombre-body").style.display = "block";
|
||||
document.getElementById("pop-upspinner").style.display = "block";
|
||||
check_connected();
|
||||
|
||||
AudioRX_start();
|
||||
ControlTRX_start();
|
||||
|
||||
checklatency();
|
||||
|
||||
poweron = true;
|
||||
}
|
||||
else{
|
||||
event.srcElement.src="img/poweroff.png";
|
||||
AudioRX_stop();
|
||||
ControlTRX_stop();
|
||||
|
||||
poweron = false;
|
||||
}
|
||||
}
|
||||
|
||||
function check_connected() {
|
||||
setTimeout(function () {
|
||||
if (wsAudioRX.readyState === WebSocket.OPEN && wsControlTRX.readyState === WebSocket.OPEN){document.getElementById("ombre-body").style.display = "none";document.getElementById("pop-upspinner").style.display = "none";}
|
||||
else{check_connected();}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
//RX Audio routines///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var wsAudioRX = "";
|
||||
var AudioRX_context = "";
|
||||
var AudioRX_source_node = "";
|
||||
var audiobufferready = false;
|
||||
|
||||
function AudioRX_start(){
|
||||
document.getElementById("indwsAudioRX").innerHTML='<img src="img/critsgrey.png">wsRX';
|
||||
var audiobuffer = [];var lenglitchbuf = 2;
|
||||
|
||||
wsAudioRX = new WebSocket( 'wss://' + window.location.href.split( '/' )[2] + '/audioRX' );
|
||||
wsAudioRX.binaryType = 'arraybuffer';
|
||||
wsAudioRX.onmessage = appendwsAudioRX;
|
||||
wsAudioRX.onopen = wsAudioRXopen;
|
||||
wsAudioRX.onclose = wsAudioRXclose;
|
||||
wsAudioRX.onerror = wsAudioRXerror;
|
||||
|
||||
function appendwsAudioRX( msg ){
|
||||
var buffer = new Float32Array(msg.data);
|
||||
audiobuffer.push(buffer);
|
||||
if(audiobuffer.length>lenglitchbuf){audiobufferready= true;}
|
||||
//console.log(audiobuffer.length);
|
||||
|
||||
}
|
||||
|
||||
var BUFF_SIZE = 256; // spec allows, yet do not go below 1024
|
||||
AudioRX_context = new AudioContext({latencyHint: "interactive",sampleRate: 8000});
|
||||
var AudioRX_gain_node = AudioRX_context.createGain();
|
||||
AudioRX_gain_node.connect( AudioRX_context.destination );
|
||||
AudioRX_source_node = AudioRX_context.createScriptProcessor(BUFF_SIZE, 1, 1);
|
||||
|
||||
AudioRX_source_node.onaudioprocess = (function() {
|
||||
return function(event) {
|
||||
var synth_buff = event.outputBuffer.getChannelData(0); // mono for now
|
||||
if(audiobufferready){
|
||||
for (var i = 0, buff_size = synth_buff.length; i < buff_size; i++) {
|
||||
synth_buff[i] = audiobuffer[0][i];
|
||||
}
|
||||
if(audiobuffer.length > 1){audiobuffer.shift();}
|
||||
}
|
||||
|
||||
};
|
||||
}());
|
||||
|
||||
AudioRX_source_node.connect(AudioRX_gain_node);
|
||||
}
|
||||
|
||||
function wsAudioRXopen(){
|
||||
document.getElementById("indwsAudioRX").innerHTML='<img src="img/critsgreen.png">wsRX';
|
||||
}
|
||||
|
||||
function wsAudioRXclose(){
|
||||
document.getElementById("indwsAudioRX").innerHTML='<img src="img/critsred.png">wsRX';
|
||||
AudioRX_stop();
|
||||
}
|
||||
|
||||
function wsAudioRXerror(err){
|
||||
document.getElementById("indwsAudioRX").innerHTML='<img src="img/critsred.png">wsRX';
|
||||
AudioRX_stop();
|
||||
}
|
||||
|
||||
function AudioRX_stop()
|
||||
{
|
||||
audiobufferready = false;
|
||||
wsAudioRX.close();
|
||||
AudioRX_source_node.onaudioprocess = null
|
||||
AudioRX_context.close();
|
||||
}
|
||||
|
||||
//ControlTRX routines///////////////////////////////////////////////////////////////////////////
|
||||
var wsControlTRX = "";
|
||||
|
||||
function ControlTRX_start(){
|
||||
document.getElementById("indwsControlTRX").innerHTML='<img src="img/critsgrey.png">wsCtrl';
|
||||
wsControlTRX = new WebSocket( 'wss://' + window.location.href.split( '/' )[2] + '/CTRX' );
|
||||
wsControlTRX.onopen = wsControlTRXopen;
|
||||
wsControlTRX.onclose = wsControlTRXclose;
|
||||
wsControlTRX.onerror = wsControlTRXerror;
|
||||
wsControlTRX.onmessage = wsControlTRXcrtol;
|
||||
}
|
||||
|
||||
function wsControlTRXcrtol( msg ){
|
||||
console.log(String(msg.data));
|
||||
words = String(msg.data).split(':');
|
||||
if(words[0] == "PONG"){showlatency();}
|
||||
else if(words[0] == "getFreq"){showfreq(words[1]);}
|
||||
|
||||
}
|
||||
|
||||
function ControlTRX_stop()
|
||||
{
|
||||
wsControlTRX.close();
|
||||
}
|
||||
|
||||
function wsControlTRXopen(){
|
||||
document.getElementById("indwsControlTRX").innerHTML='<img src="img/critsgreen.png">wsCtrl';
|
||||
wsControlTRX.send("getFreq:");
|
||||
}
|
||||
|
||||
function wsControlTRXclose(){
|
||||
document.getElementById("indwsControlTRX").innerHTML='<img src="img/critsred.png">wsCtrl';
|
||||
}
|
||||
|
||||
function wsControlTRXerror(err){
|
||||
wsControlTRX.close();
|
||||
document.getElementById("indwsControlTRX").innerHTML='<img src="img/critsred.png">wsCtrl';
|
||||
ControlTRX_start();
|
||||
}
|
||||
|
||||
var startTime;
|
||||
function checklatency() {
|
||||
setTimeout(function () {
|
||||
startTime = Date.now();
|
||||
if (wsControlTRX.readyState === WebSocket.OPEN) {wsControlTRX.send("PING");}
|
||||
if(poweron == true){checklatency();}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function showlatency(){
|
||||
latency = Date.now() - startTime;
|
||||
document.getElementById("div-latencymeter").innerHTML="latency:"+latency+"ms";
|
||||
}
|
||||
|
||||
function get_digit_freq(){
|
||||
return parseInt(
|
||||
document.getElementById("cmhz").innerHTML+
|
||||
document.getElementById("dmhz").innerHTML+
|
||||
document.getElementById("umhz").innerHTML+
|
||||
document.getElementById("ckhz").innerHTML+
|
||||
document.getElementById("dkhz").innerHTML+
|
||||
document.getElementById("ukhz").innerHTML+
|
||||
document.getElementById("chz").innerHTML+
|
||||
document.getElementById("dhz").innerHTML+
|
||||
document.getElementById("uhz").innerHTML
|
||||
);
|
||||
}
|
||||
|
||||
freq_digit_selected="";
|
||||
function freq_digit_scroll() {
|
||||
if (poweron) {
|
||||
if(event.deltaY>0){toadd=-1;}else{toadd=1;}
|
||||
freq=get_digit_freq()+(freq_digit_selected.getAttribute('v')*toadd);
|
||||
if(freq>0){showfreq(freq);sendTRXfreq();}
|
||||
}
|
||||
}
|
||||
|
||||
function select_digit() {
|
||||
freq_digit_selected=event.srcElement;
|
||||
}
|
||||
|
||||
function clear_select_digit() {
|
||||
freq_digit_selected="";
|
||||
}
|
||||
|
||||
function rotatefreq(){
|
||||
if (poweron) {
|
||||
freq=get_digit_freq()+parseInt(event.srcElement.getAttribute('v'));
|
||||
if(freq>0){showfreq(freq);sendTRXfreq();}
|
||||
}
|
||||
}
|
||||
|
||||
function showfreq(freq){
|
||||
freq=freq.toString();
|
||||
while (freq.length < 9){freq="0"+freq;}
|
||||
document.getElementById("cmhz").innerHTML=freq.substring(0, 1);
|
||||
document.getElementById("dmhz").innerHTML=freq.substring(1, 2);
|
||||
document.getElementById("umhz").innerHTML=freq.substring(2, 3);
|
||||
document.getElementById("ckhz").innerHTML=freq.substring(3, 4);
|
||||
document.getElementById("dkhz").innerHTML=freq.substring(4, 5);
|
||||
document.getElementById("ukhz").innerHTML=freq.substring(5, 6);
|
||||
document.getElementById("chz").innerHTML=freq.substring(6, 7);
|
||||
document.getElementById("dhz").innerHTML=freq.substring(7, 8);
|
||||
document.getElementById("uhz").innerHTML=freq.substring(8, 9);
|
||||
}
|
||||
|
||||
function sendTRXfreq(){
|
||||
if (wsControlTRX.readyState === WebSocket.OPEN) {wsControlTRX.send("setFreq:"+get_digit_freq());}
|
||||
}
|
||||
|
||||
//Cosmetics
|
||||
function button_pressed(item)
|
||||
{
|
||||
if(!item){item=event.srcElement;}
|
||||
item.classList.remove('button_unpressed');
|
||||
item.classList.add('button_pressed');
|
||||
button_light(item);
|
||||
}
|
||||
|
||||
function button_unpressed(item)
|
||||
{
|
||||
if(!item){item=event.srcElement;}
|
||||
item.classList.remove('button_green');
|
||||
item.classList.remove('button_pressed');
|
||||
item.classList.add('button_unpressed');
|
||||
}
|
||||
|
||||
function button_light(item,color="G")
|
||||
{
|
||||
if(!item){item=event.srcElement;}
|
||||
if(color=="G"){
|
||||
if(poweron){item.classList.add('button_green');}
|
||||
else{item.classList.remove('button_green');}
|
||||
}
|
||||
else if(color=="R"){
|
||||
if(poweron){item.classList.add('button_red');}
|
||||
else{item.classList.remove('button_red');}
|
||||
}
|
||||
else if(color=="Z"){
|
||||
item.classList.remove('button_red');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
www/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
www/favicon.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
www/img/critsgreen.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
www/img/critsgrey.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
www/img/critsred.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
www/img/critsyellow.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
www/img/poweroff.png
Normal file
After Width: | Height: | Size: 207 KiB |
BIN
www/img/poweron.png
Normal file
After Width: | Height: | Size: 224 KiB |
BIN
www/img/spinner.gif
Normal file
After Width: | Height: | Size: 55 KiB |
73
www/index.html
Normal file
@ -0,0 +1,73 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Universal Hamradio Remote by F4HTB</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script src="controls.js"></script>
|
||||
</head>
|
||||
</head>
|
||||
<body onload="bodyload();">
|
||||
|
||||
<a href="#fermer" id="ombre-body"></a>
|
||||
<div id="pop-upspinner">
|
||||
<img alt="" src="img/spinner.gif">
|
||||
<p id="socketsate"><center>Wait For connection....</center></p>
|
||||
</div>
|
||||
|
||||
<div id="div-princ">
|
||||
<img onclick="powertogle();" id="button_power" src="img/poweroff.png">
|
||||
|
||||
|
||||
<div id="div-freq">
|
||||
<ul id="freq_but">
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="cmhz" v=100000000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dmhz" v=10000000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="umhz" v=1000000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();"> </li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="ckhz" v=100000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dkhz" v=10000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="ukhz" v=1000>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();"> </li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="chz" v=100>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dhz" v=10>▲</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="uhz" v=1>▲</li>
|
||||
</ul>
|
||||
<ul id="freq_disp" onwheel="freq_digit_scroll()">
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="cmhz" v=100000000>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="dmhz" v=10000000>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="umhz" v=1000000>0</li>
|
||||
<li class="freq_digit">.</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="ckhz" v=100000>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="dkhz" v=10000>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="ukhz" v=1000>0</li>
|
||||
<li class="freq_digit">.</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="chz" v=100>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="dhz" v=10>0</li>
|
||||
<li class="freq_digit" onmouseenter="select_digit();" onmouseleave="clear_select_digit();" id="uhz" v=1>0</li>
|
||||
</ul>
|
||||
<ul id="freq_but">
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="cmhz" v=-100000000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dmhz" v=-10000000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="umhz" v=-1000000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();"> </li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="ckhz" v=-100000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dkhz" v=-10000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="ukhz" v=-1000>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" > </li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="chz" v=-100>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="dhz" v=-10>▼</li>
|
||||
<li onmousedown="button_pressed();rotatefreq();" onmouseup="button_unpressed();" class="button_unpressed" digit="uhz" v=-1>▼</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="div-scoketscontrols">
|
||||
<p id="indcwsTX"><img src="img/critsred.png">wsTX</p>
|
||||
<p id="indwsAudioRX"><img src="img/critsred.png">wsRX</p>
|
||||
<p id="indwsControlTRX"><img src="img/critsred.png">wsCtrl</p>
|
||||
<p id="indcwsFFT"><img src="img/critsred.png">wsFFT</p>
|
||||
</div>
|
||||
<div id="div-latencymeter">latency:∞</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
178
www/style.css
Normal file
@ -0,0 +1,178 @@
|
||||
body {
|
||||
color: white;
|
||||
font:normal bold 14px tahoma;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#ombre-body{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.7);
|
||||
z-index: 1000;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#pop-upspinner{
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: calc(50% - 100px);
|
||||
top: 50%;
|
||||
z-index: 2000;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#div-princ {
|
||||
margin: 20px auto;
|
||||
width: 1800px;
|
||||
height: 860px;
|
||||
background-color:#171717;
|
||||
box-shadow:5px 5px 5px 5px rgba(0, 0, 0, 0.5),0px 0px 0px 0px rgba(255, 255, 255, 0.5) inset;
|
||||
border-radius: 30px 30px 30px 30px ;
|
||||
position:relative
|
||||
}
|
||||
|
||||
#button_power
|
||||
{
|
||||
position:absolute;
|
||||
left:100px;
|
||||
top:100px;
|
||||
width:100px;
|
||||
height:100px;
|
||||
}
|
||||
|
||||
.button_mode{
|
||||
width:60px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.button_pressed{
|
||||
box-shadow:0px 2px 2px 0px rgba(0, 0, 0, 0.5) inset,0px 2px 2px 0px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.button_unpressed{
|
||||
box-shadow:0px 2px 2px 0px rgba(0, 0, 0, 0.5),0px 2px 2px 0px rgba(255, 255, 255, 0.5) inset;
|
||||
}
|
||||
|
||||
.button_white{
|
||||
color: #e0e0e0;
|
||||
background: #a5cd4e;
|
||||
}
|
||||
|
||||
.button_green {
|
||||
color: #7FFF00;
|
||||
text-shadow: 0 0 10px #6a6767, 0 0 20px #444, 0 0 30px #515151, 0 0 40px #FFFAFC, 0 0 70px #3AFF11, 0 0 80px #45FF11, 0 0 100px #4F4F4F, 0 0 150px #18FF11;
|
||||
}
|
||||
|
||||
.button_red {
|
||||
color: #ff3a3a;
|
||||
background: #a5cd4e;
|
||||
}
|
||||
|
||||
.button_blue {
|
||||
color: #176fff;
|
||||
background: #70c9e3;
|
||||
}
|
||||
|
||||
#div-freq
|
||||
{
|
||||
position:absolute;
|
||||
left: 400px;
|
||||
top:100px;
|
||||
height: 200px;
|
||||
width:1000px;
|
||||
}
|
||||
|
||||
#div-freq > ul > li {
|
||||
display: inline-block;
|
||||
font:normal bold 20px tahoma;
|
||||
text-align:center;
|
||||
width:87px;
|
||||
}
|
||||
|
||||
#freq_disp{
|
||||
border-radius: 5px 5px 5px 5px ;
|
||||
box-shadow:0px 2px 2px 0px rgba(0, 0, 0, 0.5) inset,0px 2px 2px 0px rgba(255, 255, 255, 0.5);
|
||||
background-color: black;
|
||||
width:1000px;
|
||||
padding-top:5px;
|
||||
padding-left:5px;
|
||||
margin-top:10px;
|
||||
margin-bottom:10px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#freq_disp > ul > li {
|
||||
display: inline-block;
|
||||
font:normal bold 14px tahoma;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#freq_disp > ul > li:before{
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#freq_but{
|
||||
width:1000px;
|
||||
margin:0;
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
#freq_but > ul > li {
|
||||
display: inline-block;
|
||||
font:normal bold 14px tahoma;
|
||||
text-align:center;
|
||||
margin-top:5px;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
#freq_but > ul > li:before{
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
margin-top:5px;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
#div-scoketscontrols
|
||||
{
|
||||
position:absolute;
|
||||
left: 1350px;
|
||||
top:825px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
#div-scoketscontrols > p
|
||||
{
|
||||
display: inline-block;
|
||||
font:normal bold 14px tahoma;
|
||||
text-align:center;
|
||||
margin-right:10px;
|
||||
}
|
||||
|
||||
#div-scoketscontrols > p > img
|
||||
{
|
||||
margin-right:5px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
}
|
||||
|
||||
#div-latencymeter
|
||||
{
|
||||
position:absolute;
|
||||
left:1680px;
|
||||
top:840px;
|
||||
}
|