Delete src directory

This commit is contained in:
DJ2LS 2021-08-10 19:09:59 +02:00 committed by GitHub
parent df4d0a0751
commit 6532301916
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 0 additions and 2138 deletions

View file

@ -1,150 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<meta http-equiv="Content-Security-Policy" content="script-src 'self';">-->
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<title>Send & Receive Data</title>
</head>
<body>
<div class="container-fluid">
<div class="container mt-1">
<div class="row mb-1">
<div class="col">
<div class="card text-dark bg-light mb-0 " >
<div class="card-header">Select data </div>
<div class="card-body">
<div class="input-group input-group-sm mb-0">
<input type="file" class="form-control" id="inputGroupFile02">
<label class="input-group-text" for="inputGroupFile02">kB</label>
</div>
</div>
</div>
</div>
<!--col-->
</div>
<!--row-->
<div class="row mb-2">
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">Transmission </div>
<div class="card-body">
<div class="row mb-2">
<div class="col-auto">
<div class="input-group input-group-sm">
<input type="text" class="form-control" style="max-width: 6rem" placeholder="DX Call" id="dxCall" maxlength="6" aria-label="Input group example" aria-describedby="btnGroupAddon">
<button type="button" id="sendPing"class="btn btn-primary">Ping</button>
<span class="input-group-text" id="tnc_running_state">ACK</span>
<span class="input-group-text" id="tnc_running_state">0000 km</span>
<span class="input-group-text" id="tnc_running_state">0 dB</span>
</div>
</div>
</div>
<div class="row">
<div class="col-auto">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Mode</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="datamode">
<option selected value="10">DATAC1</option>
<option value="1">DATAC3</option>
</select>
</div>
</div>
<div class="col-auto">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Frames</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="framesperburst">
<option selected value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
<div class="col">
<div class="input-group input-group-sm">
<button type="button" id="startTransmission"class="btn btn-success">Send</button>
<!--<button type="button" id="stopTNC"class="btn btn-danger">STOP</button>-->
</div>
</div>
</div>
</div>
</div>
<!--col-->
</div>
<!--row-->
</div>
<div class="row">
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">Info </div>
<div class="card-body">
123
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<hr>
</div>
</div>
<!--row-->
</div>
<!--container-->
</div>
<!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------>
<nav class="navbar fixed-bottom navbar-light bg-light">
<div class="container-fluid">
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group btn-group-sm me-2" role="group" aria-label="First group">
<button class="btn btn-secondary" id="ptt_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-broadcast-pin" viewBox="0 0 16 16">
<path d="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707zm2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708zm5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708zm2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Second group">
<button class="btn btn-secondary" id="busy_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cpu" viewBox="0 0 16 16">
<path d="M5 0a.5.5 0 0 1 .5.5V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2A2.5 2.5 0 0 1 14 4.5h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14a2.5 2.5 0 0 1-2.5 2.5v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14A2.5 2.5 0 0 1 2 11.5H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2A2.5 2.5 0 0 1 4.5 2V.5A.5.5 0 0 1 5 0zm-.5 3A1.5 1.5 0 0 0 3 4.5v7A1.5 1.5 0 0 0 4.5 13h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 11.5 3h-7zM5 6.5A1.5 1.5 0 0 1 6.5 5h3A1.5 1.5 0 0 1 11 6.5v3A1.5 1.5 0 0 1 9.5 11h-3A1.5 1.5 0 0 1 5 9.5v-3zM6.5 6a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Second group">
<button class="btn btn-secondary" id="arq_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm me-2 " role="group" aria-label="Third group">
<button class="btn btn-secondary" id="signalling_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-code" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>
</button>
<button class="btn btn-secondary" id="data_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-richtext" viewBox="0 0 16 16">
<path d="M7.5 3.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm-.861 1.542 1.33.886 1.854-1.855a.25.25 0 0 1 .289-.047L11 4.75V7a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 7v-.5s1.54-1.274 1.639-1.208zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>
</button>
</div>
<div class="input-group input-group-sm me-2">
<span class="input-group-text" id="basic-addon1">Bytes/s</span>
<span class="input-group-text" id="basic-addon1">----</span>
</div>
<div class="progress" style="height:100%; width: 200px">
<div class="progress-bar progress-bar-striped bg-primary" id="arq-progress" role="progressbar" style="width: 25%" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">25%</div>
</div>
</div>
</div>
</nav>
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View file

@ -1,755 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self';">-->
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<!-- Waterfall CSS -->
<link rel="stylesheet" type="text/css" href="waterfall/waterfall.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<title>codec2 | FreeDATA</title>
</head>
<body>
<!-- MAIN NAVBAR -->
<nav class="navbar fixed-top bg-dark navbar-dark">
<div class="container-fluid">
<a class="navbar-brand"><b>codec2</b> | FreeDATA</a>
<button class="btn btn-primary" id="openDataModule" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-folder-symlink" viewBox="0 0 16 16">
<path d="m11.798 8.271-3.182 1.97c-.27.166-.616-.036-.616-.372V9.1s-2.571-.3-4 2.4c.571-4.8 3.143-4.8 4-4.8v-.769c0-.336.346-.538.616-.371l3.182 1.969c.27.166.27.576 0 .742z"/>
<path d="m.5 3 .04.87a1.99 1.99 0 0 0-.342 1.311l.637 7A2 2 0 0 0 2.826 14h10.348a2 2 0 0 0 1.991-1.819l.637-7A2 2 0 0 0 13.81 3H9.828a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 6.172 1H2.5a2 2 0 0 0-2 2zm.694 2.09A1 1 0 0 1 2.19 4h11.62a1 1 0 0 1 .996 1.09l-.636 7a1 1 0 0 1-.996.91H2.826a1 1 0 0 1-.995-.91l-.637-7zM6.172 2a1 1 0 0 1 .707.293L7.586 3H2.19c-.24 0-.47.042-.683.12L1.5 2.98a1 1 0 0 1 1-.98h3.672z"/>
</svg>
</button>
</div>
</nav>
<!-- SECONDARY NAVBAR -->
<nav class="navbar bg-light navbar-underline mt-5 shadow">
<div class="container-fluid mt-1">
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">TNC</span>
<input type="text" class="form-control" placeholder="ip adress" id="tnc_adress" value="192.168.178.163" maxlength="17" style="width: 8rem" aria-label="Username" aria-describedby="basic-addon1" >
<span class="input-group-text" id="basic-addon1">:</span>
<input type="text" class="form-control" placeholder="port" value="3000" id="tnc_port" maxlength="5" style="width: 4rem" aria-label="Username" aria-describedby="basic-addon1" >
<button class="btn btn-danger" id="daemon_connection_state" type="button" disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-diagram-3" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
</svg>
</button>
</div>
</div>
</div>
</nav>
<!---------------------------------------------------------------------- MAIN AREA ------------------------------------------------------------>
<!---------------------------------------------------------------------------------------------------------------------------------------------------->
<div class="container mt-3">
<div class="row">
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">
1. AUDIO
</div>
<div class="card-body">
<div class="input-group input-group-sm mb-2">
<span class="input-group-text" id="basic-addon1">RX</span>
<select class="form-select form-select-sm" id="audio_input_selectbox" aria-label=".form-select-sm example">
<!-- <option selected value="3011">USB Interface</option>-->
</select>
</div>
<div class="input-group input-group-sm mb-2">
<span class="input-group-text" id="basic-addon1">TX</span>
<select class="form-select form-select-sm" id="audio_output_selectbox" aria-label=".form-select-sm example">
<!--<option selected value="RTS">USB Interface</option>-->
</select>
</div>
<div class="progress mb-2" style="height: 20px;" >
<div class="progress-bar progress-bar-striped bg-primary" id="rms_level" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<p class="justify-content-center d-flex position-absolute w-100">RX AUDIO LEVEL</p>
</div>
</div>
<div class="card-footer text-muted small">
Select audio device for RX and TX
</div>
</div>
</div>
<div class="col">
<div class="card text-dark bg-light mb-0">
<div class="card-header">
2. RADIO
</div>
<div class="card-body">
<div class="input-group input-group-sm mb-2">
<span class="input-group-text" id="basic-addon1">RIG</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="hamlib_deviceid">
<option selected value="2028">Kenwood TS480</option>
<option value="1">Hamlib Dummy</option>
<option value="2">Hamlib NET rigctl </option>
<option value="4">FLRig FLRig </option>
<option value="5">TRXManager TRXManager 5.7.630+</option>
<option value="6"> Hamlib Dummy No VFO </option>
<option value="1001"> Yaesu FT-847 </option>
<option value="1003"> Yaesu FT-1000D </option>
<option value="1004"> Yaesu MARK-V FT-1000MP </option>
<option value="1005"> Yaesu FT-747GX </option>
<option value="1006"> Yaesu FT-757GX </option>
<option value="1007"> Yaesu FT-757GXII</option>
<option value="1009"> Yaesu FT-767GX </option>
<option value="1010"> Yaesu FT-736R </option>
<option value="1011"> Yaesu FT-840 </option>
<option value="1013"> Yaesu FT-900 </option>
<option value="1014"> Yaesu FT-920 </option>
<option value="1015"> Yaesu FT-890 </option>
<option value="1016"> Yaesu FT-990 </option>
<option value="1017"> Yaesu FRG-100 </option>
<option value="1018"> Yaesu FRG-9600 </option>
<option value="1019"> Yaesu FRG-8800 </option>
<option value="1020"> Yaesu FT-817 </option>
<option value="1021"> Yaesu FT-100 </option>
<option value="1022"> Yaesu FT-857 </option>
<option value="1023"> Yaesu FT-897 </option>
<option value="1024"> Yaesu FT-1000MP </option>
<option value="1025"> Yaesu MARK-V Field FT-1000MP </option>
<option value="1026"> Yaesu VR-5000 </option>
<option value="1027"> Yaesu FT-450 </option>
<option value="1028"> Yaesu FT-950 </option>
<option value="1029"> Yaesu FT-2000 </option>
<option value="1030"> Yaesu FTDX-9000 </option>
<option value="1031"> Yaesu FT-980 </option>
<option value="1032"> Yaesu FTDX-5000 </option>
<option value="1033"> Vertex Standard VX-1700 </option>
<option value="1034"> Yaesu FTDX-1200 </option>
<option value="1035"> Yaesu FT-991 </option>
<option value="1036"> Yaesu FT-891 </option>
<option value="1037"> Yaesu FTDX-3000 </option>
<option value="1038"> Yaesu FT-847UNI </option>
<option value="1039"> Yaesu FT-600 </option>
<option value="1040"> Yaesu FTDX-101D </option>
<option value="1041"> Yaesu FT-818 </option>
<option value="1042"> Yaesu FTDX-10 </option>
<option value="1043"> Yaesu FT-897D </option>
<option value="1044"> Yaesu FTDX-101MP </option>
<option value="2001"> Kenwood TS-50S </option>
<option value="2002"> Kenwood TS-440S </option>
<option value="2003"> Kenwood TS-450S </option>
<option value="2004"> Kenwood TS-570D </option>
<option value="2005"> Kenwood TS-690S </option>
<option value="2006"> Kenwood TS-711 </option>
<option value="2007"> Kenwood TS-790 </option>
<option value="2008"> Kenwood TS-811 </option>
<option value="2009"> Kenwood TS-850 </option>
<option value="2010"> Kenwood TS-870S </option>
<option value="2011"> Kenwood TS-940S </option>
<option value="2012"> Kenwood TS-950S </option>
<option value="2013"> Kenwood TS-950SDX </option>
<option value="2014"> Kenwood TS-2000 </option>
<option value="2015"> Kenwood R-5000 </option>
<option value="2016"> Kenwood TS-570S </option>
<option value="2017"> Kenwood TH-D7A </option>
<option value="2019"> Kenwood TH-F6A </option>
<option value="2020"> Kenwood TH-F7E </option>
<option value="2021"> Elecraft K2 </option>
<option value="2022"> Kenwood TS-930 </option>
<option value="2023"> Kenwood TH-G71 </option>
<option value="2024"> Kenwood TS-680S </option>
<option value="2025"> Kenwood TS-140S </option>
<option value="2026"> Kenwood TM-D700 </option>
<option value="2027"> Kenwood TM-V7 </option>
<option value="2028"> Kenwood TS-480 </option>
<option value="2029"> Elecraft K3 </option>
<option value="2030"> Kenwood TRC-80 </option>
<option value="2031"> Kenwood TS-590S </option>
<option value="2032"> SigFox Transfox </option>
<option value="2033"> Kenwood TH-D72A </option>
<option value="2034"> Kenwood TM-D710(G) </option>
<option value="2036"> FlexRadio 6xxx </option>
<option value="2037"> Kenwood TS-590SG </option>
<option value="2038"> Elecraft XG3 </option>
<option value="2039"> Kenwood TS-990s </option>
<option value="2040"> OpenHPSDR PiHPSDR </option>
<option value="2041"> Kenwood TS-890S </option>
<option value="2042"> Kenwood TH-D74 </option>
<option value="2043"> Elecraft K3S </option>
<option value="2044"> Elecraft KX2 </option>
<option value="2045"> Elecraft KX3 </option>
<option value="2046"> Hilberling PT-8000A </option>
<option value="2047"> Elecraft K4 </option>
<option value="2048"> FlexRadio/ANAN PowerSDR/Thetis </option>
<option value="2049"> Malachite DSP </option>
<option value="3002"> Icom IC-1275 </option>
<option value="3003"> Icom IC-271 </option>
<option value="3004"> Icom IC-275 </option>
<option value="3006"> Icom IC-471 </option>
<option value="3007"> Icom IC-475 </option>
<option value="3009"> Icom IC-706 </option>
<option value="3010"> Icom IC-706MkII </option>
<option value="3011"> Icom IC-706MkIIG </option>
<option value="3012"> Icom IC-707 </option>
<option value="3013"> Icom IC-718 </option>
<option value="3014"> Icom IC-725 </option>
<option value="3015"> Icom IC-726 </option>
<option value="3016"> Icom IC-728 </option>
<option value="3017"> Icom IC-729 </option>
<option value="3019"> Icom IC-735 </option>
<option value="3020"> Icom IC-736 </option>
<option value="3021"> Icom IC-737 </option>
<option value="3022"> Icom IC-738 </option>
<option value="3023"> Icom IC-746 </option>
<option value="3024"> Icom IC-751 </option>
<option value="3026"> Icom IC-756 </option>
<option value="3027"> Icom IC-756PRO </option>
<option value="3028"> Icom IC-761 </option>
<option value="3029"> Icom IC-765 </option>
<option value="3030"> Icom IC-775 </option>
<option value="3031"> Icom IC-781 </option>
<option value="3032"> Icom IC-820H </option>
<option value="3034"> Icom IC-821H </option>
<option value="3035"> Icom IC-970 </option>
<option value="3036"> Icom IC-R10 </option>
<option value="3037"> Icom IC-R71 </option>
<option value="3038"> Icom IC-R72 </option>
<option value="3039"> Icom IC-R75 </option>
<option value="3040"> Icom IC-R7000 </option>
<option value="3041"> Icom IC-R7100 </option>
<option value="3042"> Icom ICR-8500 </option>
<option value="3043"> Icom IC-R9000 </option>
<option value="3044"> Icom IC-910 </option>
<option value="3045"> Icom IC-78 </option>
<option value="3046"> Icom IC-746PRO </option>
<option value="3047"> Icom IC-756PROII </option>
<option value="3051">Ten-Tec Omni VI Plus </option>
<option value="3052"> Optoelectronics OptoScan535 </option>
<option value="3053"> Optoelectronics OptoScan456 </option>
<option value="3054"> Icom IC ID-1 </option>
<option value="3055"> Icom IC-703 </option>
<option value="3056"> Icom IC-7800 </option>
<option value="3057"> Icom IC-756PROIII </option>
<option value="3058"> Icom IC-R20 </option>
<option value="3060"> Icom IC-7000 </option>
<option value="3061"> Icom IC-7200 </option>
<option value="3062"> Icom IC-7700 </option>
<option value="3063"> Icom IC-7600 </option>
<option value="3064"> Ten-Tec Delta II </option>
<option value="3065"> Icom IC-92D </option>
<option value="3066"> Icom IC-R9500 </option>
<option value="3067"> Icom IC-7410 </option>
<option value="3068"> Icom IC-9100 </option>
<option value="3069"> Icom IC-RX7 </option>
<option value="3070"> Icom IC-7100 </option>
<option value="3071"> Icom ID-5100 </option>
<option value="3072"> Icom IC-2730 </option>
<option value="3073"> Icom IC-7300 </option>
<option value="3074"> Microtelecom Perseus </option>
<option value="3075"> Icom IC-785x </option>
<option value="3076"> Xeigu X108G </option>
<option value="3077"> Icom IC-R6 </option>
<option value="3078"> Icom IC-7610 </option>
<option value="3079"> Icom IC-R8600 </option>
<option value="3080"> Icom IC-R30 </option>
<option value="3081"> Icom IC-9700 </option>
<option value="3082"> Icom ID-4100 </option>
<option value="3083"> Icom ID-31 </option>
<option value="3084"> Icom ID-51 </option>
<option value="3085"> Icom IC-705 </option>
<option value="4001"> Icom IC-PCR1000 </option>
<option value="4002"> Icom IC-PCR100 </option>
<option value="4003"> Icom IC-PCR1500 </option>
<option value="4004"> Icom IC-PCR2500 </option>
<option value="5001"> AOR AR8200 </option>
<option value="5002"> AOR AR8000 </option>
<option value="5003"> AOR AR7030 </option>
<option value="5004"> AOR AR5000 </option>
<option value="5005"> AOR AR3030 </option>
<option value="5006"> AOR AR3000A </option>
<option value="5008"> AOR AR2700 </option>
<option value="5013"> AOR AR8600 </option>
<option value="5014"> AOR AR5000A </option>
<option value="5015"> AOR AR7030 Plus </option>
<option value="5016"> AOR SR2200 </option>
<option value="6005"> JRC NRD-525 </option>
<option value="6006"> JRC NRD-535D </option>
<option value="6007"> JRC NRD-545 DSP </option>
<option value="8001"> Uniden BC780xlt </option>
<option value="8002"> Uniden BC245xlt </option>
<option value="8003"> Uniden BC895xlt </option>
<option value="8004"> Radio Shack PRO-2052 </option>
<option value="8006"> Uniden BC250D </option>
<option value="8010"> Uniden BCD-396T </option>
<option value="8011"> Uniden BCD-996T </option>
<option value="8012"> Uniden BC898T </option>
<option value="9002"> Drake R-8A </option>
<option value="9003"> Drake R-8B </option>
<option value="10004"> Lowe HF-235 </option>
<option value="11003">Racal RA6790/GM </option>
<option value="11005"> Racal RA3702 </option>
<option value="12004"> Watkins-Johnson WJ-8888 </option>
<option value="14002"> Skanti TRP8000 </option>
<option value="14004"> Skanti TRP 8255 S R </option>
<option value="15001"> Winradio WR-1000 </option>
<option value="15002"> Winradio WR-1500 </option>
<option value="15003"> Winradio WR-1550 </option>
<option value="15004"> Winradio WR-3100 </option>
<option value="15005"> Winradio WR-3150 </option>
<option value="15006">Winradio WR-3500 </option>
<option value="15007"> Winradio WR-3700 </option>
<option value="15009"> Winradio WR-G313 </option>
<option value="16001"> Ten-Tec TT-550 </option>
<option value="16002"> Ten-Tec TT-538 Jupiter </option>
<option value="16003"> Ten-Tec RX-320 </option>
<option value="16004"> Ten-Tec RX-340 </option>
<option value="16005"> Ten-Tec RX-350 </option>
<option value="16007"> Ten-Tec TT-516 Argonaut V </option>
<option value="16008"> Ten-Tec TT-565 Orion </option>
<option value="16009"> Ten-Tec TT-585 Paragon </option>
<option value="16011"> Ten-Tec TT-588 Omni VII </option>
<option value="16012"> Ten-Tec RX-331 </option>
<option value="16013"> Ten-Tec TT-599 Eagle </option>
<option value="17001"> Alinco DX-77 </option>
<option value="17002"> Alinco DX-SR8 </option>
<option value="18001"> Kachina 505DSP </option>
<option value="22001"> TAPR DSP-10 </option>
<option value="23001"> Flex-radio SDR-1000 </option>
<option value="23003"> DTTS Microwave Society DttSP IPC </option>
<option value="23004"> DTTS Microwave Society DttSP UDP </option>
<option value="24001"> RFT EKD-500 </option>
<option value="25001"> Elektor Elektor 3/04 </option>
<option value="25002"> SAT-Schneider DRT1 </option>
<option value="25003"> Coding Technologies Digital World Traveller</option>
<option value="25006"> AmQRP DDS-60 </option>
<option value="25007"> Elektor Elektor SDR-USB </option>
<option value="25008"> mRS miniVNA </option>
<option value="25009"> SoftRock Si570 AVR-USB </option>
<option value="25011"> KTH-SDR kit Si570 PIC-USB </option>
<option value="25012"> FiFi FiFi-SDR </option>
<option value="25013"> AMSAT-UK FUNcube Dongle </option>
<option value="25014"> N2ADR HiQSDR </option>
<option value="25015"> Funkamateur FA-SDR </option>
<option value="25016"> AE9RB Si570 Peaberry V1 </option>
<option value="25017"> AE9RB Si570 Peaberry V2 </option>
<option value="25018"> AMSAT-UK FUNcube Dongle Pro+ </option>
<option value="25019"> HobbyPCB RS-HFIQ </option>
<option value="26001"> Video4Linux SW/FM radio </option>
<option value="26002"> Video4Linux2 SW/FM radio </option>
<option value="27001"> Rohde&Schwarz ESMC </option>
<option value="27002"> Rohde&Schwarz EB200 </option>
<option value="27003"> Rohde&Schwarz XK2100 </option>
<option value="28001"> Philips/Simoco PRM8060 </option>
<option value="29001"> ADAT www.adat.ch ADT-200A </option>
<option value="30001"> Icom IC-M700PRO </option>
<option value="30002"> Icom IC-M802 </option>
<option value="30003"> Icom IC-M710 </option>
<option value="30004"> Icom IC-M803 </option>
<option value="31001"> Dorji DRA818V </option>
<option value="31002"> Dorji DRA818U </option>
<option value="32001"> Barrett 2050 </option>
<option value="32002"> Barrett 950 </option>
<option value="33001"> ELAD FDM-DUO </option>
</select>
</div>
<div class="input-group input-group-sm mb-2">
<span class="input-group-text" id="basic-addon1">PTT</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="hamlib_ptt">
<option selected value="RTS">RTS</option>
<option value="2">DTR</option>
</select>
</div>
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Port</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="hamlib_deviceport">
<option selected value="/dev/ttyUSB0">/dev/ttyUSB0</option>
<option value="/dev/ttyUSB1">/dev/ttyUSB1</option>
</select>
<span class="input-group-text" id="basic-addon1">Speed</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="hamlib_serialspeed">
<option value="1200">1200</option>
<option value="2400">2400</option>
<option value="4800">4800</option>
<option selected value="9600">9600</option>
<option value="14400">14400</option>
<option value="19200">19200</option>
<option value="28800">28800</option>
<option value="38400">38400</option>
<option value="57600">57600</option>
<option value="115200">115200</option>
</select>
</div>
</div>
<div class="card-footer text-muted small">
Select radio model and PTT type
</div>
</div>
</div>
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">3. TNC</div>
<div class="card-body">
<!--
<div class="input-group input-group-sm mb-2">
<button type="button" id="startTNC"class="btn btn-success">Start</button>
<span class="input-group-text" id="tnc_running_state">---</span>
<button type="button" id="stopTNC"class="btn btn-danger">STOP</button>
</div>
-->
<div class="container">
<div class="row">
<div class="col-md-auto">
TNC
</div>
<div class="col">
<div class="input-group input-group-sm mb-2">
<button type="button" id="startTNC"class="btn btn-success">Start</button>
<span class="input-group-text" id="tnc_running_state" style="width: 7rem">---</span>
<button type="button" id="stopTNC"class="btn btn-danger">STOP</button>
</div>
</div>
</div>
<div class="row">
<div class="col-md-auto">
CPU
</div>
<div class="col">
<div class="progress" style="height: 20px;" >
<div class="progress-bar progress-bar-striped bg-primary" id="progressbar_cpu" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<p class="justify-content-center d-flex position-absolute w-100" id="progressbar_cpu_value"></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-auto">
RAM
</div>
<div class="col">
<div class="progress" style="height: 20px;" >
<div class="progress-bar progress-bar-striped bg-primary" id="progressbar_ram" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<p class="justify-content-center d-flex position-absolute w-100" id="progressbar_ram_value"></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-auto">
TOE
</div>
<div class="col-md-auto">
<p class="text-start mb-0" id="toe"></p>
</div>
</div>
</div>
</div>
<div class="card-footer text-muted small">
TNC settings
</div>
</div>
</div>
</div>
</div>
<hr>
<div class="container mt-2">
<div class="row">
<div class="col">
<div class="card text-dark bg-light mb-1">
<div class="card-header">MY STATION</div>
<div class="card-body">
<div class="row">
<div class="col-md-auto">
<div class="input-group input-group-sm mb-0">
<input type="text" class="form-control" style="max-width: 6rem" placeholder="callsign" id="myCall" maxlength="6" aria-label="Input group example" aria-describedby="btnGroupAddon">
<button class="btn btn-success" id="saveMyCall" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
</svg>
</button>
</div>
</div>
<div class="col-md-auto">
<div class="input-group input-group-sm mb-0">
<input type="text" class="form-control mr-1" style="max-width: 6rem" placeholder="locator" id="myGrid" maxlength="6" aria-label="Input group example" aria-describedby="btnGroupAddon">
<button class="btn btn-success" id="saveMyGrid" type="button" >
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
</svg>
</button>
</div>
</div>
</div>
<!-- end of row-->
</div>
</div>
</div>
<div class="col">
<div class="card text-dark bg-light mb-1">
<div class="card-header">PING & CQ</div>
<div class="card-body">
<div class="row">
<div class="col-md-auto">
<div class="input-group input-group-sm mb-0">
<span class="input-group-text">Ping</span>
<input type="text" class="form-control" style="max-width: 6rem" placeholder="DXcall" id="dxCall" maxlength="6" aria-label="Input group example" aria-describedby="btnGroupAddon">
<button class="btn btn-success" id="sendPing" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
</svg>
</button>
<span class="input-group-text text-secondary" id="pingACK">ACK</span>
<span class="input-group-text" id="pingDistance">0000 km</span>
<span class="input-group-text" id="pingDB">0 dB</span>
</div>
</div>
<div class="col-md-auto">
<div class="input-group input-group-sm mb-0">
<button class="btn btn-success" id="sendCQ" type="button" >CQ CQ CQ</button>
</div>
</div>
</div>
<!-- end of row-->
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="card text-dark bg-light mb-1" style="height: 360px">
<div class="card-header">
<div class="btn-group btn-group-sm" role="group" aria-label="waterfall-scatter-switch toggle button group">
<input type="radio" class="btn-check" name="waterfall-scatter-switch" id="waterfall-scatter-switch1" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="waterfall-scatter-switch1">WATERFALL</label>
<input type="radio" class="btn-check" name="waterfall-scatter-switch" id="waterfall-scatter-switch2" autocomplete="off">
<label class="btn btn-outline-secondary" for="waterfall-scatter-switch2">SCATTER</label>
</div>
</div>
<!--<div class="card-body">-->
<canvas id="waterfall" style="position: relative; z-index: 2;"></canvas>
<canvas id="scatter" style="position: relative; z-index: 1;"></canvas>
<!-- </div>-->
</div>
</div>
<div class="col">
<div class="card text-dark bg-light mb-1" style="height: 360px">
<div class="card-header">HEARD STATIONS</div>
<div class="card-body">
<!-- START OF TABLE FOR HEARD STATIONS -->
<table class="table">
<thead>
<tr>
<th scope="col">Time</th>
<th scope="col">DXCall</th>
<th scope="col">DXGrid</th>
<th scope="col">Distance</th>
<th scope="col">Type</th>
<th scope="col">SNR</th>
</tr>
</thead>
<tbody id="heardstations">
<!--
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
-->
</tbody>
</table>
<!-- END OF HEARD STATIONS TABLE -->
</div>
</div>
</div>
</div>
</div>
</div>
<!---------------------------------------------------------------------- DATA SIDEBAR ------------------------------------------------------------>
<div id="mySidebar" class="sidebar shadow-lg rounded">
<div class="container-fluid">
<div class="container mt-1">
<div class="row mb-1">
<div class="col">
<div class="card text-dark bg-light mb-0 " >
<div class="card-header">DX Station </div>
<div class="card-body">
<div class="input-group input-group-sm mb-0">
<span class="input-group-text">Ping</span>
<input type="text" class="form-control" style="max-width: 6rem" placeholder="DXcall" id="dxCall" maxlength="6" aria-label="Input group example" aria-describedby="btnGroupAddon">
<button class="btn btn-success" id="sendPing" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check2" viewBox="0 0 16 16">
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
</svg>
</button>
<span class="input-group-text text-secondary" id="pingACK">ACK</span>
<span class="input-group-text" id="pingDistance">0000 km</span>
<span class="input-group-text" id="pingDB">0 dB</span>
</div>
</div>
</div>
</div>
<!--col-->
</div>
<!--row-->
<div class="row mb-1">
<div class="col">
<div class="card text-dark bg-light mb-0 " >
<div class="card-header">Select data </div>
<div class="card-body">
<div class="input-group input-group-sm mb-0">
<input type="file" class="form-control" id="inputGroupFile02">
<label class="input-group-text" for="inputGroupFile02">kB</label>
</div>
</div>
</div>
</div>
<!--col-->
</div>
<!--row-->
<div class="row mb-2">
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">Transmission </div>
<div class="card-body">
<div class="row">
<div class="col-auto">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Mode</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="datamode">
<option selected value="10">DATAC1</option>
<option value="1">DATAC3</option>
</select>
</div>
</div>
<div class="col-auto">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Frames</span>
<select class="form-select form-select-sm" aria-label=".form-select-sm example" id="framesperburst">
<option selected value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!--col-->
</div>
<!--row-->
</div>
<div class="row mb-2">
<div class="col">
<button type="button" id="startTransmission" class="btn btn-success" style="width:100%">START TRANSMISSION</button>
</div>
<div class="col-md-auto">
<button type="button" id="stopTNC" class="btn btn-danger" style="width:100%" disabled>STOP</button>
</div>
</div>
<div class="row">
<div class="col">
<div class="card text-dark bg-light mb-0" >
<div class="card-header">Info </div>
<div class="card-body">
123
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<hr>
</div>
</div>
<!--row-->
</div>
<!--container-->
</div>
</div>
<!---------------------------------------------------------------------- FOOTER AREA ------------------------------------------------------------>
<nav class="navbar fixed-bottom navbar-light bg-light">
<div class="container-fluid">
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group btn-group-sm me-2" role="group" aria-label="First group">
<button class="btn btn-secondary" id="ptt_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-broadcast-pin" viewBox="0 0 16 16">
<path d="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707zm2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708zm5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708zm2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Second group">
<button class="btn btn-secondary" id="busy_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cpu" viewBox="0 0 16 16">
<path d="M5 0a.5.5 0 0 1 .5.5V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2h1V.5a.5.5 0 0 1 1 0V2A2.5 2.5 0 0 1 14 4.5h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14v1h1.5a.5.5 0 0 1 0 1H14a2.5 2.5 0 0 1-2.5 2.5v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14h-1v1.5a.5.5 0 0 1-1 0V14A2.5 2.5 0 0 1 2 11.5H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2v-1H.5a.5.5 0 0 1 0-1H2A2.5 2.5 0 0 1 4.5 2V.5A.5.5 0 0 1 5 0zm-.5 3A1.5 1.5 0 0 0 3 4.5v7A1.5 1.5 0 0 0 4.5 13h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 11.5 3h-7zM5 6.5A1.5 1.5 0 0 1 6.5 5h3A1.5 1.5 0 0 1 11 6.5v3A1.5 1.5 0 0 1 9.5 11h-3A1.5 1.5 0 0 1 5 9.5v-3zM6.5 6a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Second group">
<button class="btn btn-secondary" id="arq_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
</svg>
</button>
</div>
<div class="btn-group btn-group-sm" role="group" aria-label="Third group">
<button class="btn btn-secondary" id="signalling_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-code" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>
</button>
<button class="btn btn-secondary" id="data_state" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-richtext" viewBox="0 0 16 16">
<path d="M7.5 3.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm-.861 1.542 1.33.886 1.854-1.855a.25.25 0 0 1 .289-.047L11 4.75V7a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 7v-.5s1.54-1.274 1.639-1.208zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>
</button>
</div>
</div>
<div class="container-fluid" style="width:30rem">
<div class="input-group input-group-sm">
<span class="input-group-text" id="basic-addon1">Freq</span>
<span class="input-group-text" id="frequency">---</span>
<span class="input-group-text" id="basic-addon1">Mode</span>
<span class="input-group-text" id="mode">---</span>
<span class="input-group-text" id="basic-addon1">BW</span>
<span class="input-group-text" id="bandwith">---</span>
</div>
</div>
</div>
</nav>
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="../node_modules/chart.js/dist/chart.min.js"></script>
<!--<script src="../ui.js"></script>-->
<!-- WATERFALL -->
<script src="waterfall/colormap.js"></script>
<script src="waterfall/spectrum.js"></script>
<script src="waterfall/spectrogram.js"></script>
<!--<script src="waterfall/script.js"></script>-->
</body>
</html>

View file

@ -1,37 +0,0 @@
/**
* disable scrolling in main window
*/
body {
padding-right: 0px !important;
overflow-y: hidden !important;
}
/**
* Progress bars with centered text
*/
.progress {
position: relative;
}
.progress span {
position: absolute;
display: block;
width: 100%;
color: black;
}
/* The sidebar menu */
/* https://www.w3schools.com/howto/howto_js_collapse_sidebar.asp*/
.sidebar {
height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1000; /* Stay on top */
top: 0;
/*left: 1220px;*/
right: 0;
background-color: #fff; /* White*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidebar */
}

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Jeppe Ledet-Pedersen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,13 +0,0 @@
********************************
HTML Canvas/WebSockets Waterfall
********************************
This is a small experiment to create a waterfall plot with HTML Canvas and WebSockets to stream live FFT data from an SDR:
.. image:: img/waterfall.png
``spectrum.js`` contains the main JavaScript source code for the plot, while ``colormap.js`` contains colormaps generated using ``make_colormap.py``.
``index.html``, ``style.css``, ``script.js`` contain an example page that receives FFT data on a WebSocket and plots it on the waterfall plot.
``server.py`` contains a example `Bottle <https://bottlepy.org/docs/dev/>`_ and `gevent-websocket <https://pypi.org/project/gevent-websocket/>`_ server that broadcasts FFT data to connected clients. The FFT data is generated using `GNU radio <https://www.gnuradio.org/>`_ using a USRP but it should be fairly easy to change it to a different SDR.

View file

@ -1,8 +0,0 @@
var turbo = [[48, 18, 59], [50, 21, 67], [51, 24, 74], [52, 27, 81], [53, 30, 88], [54, 33, 95], [55, 36, 102], [56, 39, 109], [57, 42, 115], [58, 45, 121], [59, 47, 128], [60, 50, 134], [61, 53, 139], [62, 56, 145], [63, 59, 151], [63, 62, 156], [64, 64, 162], [65, 67, 167], [65, 70, 172], [66, 73, 177], [66, 75, 181], [67, 78, 186], [68, 81, 191], [68, 84, 195], [68, 86, 199], [69, 89, 203], [69, 92, 207], [69, 94, 211], [70, 97, 214], [70, 100, 218], [70, 102, 221], [70, 105, 224], [70, 107, 227], [71, 110, 230], [71, 113, 233], [71, 115, 235], [71, 118, 238], [71, 120, 240], [71, 123, 242], [70, 125, 244], [70, 128, 246], [70, 130, 248], [70, 133, 250], [70, 135, 251], [69, 138, 252], [69, 140, 253], [68, 143, 254], [67, 145, 254], [66, 148, 255], [65, 150, 255], [64, 153, 255], [62, 155, 254], [61, 158, 254], [59, 160, 253], [58, 163, 252], [56, 165, 251], [55, 168, 250], [53, 171, 248], [51, 173, 247], [49, 175, 245], [47, 178, 244], [46, 180, 242], [44, 183, 240], [42, 185, 238], [40, 188, 235], [39, 190, 233], [37, 192, 231], [35, 195, 228], [34, 197, 226], [32, 199, 223], [31, 201, 221], [30, 203, 218], [28, 205, 216], [27, 208, 213], [26, 210, 210], [26, 212, 208], [25, 213, 205], [24, 215, 202], [24, 217, 200], [24, 219, 197], [24, 221, 194], [24, 222, 192], [24, 224, 189], [25, 226, 187], [25, 227, 185], [26, 228, 182], [28, 230, 180], [29, 231, 178], [31, 233, 175], [32, 234, 172], [34, 235, 170], [37, 236, 167], [39, 238, 164], [42, 239, 161], [44, 240, 158], [47, 241, 155], [50, 242, 152], [53, 243, 148], [56, 244, 145], [60, 245, 142], [63, 246, 138], [67, 247, 135], [70, 248, 132], [74, 248, 128], [78, 249, 125], [82, 250, 122], [85, 250, 118], [89, 251, 115], [93, 252, 111], [97, 252, 108], [101, 253, 105], [105, 253, 102], [109, 254, 98], [113, 254, 95], [117, 254, 92], [121, 254, 89], [125, 255, 86], [128, 255, 83], [132, 255, 81], [136, 255, 78], [139, 255, 75], [143, 255, 73], [146, 255, 71], [150, 254, 68], [153, 254, 66], [156, 254, 64], [159, 253, 63], [161, 253, 61], [164, 252, 60], [167, 252, 58], [169, 251, 57], [172, 251, 56], [175, 250, 55], [177, 249, 54], [180, 248, 54], [183, 247, 53], [185, 246, 53], [188, 245, 52], [190, 244, 52], [193, 243, 52], [195, 241, 52], [198, 240, 52], [200, 239, 52], [203, 237, 52], [205, 236, 52], [208, 234, 52], [210, 233, 53], [212, 231, 53], [215, 229, 53], [217, 228, 54], [219, 226, 54], [221, 224, 55], [223, 223, 55], [225, 221, 55], [227, 219, 56], [229, 217, 56], [231, 215, 57], [233, 213, 57], [235, 211, 57], [236, 209, 58], [238, 207, 58], [239, 205, 58], [241, 203, 58], [242, 201, 58], [244, 199, 58], [245, 197, 58], [246, 195, 58], [247, 193, 58], [248, 190, 57], [249, 188, 57], [250, 186, 57], [251, 184, 56], [251, 182, 55], [252, 179, 54], [252, 177, 54], [253, 174, 53], [253, 172, 52], [254, 169, 51], [254, 167, 50], [254, 164, 49], [254, 161, 48], [254, 158, 47], [254, 155, 45], [254, 153, 44], [254, 150, 43], [254, 147, 42], [254, 144, 41], [253, 141, 39], [253, 138, 38], [252, 135, 37], [252, 132, 35], [251, 129, 34], [251, 126, 33], [250, 123, 31], [249, 120, 30], [249, 117, 29], [248, 114, 28], [247, 111, 26], [246, 108, 25], [245, 105, 24], [244, 102, 23], [243, 99, 21], [242, 96, 20], [241, 93, 19], [240, 91, 18], [239, 88, 17], [237, 85, 16], [236, 83, 15], [235, 80, 14], [234, 78, 13], [232, 75, 12], [231, 73, 12], [229, 71, 11], [228, 69, 10], [226, 67, 10], [225, 65, 9], [223, 63, 8], [221, 61, 8], [220, 59, 7], [218, 57, 7], [216, 55, 6], [214, 53, 6], [212, 51, 5], [210, 49, 5], [208, 47, 5], [206, 45, 4], [204, 43, 4], [202, 42, 4], [200, 40, 3], [197, 38, 3], [195, 37, 3], [193, 35, 2], [190, 33, 2], [188, 32, 2], [185, 30, 2], [183, 29, 2], [180, 27, 1], [178, 26, 1], [175, 24, 1], [172, 23, 1], [169, 22, 1], [167, 20, 1], [164, 19, 1], [161, 18, 1], [158, 16, 1], [155, 15, 1], [152, 14, 1], [149, 13, 1], [146, 11, 1], [142, 10, 1], [139, 9, 2], [136, 8, 2], [133, 7, 2], [129, 6, 2], [126, 5, 2], [122, 4, 3]]
var fosphor = [[6, 0, 13], [7, 0, 14], [7, 0, 15], [7, 0, 16], [7, 0, 17], [7, 0, 18], [7, 0, 18], [7, 0, 19], [7, 0, 20], [7, 0, 21], [7, 0, 22], [7, 0, 23], [7, 0, 24], [7, 0, 25], [7, 0, 26], [6, 0, 27], [6, 0, 28], [6, 0, 29], [5, 0, 30], [5, 0, 31], [5, 0, 32], [4, 0, 33], [4, 0, 34], [3, 0, 35], [3, 0, 36], [2, 0, 36], [2, 0, 37], [1, 0, 38], [0, 0, 39], [0, 0, 40], [0, 1, 41], [0, 2, 42], [0, 3, 43], [0, 4, 44], [0, 5, 45], [0, 5, 46], [0, 6, 47], [0, 7, 48], [0, 8, 49], [0, 9, 50], [0, 10, 51], [0, 12, 52], [0, 13, 53], [0, 14, 54], [0, 15, 55], [0, 16, 56], [0, 18, 56], [0, 19, 57], [0, 20, 58], [0, 22, 59], [0, 23, 60], [0, 24, 61], [0, 26, 62], [0, 27, 63], [0, 29, 64], [0, 31, 65], [0, 32, 66], [0, 34, 67], [0, 36, 68], [0, 37, 69], [0, 39, 70], [0, 41, 71], [0, 43, 72], [0, 44, 73], [0, 46, 74], [0, 48, 74], [0, 50, 75], [0, 52, 76], [0, 54, 77], [0, 56, 78], [0, 58, 79], [0, 60, 80], [0, 63, 81], [0, 65, 82], [0, 67, 83], [0, 69, 84], [0, 71, 85], [0, 74, 86], [0, 76, 87], [0, 79, 88], [0, 81, 89], [0, 83, 90], [0, 86, 91], [0, 88, 92], [0, 91, 93], [0, 94, 94], [0, 94, 93], [0, 95, 92], [0, 96, 91], [0, 97, 90], [0, 98, 90], [0, 99, 89], [0, 100, 88], [0, 101, 87], [0, 102, 86], [0, 103, 85], [0, 104, 84], [0, 105, 83], [0, 106, 82], [0, 107, 80], [0, 108, 79], [0, 109, 78], [0, 110, 77], [0, 111, 75], [0, 112, 74], [0, 112, 73], [0, 113, 71], [0, 114, 70], [0, 115, 69], [0, 116, 67], [0, 117, 66], [0, 118, 64], [0, 119, 62], [0, 120, 61], [0, 121, 59], [0, 122, 57], [0, 123, 56], [0, 124, 54], [0, 125, 52], [0, 126, 50], [0, 127, 48], [0, 128, 47], [0, 129, 45], [0, 130, 43], [0, 131, 41], [0, 132, 39], [0, 132, 37], [0, 133, 35], [0, 134, 32], [0, 135, 30], [0, 136, 28], [0, 137, 26], [0, 138, 24], [0, 139, 21], [0, 140, 19], [0, 141, 17], [0, 142, 14], [0, 143, 12], [0, 144, 9], [0, 145, 7], [0, 146, 4], [0, 147, 2], [1, 148, 0], [3, 149, 0], [6, 150, 0], [9, 150, 0], [12, 151, 0], [14, 152, 0], [17, 153, 0], [20, 154, 0], [23, 155, 0], [26, 156, 0], [29, 157, 0], [32, 158, 0], [35, 159, 0], [38, 160, 0], [41, 161, 0], [44, 162, 0], [47, 163, 0], [50, 164, 0], [53, 165, 0], [57, 166, 0], [60, 167, 0], [63, 168, 0], [66, 169, 0], [70, 170, 0], [73, 170, 0], [77, 171, 0], [80, 172, 0], [84, 173, 0], [87, 174, 0], [91, 175, 0], [94, 176, 0], [98, 177, 0], [102, 178, 0], [105, 179, 0], [109, 180, 0], [113, 181, 0], [117, 182, 0], [120, 183, 0], [124, 184, 0], [128, 185, 0], [132, 186, 0], [136, 187, 0], [140, 188, 0], [144, 188, 0], [148, 189, 0], [152, 190, 0], [156, 191, 0], [161, 192, 0], [165, 193, 0], [169, 194, 0], [173, 195, 0], [178, 196, 0], [182, 197, 0], [186, 198, 0], [191, 199, 0], [195, 200, 0], [200, 201, 0], [202, 199, 0], [203, 197, 0], [204, 194, 0], [205, 191, 0], [206, 189, 0], [207, 186, 0], [208, 183, 0], [208, 180, 0], [209, 177, 0], [210, 174, 0], [211, 172, 0], [212, 169, 0], [213, 166, 0], [214, 163, 0], [215, 159, 0], [216, 156, 0], [217, 153, 0], [218, 150, 0], [219, 147, 0], [220, 144, 0], [221, 140, 0], [222, 137, 0], [223, 134, 0], [224, 130, 0], [225, 127, 0], [226, 123, 0], [226, 120, 0], [227, 116, 0], [228, 113, 0], [229, 109, 0], [230, 106, 0], [231, 102, 0], [232, 98, 0], [233, 95, 0], [234, 91, 0], [235, 87, 0], [236, 83, 0], [237, 79, 0], [238, 76, 0], [239, 72, 0], [240, 68, 0], [241, 64, 0], [242, 60, 0], [243, 56, 0], [244, 52, 0], [245, 47, 0], [246, 43, 0], [246, 39, 0], [247, 35, 0], [248, 31, 0], [249, 26, 0], [250, 22, 0], [251, 18, 0], [252, 13, 0], [253, 9, 0], [254, 4, 0], [255, 0, 0]]
var viridis = [[68, 1, 84], [68, 2, 86], [69, 4, 87], [69, 5, 89], [70, 7, 90], [70, 8, 92], [70, 10, 93], [70, 11, 94], [71, 13, 96], [71, 14, 97], [71, 16, 99], [71, 17, 100], [71, 19, 101], [72, 20, 103], [72, 22, 104], [72, 23, 105], [72, 24, 106], [72, 26, 108], [72, 27, 109], [72, 28, 110], [72, 29, 111], [72, 31, 112], [72, 32, 113], [72, 33, 115], [72, 35, 116], [72, 36, 117], [72, 37, 118], [72, 38, 119], [72, 40, 120], [72, 41, 121], [71, 42, 122], [71, 44, 122], [71, 45, 123], [71, 46, 124], [71, 47, 125], [70, 48, 126], [70, 50, 126], [70, 51, 127], [70, 52, 128], [69, 53, 129], [69, 55, 129], [69, 56, 130], [68, 57, 131], [68, 58, 131], [68, 59, 132], [67, 61, 132], [67, 62, 133], [66, 63, 133], [66, 64, 134], [66, 65, 134], [65, 66, 135], [65, 68, 135], [64, 69, 136], [64, 70, 136], [63, 71, 136], [63, 72, 137], [62, 73, 137], [62, 74, 137], [62, 76, 138], [61, 77, 138], [61, 78, 138], [60, 79, 138], [60, 80, 139], [59, 81, 139], [59, 82, 139], [58, 83, 139], [58, 84, 140], [57, 85, 140], [57, 86, 140], [56, 88, 140], [56, 89, 140], [55, 90, 140], [55, 91, 141], [54, 92, 141], [54, 93, 141], [53, 94, 141], [53, 95, 141], [52, 96, 141], [52, 97, 141], [51, 98, 141], [51, 99, 141], [50, 100, 142], [50, 101, 142], [49, 102, 142], [49, 103, 142], [49, 104, 142], [48, 105, 142], [48, 106, 142], [47, 107, 142], [47, 108, 142], [46, 109, 142], [46, 110, 142], [46, 111, 142], [45, 112, 142], [45, 113, 142], [44, 113, 142], [44, 114, 142], [44, 115, 142], [43, 116, 142], [43, 117, 142], [42, 118, 142], [42, 119, 142], [42, 120, 142], [41, 121, 142], [41, 122, 142], [41, 123, 142], [40, 124, 142], [40, 125, 142], [39, 126, 142], [39, 127, 142], [39, 128, 142], [38, 129, 142], [38, 130, 142], [38, 130, 142], [37, 131, 142], [37, 132, 142], [37, 133, 142], [36, 134, 142], [36, 135, 142], [35, 136, 142], [35, 137, 142], [35, 138, 141], [34, 139, 141], [34, 140, 141], [34, 141, 141], [33, 142, 141], [33, 143, 141], [33, 144, 141], [33, 145, 140], [32, 146, 140], [32, 146, 140], [32, 147, 140], [31, 148, 140], [31, 149, 139], [31, 150, 139], [31, 151, 139], [31, 152, 139], [31, 153, 138], [31, 154, 138], [30, 155, 138], [30, 156, 137], [30, 157, 137], [31, 158, 137], [31, 159, 136], [31, 160, 136], [31, 161, 136], [31, 161, 135], [31, 162, 135], [32, 163, 134], [32, 164, 134], [33, 165, 133], [33, 166, 133], [34, 167, 133], [34, 168, 132], [35, 169, 131], [36, 170, 131], [37, 171, 130], [37, 172, 130], [38, 173, 129], [39, 173, 129], [40, 174, 128], [41, 175, 127], [42, 176, 127], [44, 177, 126], [45, 178, 125], [46, 179, 124], [47, 180, 124], [49, 181, 123], [50, 182, 122], [52, 182, 121], [53, 183, 121], [55, 184, 120], [56, 185, 119], [58, 186, 118], [59, 187, 117], [61, 188, 116], [63, 188, 115], [64, 189, 114], [66, 190, 113], [68, 191, 112], [70, 192, 111], [72, 193, 110], [74, 193, 109], [76, 194, 108], [78, 195, 107], [80, 196, 106], [82, 197, 105], [84, 197, 104], [86, 198, 103], [88, 199, 101], [90, 200, 100], [92, 200, 99], [94, 201, 98], [96, 202, 96], [99, 203, 95], [101, 203, 94], [103, 204, 92], [105, 205, 91], [108, 205, 90], [110, 206, 88], [112, 207, 87], [115, 208, 86], [117, 208, 84], [119, 209, 83], [122, 209, 81], [124, 210, 80], [127, 211, 78], [129, 211, 77], [132, 212, 75], [134, 213, 73], [137, 213, 72], [139, 214, 70], [142, 214, 69], [144, 215, 67], [147, 215, 65], [149, 216, 64], [152, 216, 62], [155, 217, 60], [157, 217, 59], [160, 218, 57], [162, 218, 55], [165, 219, 54], [168, 219, 52], [170, 220, 50], [173, 220, 48], [176, 221, 47], [178, 221, 45], [181, 222, 43], [184, 222, 41], [186, 222, 40], [189, 223, 38], [192, 223, 37], [194, 223, 35], [197, 224, 33], [200, 224, 32], [202, 225, 31], [205, 225, 29], [208, 225, 28], [210, 226, 27], [213, 226, 26], [216, 226, 25], [218, 227, 25], [221, 227, 24], [223, 227, 24], [226, 228, 24], [229, 228, 25], [231, 228, 25], [234, 229, 26], [236, 229, 27], [239, 229, 28], [241, 229, 29], [244, 230, 30], [246, 230, 32], [248, 230, 33], [251, 231, 35], [253, 231, 37]]
var inferno = [[0, 0, 4], [1, 0, 5], [1, 1, 6], [1, 1, 8], [2, 1, 10], [2, 2, 12], [2, 2, 14], [3, 2, 16], [4, 3, 18], [4, 3, 20], [5, 4, 23], [6, 4, 25], [7, 5, 27], [8, 5, 29], [9, 6, 31], [10, 7, 34], [11, 7, 36], [12, 8, 38], [13, 8, 41], [14, 9, 43], [16, 9, 45], [17, 10, 48], [18, 10, 50], [20, 11, 52], [21, 11, 55], [22, 11, 57], [24, 12, 60], [25, 12, 62], [27, 12, 65], [28, 12, 67], [30, 12, 69], [31, 12, 72], [33, 12, 74], [35, 12, 76], [36, 12, 79], [38, 12, 81], [40, 11, 83], [41, 11, 85], [43, 11, 87], [45, 11, 89], [47, 10, 91], [49, 10, 92], [50, 10, 94], [52, 10, 95], [54, 9, 97], [56, 9, 98], [57, 9, 99], [59, 9, 100], [61, 9, 101], [62, 9, 102], [64, 10, 103], [66, 10, 104], [68, 10, 104], [69, 10, 105], [71, 11, 106], [73, 11, 106], [74, 12, 107], [76, 12, 107], [77, 13, 108], [79, 13, 108], [81, 14, 108], [82, 14, 109], [84, 15, 109], [85, 15, 109], [87, 16, 110], [89, 16, 110], [90, 17, 110], [92, 18, 110], [93, 18, 110], [95, 19, 110], [97, 19, 110], [98, 20, 110], [100, 21, 110], [101, 21, 110], [103, 22, 110], [105, 22, 110], [106, 23, 110], [108, 24, 110], [109, 24, 110], [111, 25, 110], [113, 25, 110], [114, 26, 110], [116, 26, 110], [117, 27, 110], [119, 28, 109], [120, 28, 109], [122, 29, 109], [124, 29, 109], [125, 30, 109], [127, 30, 108], [128, 31, 108], [130, 32, 108], [132, 32, 107], [133, 33, 107], [135, 33, 107], [136, 34, 106], [138, 34, 106], [140, 35, 105], [141, 35, 105], [143, 36, 105], [144, 37, 104], [146, 37, 104], [147, 38, 103], [149, 38, 103], [151, 39, 102], [152, 39, 102], [154, 40, 101], [155, 41, 100], [157, 41, 100], [159, 42, 99], [160, 42, 99], [162, 43, 98], [163, 44, 97], [165, 44, 96], [166, 45, 96], [168, 46, 95], [169, 46, 94], [171, 47, 94], [173, 48, 93], [174, 48, 92], [176, 49, 91], [177, 50, 90], [179, 50, 90], [180, 51, 89], [182, 52, 88], [183, 53, 87], [185, 53, 86], [186, 54, 85], [188, 55, 84], [189, 56, 83], [191, 57, 82], [192, 58, 81], [193, 58, 80], [195, 59, 79], [196, 60, 78], [198, 61, 77], [199, 62, 76], [200, 63, 75], [202, 64, 74], [203, 65, 73], [204, 66, 72], [206, 67, 71], [207, 68, 70], [208, 69, 69], [210, 70, 68], [211, 71, 67], [212, 72, 66], [213, 74, 65], [215, 75, 63], [216, 76, 62], [217, 77, 61], [218, 78, 60], [219, 80, 59], [221, 81, 58], [222, 82, 56], [223, 83, 55], [224, 85, 54], [225, 86, 53], [226, 87, 52], [227, 89, 51], [228, 90, 49], [229, 92, 48], [230, 93, 47], [231, 94, 46], [232, 96, 45], [233, 97, 43], [234, 99, 42], [235, 100, 41], [235, 102, 40], [236, 103, 38], [237, 105, 37], [238, 106, 36], [239, 108, 35], [239, 110, 33], [240, 111, 32], [241, 113, 31], [241, 115, 29], [242, 116, 28], [243, 118, 27], [243, 120, 25], [244, 121, 24], [245, 123, 23], [245, 125, 21], [246, 126, 20], [246, 128, 19], [247, 130, 18], [247, 132, 16], [248, 133, 15], [248, 135, 14], [248, 137, 12], [249, 139, 11], [249, 140, 10], [249, 142, 9], [250, 144, 8], [250, 146, 7], [250, 148, 7], [251, 150, 6], [251, 151, 6], [251, 153, 6], [251, 155, 6], [251, 157, 7], [252, 159, 7], [252, 161, 8], [252, 163, 9], [252, 165, 10], [252, 166, 12], [252, 168, 13], [252, 170, 15], [252, 172, 17], [252, 174, 18], [252, 176, 20], [252, 178, 22], [252, 180, 24], [251, 182, 26], [251, 184, 29], [251, 186, 31], [251, 188, 33], [251, 190, 35], [250, 192, 38], [250, 194, 40], [250, 196, 42], [250, 198, 45], [249, 199, 47], [249, 201, 50], [249, 203, 53], [248, 205, 55], [248, 207, 58], [247, 209, 61], [247, 211, 64], [246, 213, 67], [246, 215, 70], [245, 217, 73], [245, 219, 76], [244, 221, 79], [244, 223, 83], [244, 225, 86], [243, 227, 90], [243, 229, 93], [242, 230, 97], [242, 232, 101], [242, 234, 105], [241, 236, 109], [241, 237, 113], [241, 239, 117], [241, 241, 121], [242, 242, 125], [242, 244, 130], [243, 245, 134], [243, 246, 138], [244, 248, 142], [245, 249, 146], [246, 250, 150], [248, 251, 154], [249, 252, 157], [250, 253, 161], [252, 255, 164]]
var magma = [[0, 0, 4], [1, 0, 5], [1, 1, 6], [1, 1, 8], [2, 1, 9], [2, 2, 11], [2, 2, 13], [3, 3, 15], [3, 3, 18], [4, 4, 20], [5, 4, 22], [6, 5, 24], [6, 5, 26], [7, 6, 28], [8, 7, 30], [9, 7, 32], [10, 8, 34], [11, 9, 36], [12, 9, 38], [13, 10, 41], [14, 11, 43], [16, 11, 45], [17, 12, 47], [18, 13, 49], [19, 13, 52], [20, 14, 54], [21, 14, 56], [22, 15, 59], [24, 15, 61], [25, 16, 63], [26, 16, 66], [28, 16, 68], [29, 17, 71], [30, 17, 73], [32, 17, 75], [33, 17, 78], [34, 17, 80], [36, 18, 83], [37, 18, 85], [39, 18, 88], [41, 17, 90], [42, 17, 92], [44, 17, 95], [45, 17, 97], [47, 17, 99], [49, 17, 101], [51, 16, 103], [52, 16, 105], [54, 16, 107], [56, 16, 108], [57, 15, 110], [59, 15, 112], [61, 15, 113], [63, 15, 114], [64, 15, 116], [66, 15, 117], [68, 15, 118], [69, 16, 119], [71, 16, 120], [73, 16, 120], [74, 16, 121], [76, 17, 122], [78, 17, 123], [79, 18, 123], [81, 18, 124], [82, 19, 124], [84, 19, 125], [86, 20, 125], [87, 21, 126], [89, 21, 126], [90, 22, 126], [92, 22, 127], [93, 23, 127], [95, 24, 127], [96, 24, 128], [98, 25, 128], [100, 26, 128], [101, 26, 128], [103, 27, 128], [104, 28, 129], [106, 28, 129], [107, 29, 129], [109, 29, 129], [110, 30, 129], [112, 31, 129], [114, 31, 129], [115, 32, 129], [117, 33, 129], [118, 33, 129], [120, 34, 129], [121, 34, 130], [123, 35, 130], [124, 35, 130], [126, 36, 130], [128, 37, 130], [129, 37, 129], [131, 38, 129], [132, 38, 129], [134, 39, 129], [136, 39, 129], [137, 40, 129], [139, 41, 129], [140, 41, 129], [142, 42, 129], [144, 42, 129], [145, 43, 129], [147, 43, 128], [148, 44, 128], [150, 44, 128], [152, 45, 128], [153, 45, 128], [155, 46, 127], [156, 46, 127], [158, 47, 127], [160, 47, 127], [161, 48, 126], [163, 48, 126], [165, 49, 126], [166, 49, 125], [168, 50, 125], [170, 51, 125], [171, 51, 124], [173, 52, 124], [174, 52, 123], [176, 53, 123], [178, 53, 123], [179, 54, 122], [181, 54, 122], [183, 55, 121], [184, 55, 121], [186, 56, 120], [188, 57, 120], [189, 57, 119], [191, 58, 119], [192, 58, 118], [194, 59, 117], [196, 60, 117], [197, 60, 116], [199, 61, 115], [200, 62, 115], [202, 62, 114], [204, 63, 113], [205, 64, 113], [207, 64, 112], [208, 65, 111], [210, 66, 111], [211, 67, 110], [213, 68, 109], [214, 69, 108], [216, 69, 108], [217, 70, 107], [219, 71, 106], [220, 72, 105], [222, 73, 104], [223, 74, 104], [224, 76, 103], [226, 77, 102], [227, 78, 101], [228, 79, 100], [229, 80, 100], [231, 82, 99], [232, 83, 98], [233, 84, 98], [234, 86, 97], [235, 87, 96], [236, 88, 96], [237, 90, 95], [238, 91, 94], [239, 93, 94], [240, 95, 94], [241, 96, 93], [242, 98, 93], [242, 100, 92], [243, 101, 92], [244, 103, 92], [244, 105, 92], [245, 107, 92], [246, 108, 92], [246, 110, 92], [247, 112, 92], [247, 114, 92], [248, 116, 92], [248, 118, 92], [249, 120, 93], [249, 121, 93], [249, 123, 93], [250, 125, 94], [250, 127, 94], [250, 129, 95], [251, 131, 95], [251, 133, 96], [251, 135, 97], [252, 137, 97], [252, 138, 98], [252, 140, 99], [252, 142, 100], [252, 144, 101], [253, 146, 102], [253, 148, 103], [253, 150, 104], [253, 152, 105], [253, 154, 106], [253, 155, 107], [254, 157, 108], [254, 159, 109], [254, 161, 110], [254, 163, 111], [254, 165, 113], [254, 167, 114], [254, 169, 115], [254, 170, 116], [254, 172, 118], [254, 174, 119], [254, 176, 120], [254, 178, 122], [254, 180, 123], [254, 182, 124], [254, 183, 126], [254, 185, 127], [254, 187, 129], [254, 189, 130], [254, 191, 132], [254, 193, 133], [254, 194, 135], [254, 196, 136], [254, 198, 138], [254, 200, 140], [254, 202, 141], [254, 204, 143], [254, 205, 144], [254, 207, 146], [254, 209, 148], [254, 211, 149], [254, 213, 151], [254, 215, 153], [254, 216, 154], [253, 218, 156], [253, 220, 158], [253, 222, 160], [253, 224, 161], [253, 226, 163], [253, 227, 165], [253, 229, 167], [253, 231, 169], [253, 233, 170], [253, 235, 172], [252, 236, 174], [252, 238, 176], [252, 240, 178], [252, 242, 180], [252, 244, 182], [252, 246, 184], [252, 247, 185], [252, 249, 187], [252, 251, 189], [252, 253, 191]]
var jet = [[0, 0, 128], [0, 0, 132], [0, 0, 137], [0, 0, 141], [0, 0, 146], [0, 0, 150], [0, 0, 155], [0, 0, 159], [0, 0, 164], [0, 0, 168], [0, 0, 173], [0, 0, 178], [0, 0, 182], [0, 0, 187], [0, 0, 191], [0, 0, 196], [0, 0, 200], [0, 0, 205], [0, 0, 209], [0, 0, 214], [0, 0, 218], [0, 0, 223], [0, 0, 227], [0, 0, 232], [0, 0, 237], [0, 0, 241], [0, 0, 246], [0, 0, 250], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 4, 255], [0, 8, 255], [0, 12, 255], [0, 16, 255], [0, 20, 255], [0, 24, 255], [0, 28, 255], [0, 32, 255], [0, 36, 255], [0, 40, 255], [0, 44, 255], [0, 48, 255], [0, 52, 255], [0, 56, 255], [0, 60, 255], [0, 64, 255], [0, 68, 255], [0, 72, 255], [0, 76, 255], [0, 80, 255], [0, 84, 255], [0, 88, 255], [0, 92, 255], [0, 96, 255], [0, 100, 255], [0, 104, 255], [0, 108, 255], [0, 112, 255], [0, 116, 255], [0, 120, 255], [0, 124, 255], [0, 128, 255], [0, 132, 255], [0, 136, 255], [0, 140, 255], [0, 144, 255], [0, 148, 255], [0, 152, 255], [0, 156, 255], [0, 160, 255], [0, 164, 255], [0, 168, 255], [0, 172, 255], [0, 176, 255], [0, 180, 255], [0, 184, 255], [0, 188, 255], [0, 192, 255], [0, 196, 255], [0, 200, 255], [0, 204, 255], [0, 208, 255], [0, 212, 255], [0, 216, 255], [0, 220, 254], [0, 224, 251], [0, 228, 248], [2, 232, 244], [6, 236, 241], [9, 240, 238], [12, 244, 235], [15, 248, 231], [19, 252, 228], [22, 255, 225], [25, 255, 222], [28, 255, 219], [31, 255, 215], [35, 255, 212], [38, 255, 209], [41, 255, 206], [44, 255, 202], [48, 255, 199], [51, 255, 196], [54, 255, 193], [57, 255, 190], [60, 255, 186], [64, 255, 183], [67, 255, 180], [70, 255, 177], [73, 255, 173], [77, 255, 170], [80, 255, 167], [83, 255, 164], [86, 255, 160], [90, 255, 157], [93, 255, 154], [96, 255, 151], [99, 255, 148], [102, 255, 144], [106, 255, 141], [109, 255, 138], [112, 255, 135], [115, 255, 131], [119, 255, 128], [122, 255, 125], [125, 255, 122], [128, 255, 119], [131, 255, 115], [135, 255, 112], [138, 255, 109], [141, 255, 106], [144, 255, 102], [148, 255, 99], [151, 255, 96], [154, 255, 93], [157, 255, 90], [160, 255, 86], [164, 255, 83], [167, 255, 80], [170, 255, 77], [173, 255, 73], [177, 255, 70], [180, 255, 67], [183, 255, 64], [186, 255, 60], [190, 255, 57], [193, 255, 54], [196, 255, 51], [199, 255, 48], [202, 255, 44], [206, 255, 41], [209, 255, 38], [212, 255, 35], [215, 255, 31], [219, 255, 28], [222, 255, 25], [225, 255, 22], [228, 255, 19], [231, 255, 15], [235, 255, 12], [238, 255, 9], [241, 252, 6], [244, 248, 2], [248, 245, 0], [251, 241, 0], [254, 237, 0], [255, 234, 0], [255, 230, 0], [255, 226, 0], [255, 222, 0], [255, 219, 0], [255, 215, 0], [255, 211, 0], [255, 208, 0], [255, 204, 0], [255, 200, 0], [255, 196, 0], [255, 193, 0], [255, 189, 0], [255, 185, 0], [255, 182, 0], [255, 178, 0], [255, 174, 0], [255, 171, 0], [255, 167, 0], [255, 163, 0], [255, 159, 0], [255, 156, 0], [255, 152, 0], [255, 148, 0], [255, 145, 0], [255, 141, 0], [255, 137, 0], [255, 134, 0], [255, 130, 0], [255, 126, 0], [255, 122, 0], [255, 119, 0], [255, 115, 0], [255, 111, 0], [255, 108, 0], [255, 104, 0], [255, 100, 0], [255, 96, 0], [255, 93, 0], [255, 89, 0], [255, 85, 0], [255, 82, 0], [255, 78, 0], [255, 74, 0], [255, 71, 0], [255, 67, 0], [255, 63, 0], [255, 59, 0], [255, 56, 0], [255, 52, 0], [255, 48, 0], [255, 45, 0], [255, 41, 0], [255, 37, 0], [255, 34, 0], [255, 30, 0], [255, 26, 0], [255, 22, 0], [255, 19, 0], [250, 15, 0], [246, 11, 0], [241, 8, 0], [237, 4, 0], [232, 0, 0], [228, 0, 0], [223, 0, 0], [218, 0, 0], [214, 0, 0], [209, 0, 0], [205, 0, 0], [200, 0, 0], [196, 0, 0], [191, 0, 0], [187, 0, 0], [182, 0, 0], [178, 0, 0], [173, 0, 0], [168, 0, 0], [164, 0, 0], [159, 0, 0], [155, 0, 0], [150, 0, 0], [146, 0, 0], [141, 0, 0], [137, 0, 0], [132, 0, 0], [128, 0, 0]]
var binary = [[255, 255, 255], [254, 254, 254], [253, 253, 253], [252, 252, 252], [251, 251, 251], [250, 250, 250], [249, 249, 249], [248, 248, 248], [247, 247, 247], [246, 246, 246], [245, 245, 245], [244, 244, 244], [243, 243, 243], [242, 242, 242], [241, 241, 241], [240, 240, 240], [239, 239, 239], [238, 238, 238], [237, 237, 237], [236, 236, 236], [235, 235, 235], [234, 234, 234], [233, 233, 233], [232, 232, 232], [231, 231, 231], [230, 230, 230], [229, 229, 229], [228, 228, 228], [227, 227, 227], [226, 226, 226], [225, 225, 225], [224, 224, 224], [223, 223, 223], [222, 222, 222], [221, 221, 221], [220, 220, 220], [219, 219, 219], [218, 218, 218], [217, 217, 217], [216, 216, 216], [215, 215, 215], [214, 214, 214], [213, 213, 213], [212, 212, 212], [211, 211, 211], [210, 210, 210], [209, 209, 209], [208, 208, 208], [207, 207, 207], [206, 206, 206], [205, 205, 205], [204, 204, 204], [203, 203, 203], [202, 202, 202], [201, 201, 201], [200, 200, 200], [199, 199, 199], [198, 198, 198], [197, 197, 197], [196, 196, 196], [195, 195, 195], [194, 194, 194], [193, 193, 193], [192, 192, 192], [191, 191, 191], [190, 190, 190], [189, 189, 189], [188, 188, 188], [187, 187, 187], [186, 186, 186], [185, 185, 185], [184, 184, 184], [183, 183, 183], [182, 182, 182], [181, 181, 181], [180, 180, 180], [179, 179, 179], [178, 178, 178], [177, 177, 177], [176, 176, 176], [175, 175, 175], [174, 174, 174], [173, 173, 173], [172, 172, 172], [171, 171, 171], [170, 170, 170], [169, 169, 169], [168, 168, 168], [167, 167, 167], [166, 166, 166], [165, 165, 165], [164, 164, 164], [163, 163, 163], [162, 162, 162], [161, 161, 161], [160, 160, 160], [159, 159, 159], [158, 158, 158], [157, 157, 157], [156, 156, 156], [155, 155, 155], [154, 154, 154], [153, 153, 153], [152, 152, 152], [151, 151, 151], [150, 150, 150], [149, 149, 149], [148, 148, 148], [147, 147, 147], [146, 146, 146], [145, 145, 145], [144, 144, 144], [143, 143, 143], [142, 142, 142], [141, 141, 141], [140, 140, 140], [139, 139, 139], [138, 138, 138], [137, 137, 137], [136, 136, 136], [135, 135, 135], [134, 134, 134], [133, 133, 133], [132, 132, 132], [131, 131, 131], [130, 130, 130], [129, 129, 129], [128, 128, 128], [127, 127, 127], [126, 126, 126], [125, 125, 125], [124, 124, 124], [123, 123, 123], [122, 122, 122], [121, 121, 121], [120, 120, 120], [119, 119, 119], [118, 118, 118], [117, 117, 117], [116, 116, 116], [115, 115, 115], [114, 114, 114], [113, 113, 113], [112, 112, 112], [111, 111, 111], [110, 110, 110], [109, 109, 109], [108, 108, 108], [107, 107, 107], [106, 106, 106], [105, 105, 105], [104, 104, 104], [103, 103, 103], [102, 102, 102], [101, 101, 101], [100, 100, 100], [99, 99, 99], [98, 98, 98], [97, 97, 97], [96, 96, 96], [95, 95, 95], [94, 94, 94], [93, 93, 93], [92, 92, 92], [91, 91, 91], [90, 90, 90], [89, 89, 89], [88, 88, 88], [87, 87, 87], [86, 86, 86], [85, 85, 85], [84, 84, 84], [83, 83, 83], [82, 82, 82], [81, 81, 81], [80, 80, 80], [79, 79, 79], [78, 78, 78], [77, 77, 77], [76, 76, 76], [75, 75, 75], [74, 74, 74], [73, 73, 73], [72, 72, 72], [71, 71, 71], [70, 70, 70], [69, 69, 69], [68, 68, 68], [67, 67, 67], [66, 66, 66], [65, 65, 65], [64, 64, 64], [63, 63, 63], [62, 62, 62], [61, 61, 61], [60, 60, 60], [59, 59, 59], [58, 58, 58], [57, 57, 57], [56, 56, 56], [55, 55, 55], [54, 54, 54], [53, 53, 53], [52, 52, 52], [51, 51, 51], [50, 50, 50], [49, 49, 49], [48, 48, 48], [47, 47, 47], [46, 46, 46], [45, 45, 45], [44, 44, 44], [43, 43, 43], [42, 42, 42], [41, 41, 41], [40, 40, 40], [39, 39, 39], [38, 38, 38], [37, 37, 37], [36, 36, 36], [35, 35, 35], [34, 34, 34], [33, 33, 33], [32, 32, 32], [31, 31, 31], [30, 30, 30], [29, 29, 29], [28, 28, 28], [27, 27, 27], [26, 26, 26], [25, 25, 25], [24, 24, 24], [23, 23, 23], [22, 22, 22], [21, 21, 21], [20, 20, 20], [19, 19, 19], [18, 18, 18], [17, 17, 17], [16, 16, 16], [15, 15, 15], [14, 14, 14], [13, 13, 13], [12, 12, 12], [11, 11, 11], [10, 10, 10], [9, 9, 9], [8, 8, 8], [7, 7, 7], [6, 6, 6], [5, 5, 5], [4, 4, 4], [3, 3, 3], [2, 2, 2], [1, 1, 1], [0, 0, 0]]
var colormaps = [turbo, fosphor, viridis, inferno, magma, jet, binary];

View file

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="author" content="Jeppe Ledet-Pedersen">
<title>Spectrum Plot</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<canvas id="waterfall"></canvas>
<script src="colormap.js"></script>
<script src="spectrum.js"></script>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,16 +0,0 @@
#!/usr/bin/env python
import matplotlib.pyplot as plt
colormaps = ('viridis', 'inferno', 'magma', 'jet', 'binary')
for c in colormaps:
cmap_name = c
cmap = plt.get_cmap(cmap_name)
colors = []
for i in range(256):
colors.append([int(round(255 * x)) for x in cmap(i)[:3]])
print(f'var {c} = {colors}')
print(f'var colormaps = [{", ".join(colormaps)}];')

View file

@ -1,65 +0,0 @@
'use strict';
/*
function connectWebSocket(spectrum) {
// var ws = new WebSocket("ws://" + window.location.host + "/websocket");
var ws = new WebSocket("ws://192.168.178.163:3000");
ws.onopen = function(evt) {
console.log("connected!");
}
ws.onclose = function(evt) {
console.log("closed");
setTimeout(function() {
connectWebSocket(spectrum);
}, 1000);
}
ws.onerror = function(evt) {
console.log("error: " + evt.message);
}
ws.onmessage = function (evt) {
var data = JSON.parse(evt.data);
if (data.s) {
spectrum.addData(data.s);
} else {
if (data.center) {
spectrum.setCenterHz(data.center);
}
if (data.span) {
spectrum.setSpanHz(data.span);
}
}
}
}
*/
function main() {
// Create spectrum object on canvas with ID "waterfall"
var spectrum = new Spectrum(
"waterfall", {
spectrumPercent: 20
});
// Connect to websocket
//connectWebSocket(spectrum);
//spectrum.setCenterHz("2000");
//spectrum.setSpanHz("1");
/*
for (var i = 0; i < 1000; i++) {
var randomstring = Math.floor(Math.random())
spectrum.addData(randomstring.toString());
// more statements
}
*/
// Bind keypress handler
window.addEventListener("keydown", function (e) {
spectrum.onKeypress(e);
});
}
window.onload = main;

View file

@ -1,149 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2019 Jeppe Ledet-Pedersen
# This software is released under the MIT license.
# See the LICENSE file for further details.
import sys
import json
import argparse
from gnuradio import gr
from gnuradio import uhd
from gnuradio.fft import logpwrfft
import numpy as np
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketError
from geventwebsocket.handler import WebSocketHandler
from bottle import request, Bottle, abort, static_file
app = Bottle()
connections = set()
opts = {}
@app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
connections.add(wsock)
# Send center frequency and span
wsock.send(json.dumps(opts))
while True:
try:
wsock.receive()
except WebSocketError:
break
connections.remove(wsock)
@app.route('/')
def index():
return static_file('index.html', root='.')
@app.route('/<filename>')
def static(filename):
return static_file(filename, root='.')
class fft_broadcast_sink(gr.sync_block):
def __init__(self, fft_size):
gr.sync_block.__init__(self,
name="plotter",
in_sig=[(np.float32, fft_size)],
out_sig=[])
def work(self, input_items, output_items):
ninput_items = len(input_items[0])
for bins in input_items[0]:
p = np.around(bins).astype(int)
p = np.fft.fftshift(p)
for c in connections.copy():
try:
c.send(json.dumps({'s': p.tolist()}, separators=(',', ':')))
except Exception:
connections.remove(c)
self.consume(0, ninput_items)
return 0
class fft_receiver(gr.top_block):
def __init__(self, samp_rate, freq, gain, fft_size, framerate):
gr.top_block.__init__(self, "Top Block")
self.usrp = uhd.usrp_source(
",".join(("", "")),
uhd.stream_args(
cpu_format="fc32",
channels=range(1),
),
)
self.usrp.set_samp_rate(samp_rate)
self.usrp.set_center_freq(freq, 0)
self.usrp.set_gain(gain, 0)
self.fft = logpwrfft.logpwrfft_c(
sample_rate=samp_rate,
fft_size=fft_size,
ref_scale=1,
frame_rate=framerate,
avg_alpha=1,
average=False,
)
self.fft_broadcast = fft_broadcast_sink(fft_size)
self.connect((self.fft, 0), (self.fft_broadcast, 0))
self.connect((self.usrp, 0), (self.fft, 0))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--sample-rate', type=float, default=40e6)
parser.add_argument('-f', '--frequency', type=float, default=940e6)
parser.add_argument('-g', '--gain', type=float, default=40)
parser.add_argument('-n', '--fft-size', type=int, default=4096)
parser.add_argument('-r', '--frame-rate', type=int, default=25)
args = parser.parse_args()
if gr.enable_realtime_scheduling() != gr.RT_OK or 0:
print("Error: failed to enable real-time scheduling.")
tb = fft_receiver(
samp_rate=args.sample_rate,
freq=args.frequency,
gain=args.gain,
fft_size=args.fft_size,
framerate=args.frame_rate
)
tb.start()
opts['center'] = args.frequency
opts['span'] = args.sample_rate
server = WSGIServer(("0.0.0.0", 8000), app,
handler_class=WebSocketHandler)
try:
server.serve_forever()
except Exception:
sys.exit(0)
tb.stop()
tb.wait()
if __name__ == '__main__':
main()

View file

@ -1,466 +0,0 @@
/*=============================================================
Filename: Spectrogram-1v00.js
JavaScript graphics functions to draw Spectrograms.
Date Description By
-------|-------------------------------------------------|---
12Nov18 First beta ARC
17Nov18 Added offset into data buffer ARC
08May19 this.imageURL URL added
bugfix: fixed isNaN test
Changed sgStart, sgStop to start, stop
Added options object to constructors ARC
10May19 Enabled Left to Right as well as Top to Bottom ARC
11May19 Added RasterscanSVG ARC
12May19 Added blnkline for horizontal ratser scans ARC
13May19 Eliminated unneccessary putImageData ARC
14May19 Removed toDataURL, not used drawImage is better
bugfix: SVG RHC names swapped ARC
02Jun19 bugfix: startOfs not honored in horizontalNewLine ARC
03Jun19 Flipped the SVG and RHC names for waterfalls ARC
04Jun19 Unflip SVG and RHC for horizontal mode ARC
Swap "SVG" & "RHC" strings to match fn names ARC
05Jun19 bugfix: WaterfallSVG scrolling wrong way ARC
10Jun19 bugfix: support lineRate=0 for static display
bugfix: ipBufPtr must be a ptr to a ptr ARC
11Jun19 Make ipBuffers an Array of Arrays, if lineRate=0
use all buffers else use only ipBuffer[0] ARC
13Jun19 Use Waterfall and Rasterscan plus direction
Use Boolean rater than string compare ARC
16Jun19 Use const and let ARC
20Jun19 Change order of parameters ARC
21Jun19 Add setLineRate method ARC
06Jul19 Released as Rev 1v00 ARC
==============================================================*/
var Waterfall, Rasterscan;
(function(){
Waterfall = function(ipBufAry, w, h, dir, options)
{
var direction = (typeof(dir) === "string")? dir.toLowerCase() : "down";
switch (direction)
{
case "up":
return new Spectrogram(ipBufAry, w, h, "WF", false, true, options);
case "down":
default:
return new Spectrogram(ipBufAry, w, h, "WF", true, true, options);
case "left":
return new Spectrogram(ipBufAry, w, h, "WF", false, false, options);
case "right":
return new Spectrogram(ipBufAry, w, h, "WF", true, false, options);
}
}
Rasterscan = function(ipBufAry, w, h, dir, options)
{
const direction = (typeof(dir) === "string")? dir.toLowerCase() : "down";
switch (direction)
{
case "up":
return new Spectrogram(ipBufAry, w, h, "RS", true, true, options);
case "down":
default:
return new Spectrogram(ipBufAry, w, h, "RS", false, true, options);
case "left":
return new Spectrogram(ipBufAry, w, h, "RS", false, false, options);
case "right":
return new Spectrogram(ipBufAry, w, h, "RS", true, false, options);
}
}
function Spectrogram(ipBufAry, w, h, sgMode, rhc, vert, options)
{
const opt = (typeof options === 'object')? options: {}; // avoid undeclared object errors
let offScreenCtx; // offscreen canvas drawing context
const pxPerLine = w || 200;
const lines = h || 200;
let lineRate = 30; // requested line rate for dynamic waterfalls
let interval = 0; // msec
let startOfs = 0;
const lineBuf = new ArrayBuffer(pxPerLine * 4); // 1 line
const lineBuf8 = new Uint8ClampedArray(lineBuf);
const lineImgData = new ImageData(lineBuf8, pxPerLine, 1); // 1 line of canvas pixels
let pageImgData; // lines * pxPerLine of canvas pixels
let ipBuf8; // map input data to 0..255 unsigned bytes
const blankBuf = new ArrayBuffer(pxPerLine * 4); // 1 line
const blankBuf8 = new Uint8ClampedArray(blankBuf);
const blankImgData = new ImageData(blankBuf8, pxPerLine, 1); // 1 line of canvas pixels
const clearBuf = new ArrayBuffer(pxPerLine * lines * 4); // fills with 0s ie. rgba 0,0,0,0 = transparent
const clearBuf8 = new Uint8ClampedArray(clearBuf);
let clearImgData;
let nextLine = 0;
let timerID = null;
let running = false;
let sgTime = 0;
let sgStartTime = 0;
// Matlab Jet ref: stackoverflow.com grayscale-to-red-green-blue-matlab-jet-color-scale
let colMap = [[ 0, 0, 128, 255], [ 0, 0, 131, 255], [ 0, 0, 135, 255], [ 0, 0, 139, 255],
[ 0, 0, 143, 255], [ 0, 0, 147, 255], [ 0, 0, 151, 255], [ 0, 0, 155, 255],
[ 0, 0, 159, 255], [ 0, 0, 163, 255], [ 0, 0, 167, 255], [ 0, 0, 171, 255],
[ 0, 0, 175, 255], [ 0, 0, 179, 255], [ 0, 0, 183, 255], [ 0, 0, 187, 255],
[ 0, 0, 191, 255], [ 0, 0, 195, 255], [ 0, 0, 199, 255], [ 0, 0, 203, 255],
[ 0, 0, 207, 255], [ 0, 0, 211, 255], [ 0, 0, 215, 255], [ 0, 0, 219, 255],
[ 0, 0, 223, 255], [ 0, 0, 227, 255], [ 0, 0, 231, 255], [ 0, 0, 235, 255],
[ 0, 0, 239, 255], [ 0, 0, 243, 255], [ 0, 0, 247, 255], [ 0, 0, 251, 255],
[ 0, 0, 255, 255], [ 0, 4, 255, 255], [ 0, 8, 255, 255], [ 0, 12, 255, 255],
[ 0, 16, 255, 255], [ 0, 20, 255, 255], [ 0, 24, 255, 255], [ 0, 28, 255, 255],
[ 0, 32, 255, 255], [ 0, 36, 255, 255], [ 0, 40, 255, 255], [ 0, 44, 255, 255],
[ 0, 48, 255, 255], [ 0, 52, 255, 255], [ 0, 56, 255, 255], [ 0, 60, 255, 255],
[ 0, 64, 255, 255], [ 0, 68, 255, 255], [ 0, 72, 255, 255], [ 0, 76, 255, 255],
[ 0, 80, 255, 255], [ 0, 84, 255, 255], [ 0, 88, 255, 255], [ 0, 92, 255, 255],
[ 0, 96, 255, 255], [ 0, 100, 255, 255], [ 0, 104, 255, 255], [ 0, 108, 255, 255],
[ 0, 112, 255, 255], [ 0, 116, 255, 255], [ 0, 120, 255, 255], [ 0, 124, 255, 255],
[ 0, 128, 255, 255], [ 0, 131, 255, 255], [ 0, 135, 255, 255], [ 0, 139, 255, 255],
[ 0, 143, 255, 255], [ 0, 147, 255, 255], [ 0, 151, 255, 255], [ 0, 155, 255, 255],
[ 0, 159, 255, 255], [ 0, 163, 255, 255], [ 0, 167, 255, 255], [ 0, 171, 255, 255],
[ 0, 175, 255, 255], [ 0, 179, 255, 255], [ 0, 183, 255, 255], [ 0, 187, 255, 255],
[ 0, 191, 255, 255], [ 0, 195, 255, 255], [ 0, 199, 255, 255], [ 0, 203, 255, 255],
[ 0, 207, 255, 255], [ 0, 211, 255, 255], [ 0, 215, 255, 255], [ 0, 219, 255, 255],
[ 0, 223, 255, 255], [ 0, 227, 255, 255], [ 0, 231, 255, 255], [ 0, 235, 255, 255],
[ 0, 239, 255, 255], [ 0, 243, 255, 255], [ 0, 247, 255, 255], [ 0, 251, 255, 255],
[ 0, 255, 255, 255], [ 4, 255, 251, 255], [ 8, 255, 247, 255], [ 12, 255, 243, 255],
[ 16, 255, 239, 255], [ 20, 255, 235, 255], [ 24, 255, 231, 255], [ 28, 255, 227, 255],
[ 32, 255, 223, 255], [ 36, 255, 219, 255], [ 40, 255, 215, 255], [ 44, 255, 211, 255],
[ 48, 255, 207, 255], [ 52, 255, 203, 255], [ 56, 255, 199, 255], [ 60, 255, 195, 255],
[ 64, 255, 191, 255], [ 68, 255, 187, 255], [ 72, 255, 183, 255], [ 76, 255, 179, 255],
[ 80, 255, 175, 255], [ 84, 255, 171, 255], [ 88, 255, 167, 255], [ 92, 255, 163, 255],
[ 96, 255, 159, 255], [100, 255, 155, 255], [104, 255, 151, 255], [108, 255, 147, 255],
[112, 255, 143, 255], [116, 255, 139, 255], [120, 255, 135, 255], [124, 255, 131, 255],
[128, 255, 128, 255], [131, 255, 124, 255], [135, 255, 120, 255], [139, 255, 116, 255],
[143, 255, 112, 255], [147, 255, 108, 255], [151, 255, 104, 255], [155, 255, 100, 255],
[159, 255, 96, 255], [163, 255, 92, 255], [167, 255, 88, 255], [171, 255, 84, 255],
[175, 255, 80, 255], [179, 255, 76, 255], [183, 255, 72, 255], [187, 255, 68, 255],
[191, 255, 64, 255], [195, 255, 60, 255], [199, 255, 56, 255], [203, 255, 52, 255],
[207, 255, 48, 255], [211, 255, 44, 255], [215, 255, 40, 255], [219, 255, 36, 255],
[223, 255, 32, 255], [227, 255, 28, 255], [231, 255, 24, 255], [235, 255, 20, 255],
[239, 255, 16, 255], [243, 255, 12, 255], [247, 255, 8, 255], [251, 255, 4, 255],
[255, 255, 0, 255], [255, 251, 0, 255], [255, 247, 0, 255], [255, 243, 0, 255],
[255, 239, 0, 255], [255, 235, 0, 255], [255, 231, 0, 255], [255, 227, 0, 255],
[255, 223, 0, 255], [255, 219, 0, 255], [255, 215, 0, 255], [255, 211, 0, 255],
[255, 207, 0, 255], [255, 203, 0, 255], [255, 199, 0, 255], [255, 195, 0, 255],
[255, 191, 0, 255], [255, 187, 0, 255], [255, 183, 0, 255], [255, 179, 0, 255],
[255, 175, 0, 255], [255, 171, 0, 255], [255, 167, 0, 255], [255, 163, 0, 255],
[255, 159, 0, 255], [255, 155, 0, 255], [255, 151, 0, 255], [255, 147, 0, 255],
[255, 143, 0, 255], [255, 139, 0, 255], [255, 135, 0, 255], [255, 131, 0, 255],
[255, 128, 0, 255], [255, 124, 0, 255], [255, 120, 0, 255], [255, 116, 0, 255],
[255, 112, 0, 255], [255, 108, 0, 255], [255, 104, 0, 255], [255, 100, 0, 255],
[255, 96, 0, 255], [255, 92, 0, 255], [255, 88, 0, 255], [255, 84, 0, 255],
[255, 80, 0, 255], [255, 76, 0, 255], [255, 72, 0, 255], [255, 68, 0, 255],
[255, 64, 0, 255], [255, 60, 0, 255], [255, 56, 0, 255], [255, 52, 0, 255],
[255, 48, 0, 255], [255, 44, 0, 255], [255, 40, 0, 255], [255, 36, 0, 255],
[255, 32, 0, 255], [255, 28, 0, 255], [255, 24, 0, 255], [255, 20, 0, 255],
[255, 16, 0, 255], [255, 12, 0, 255], [255, 8, 0, 255], [255, 4, 0, 255],
[255, 0, 0, 255], [251, 0, 0, 255], [247, 0, 0, 255], [243, 0, 0, 255],
[239, 0, 0, 255], [235, 0, 0, 255], [231, 0, 0, 255], [227, 0, 0, 255],
[223, 0, 0, 255], [219, 0, 0, 255], [215, 0, 0, 255], [211, 0, 0, 255],
[207, 0, 0, 255], [203, 0, 0, 255], [199, 0, 0, 255], [195, 0, 0, 255],
[191, 0, 0, 255], [187, 0, 0, 255], [183, 0, 0, 255], [179, 0, 0, 255],
[175, 0, 0, 255], [171, 0, 0, 255], [167, 0, 0, 255], [163, 0, 0, 255],
[159, 0, 0, 255], [155, 0, 0, 255], [151, 0, 0, 255], [147, 0, 0, 255],
[143, 0, 0, 255], [139, 0, 0, 255], [135, 0, 0, 255], [131, 0, 0, 255],
[ 0, 0, 0, 0]];
function incrLine()
{
if ((vert && !rhc) || (!vert && rhc))
{
nextLine++;
if (nextLine >= lines)
{
nextLine = 0;
}
}
else
{
nextLine--;
if (nextLine < 0)
{
nextLine = lines-1;
}
}
}
function updateWaterfall() // update dynamic waterfalls at a fixed rate
{
let sgDiff;
// grab latest line of data, write it to off screen buffer, inc 'nextLine'
sgNewLine();
// loop to write data data at the desired rate, data is being updated asynchronously
// ref for accurate timeout: http://www.sitepoint.com/creating-accurate-timers-in-javascript
sgTime += interval;
sgDiff = (Date.now() - sgStartTime) - sgTime;
if (running)
{
timerID = setTimeout(updateWaterfall, interval - sgDiff);
}
}
function sgSetLineRate(newRate)
{
if (isNaN(newRate) || newRate > 50 || newRate < 0)
{
console.error("invalid line rate [0 <= lineRate < 50 lines/sec]");
// don't change the lineRate;
}
else if (newRate === 0) // static (one pass) raster
{
lineRate = 0;
}
else
{
lineRate = newRate;
interval = 1000/lineRate; // msec
}
}
this.setLineRate = sgSetLineRate;
function setProperty(propertyName, value)
{
if ((typeof propertyName !== "string")||(value === undefined)) // null is OK, forces default
{
return;
}
switch (propertyName.toLowerCase())
{
case "linerate":
sgSetLineRate(value); // setLine does checks for number etc
break;
case "startbin":
if (!isNaN(value) && value > 0)
{
startOfs = value;
}
break;
case "onscreenparentid":
if (typeof value === "string" && document.getElementById(value))
{
demoCvsId = value;
}
break;
case "colormap":
if (Array.isArray(value) && Array.isArray(value[0]) && value[0].length == 4)
{
colMap = value; // value must be an array of 4 element arrays to get here
if (colMap.length<256) // fill out the remaining colors with last color
{
for (let i=colMap.length; i<256; i++)
{
colMap[i] = colMap[colMap.length-1];
}
}
}
break;
default:
break;
}
}
function verticalNewLine()
{
let tmpImgData, ipBuf8;
if (sgMode == "WF")
{
if (rhc)
{
// shift the current display down 1 line, oldest line drops off
tmpImgData = offScreenCtx.getImageData(0, 0, pxPerLine, lines-1);
offScreenCtx.putImageData(tmpImgData, 0, 1);
}
else
{
// shift the current display up 1 line, oldest line drops off
tmpImgData = offScreenCtx.getImageData(0, 1, pxPerLine, lines-1);
offScreenCtx.putImageData(tmpImgData, 0, 0);
}
}
ipBuf8 = Uint8ClampedArray.from(ipBufAry[0]);
for (let sigVal, rgba, opIdx = 0, ipIdx = startOfs; ipIdx < pxPerLine+startOfs; opIdx += 4, ipIdx++)
{
sigVal = ipBuf8[ipIdx] || 0; // if input line too short add zeros
rgba = colMap[sigVal]; // array of rgba values
// byte reverse so number aa bb gg rr
lineBuf8[opIdx] = rgba[0]; // red
lineBuf8[opIdx+1] = rgba[1]; // green
lineBuf8[opIdx+2] = rgba[2]; // blue
lineBuf8[opIdx+3] = rgba[3]; // alpha
}
offScreenCtx.putImageData(lineImgData, 0, nextLine);
if (sgMode === "RS")
{
incrLine();
// if not static draw a white line in front of the current line to indicate new data point
if (lineRate)
{
offScreenCtx.putImageData(blankImgData, 0, nextLine);
}
}
};
function horizontalNewLine()
{
let tmpImgData, ipBuf8;
if (sgMode == "WF")
{
if (rhc)
{
// shift the current display right 1 line, oldest line drops off
tmpImgData = offScreenCtx.getImageData(0, 0, lines-1, pxPerLine);
offScreenCtx.putImageData(tmpImgData, 1, 0);
}
else
{
// shift the current display left 1 line, oldest line drops off
tmpImgData = offScreenCtx.getImageData(1, 0, lines-1, pxPerLine);
offScreenCtx.putImageData(tmpImgData, 0, 0);
}
}
// refresh the page image (it was just shifted)
pageImgData = offScreenCtx.getImageData(0, 0, lines, pxPerLine);
if (ipBufAry[0].constructor !== Uint8Array)
{
ipBuf8 = Uint8ClampedArray.from(ipBufAry[0]); // clamp input values to 0..255 range
}
else
{
ipBuf8 = ipBufAry[0]; // conversion already done
}
for (let sigVal, rgba, opIdx, ipIdx=0; ipIdx < pxPerLine; ipIdx++)
{
sigVal = ipBuf8[ipIdx+startOfs] || 0; // if input line too short add zeros
rgba = colMap[sigVal]; // array of rgba values
opIdx = 4*((pxPerLine-ipIdx-1)*lines+nextLine);
// byte reverse so number aa bb gg rr
pageImgData.data[opIdx] = rgba[0]; // red
pageImgData.data[opIdx+1] = rgba[1]; // green
pageImgData.data[opIdx+2] = rgba[2]; // blue
pageImgData.data[opIdx+3] = rgba[3]; // alpha
}
if (sgMode === "RS")
{
incrLine();
// if not draw a white line in front of the current line to indicate new data point
if (lineRate)
{
for (let j=0; j < pxPerLine; j++)
{
if (rhc)
{
opIdx = 4*(j*lines+nextLine);
}
else
{
opIdx = 4*((pxPerLine-j-1)*lines+nextLine);
}
// byte reverse so number aa bb gg rr
pageImgData.data[opIdx] = 255; // red
pageImgData.data[opIdx+1] = 255; // green
pageImgData.data[opIdx+2] = 255; // blue
pageImgData.data[opIdx+3] = 255; // alpha
}
}
}
offScreenCtx.putImageData(pageImgData, 0, 0);
};
const sgNewLine = (vert)? verticalNewLine: horizontalNewLine; // function pointers
//===== set all the options ================
for (let prop in opt)
{
// check that this is opt's own property, not inherited from prototype
if (opt.hasOwnProperty(prop))
{
setProperty(prop, opt[prop]);
}
}
// ===== now make the exposed properties and methods ===============
this.newLine = sgNewLine;
this.offScreenCvs = document.createElement("canvas");
if (vert)
{
this.offScreenCvs.setAttribute('width', pxPerLine); // reset canvas pixels width
this.offScreenCvs.setAttribute('height', lines); // don't use style for this
clearImgData = new ImageData(clearBuf8, pxPerLine, lines);
}
else // data written in columns
{
this.offScreenCvs.setAttribute('width', lines); // reset canvas pixels width
this.offScreenCvs.setAttribute('height', pxPerLine); // don't use style for this
clearImgData = new ImageData(clearBuf8, lines, pxPerLine);
}
offScreenCtx = this.offScreenCvs.getContext("2d");
this.clear = function()
{
offScreenCtx.putImageData(clearImgData, 0, 0);
};
this.start = function()
{
sgStartTime = Date.now();
sgTime = 0;
running = true;
updateWaterfall(); // start the update loop
};
this.stop = function()
{
running = false;
if (timerID)
{
clearTimeout(timerID);
}
// reset where the next line is to be written
if (sgMode === "RS")
{
if (vert)
{
nextLine = (rhc)? lines-1 : 0;
}
else
{
nextLine = (rhc)? 0 : lines-1;
}
}
else // WF
{
nextLine = (rhc)? 0 : lines-1;
}
};
// make a white line, it will show the input line for RS displays
blankBuf8.fill(255);
// make a full canvas of the color map 0 values
for (let i=0; i<pxPerLine*lines*4; i+=4)
{
// byte reverse so number aa bb gg rr
clearBuf8[i] = colMap[0][0]; // red
clearBuf8[i+1] = colMap[0][1]; // green
clearBuf8[i+2] = colMap[0][2]; // blue
clearBuf8[i+3] = colMap[0][3]; // alpha
}
// for diagnostics only
if (typeof(demoCvsId) == "string")
{
document.getElementById(demoCvsId).appendChild(this.offScreenCvs);
}
// initialize the direction and first line position
this.stop();
// everything is set
// if dynamic, wait for the start or newLine methods to be called
}
}())

View file

@ -1,430 +0,0 @@
/*
* Copyright (c) 2019 Jeppe Ledet-Pedersen
* This software is released under the MIT license.
* See the LICENSE file for further details.
*/
'use strict';
Spectrum.prototype.squeeze = function(value, out_min, out_max) {
if (value <= this.min_db)
return out_min;
else if (value >= this.max_db)
return out_max;
else
return Math.round((value - this.min_db) / (this.max_db - this.min_db) * out_max);
}
Spectrum.prototype.rowToImageData = function(bins) {
for (var i = 0; i < this.imagedata.data.length; i += 4) {
var cindex = this.squeeze(bins[i/4], 0, 255);
var color = this.colormap[cindex];
this.imagedata.data[i+0] = color[0];
this.imagedata.data[i+1] = color[1];
this.imagedata.data[i+2] = color[2];
this.imagedata.data[i+3] = 255;
}
}
Spectrum.prototype.addWaterfallRow = function(bins) {
// Shift waterfall 1 row down
this.ctx_wf.drawImage(this.ctx_wf.canvas,
0, 0, this.wf_size, this.wf_rows - 1,
0, 1, this.wf_size, this.wf_rows - 1);
// Draw new line on waterfall canvas
this.rowToImageData(bins);
this.ctx_wf.putImageData(this.imagedata, 0, 0);
var width = this.ctx.canvas.width;
var height = this.ctx.canvas.height;
// Copy scaled FFT canvas to screen. Only copy the number of rows that will
// fit in waterfall area to avoid vertical scaling.
this.ctx.imageSmoothingEnabled = false;
var rows = Math.min(this.wf_rows, height - this.spectrumHeight);
this.ctx.drawImage(this.ctx_wf.canvas,
0, 0, this.wf_size, rows,
0, this.spectrumHeight, width, height - this.spectrumHeight);
}
Spectrum.prototype.drawFFT = function(bins) {
this.ctx.beginPath();
this.ctx.moveTo(-1, this.spectrumHeight + 1);
for (var i = 0; i < bins.length; i++) {
var y = this.spectrumHeight - this.squeeze(bins[i], 0, this.spectrumHeight);
if (y > this.spectrumHeight - 1)
y = this.spectrumHeight + 1; // Hide underflow
if (y < 0)
y = 0;
if (i == 0)
this.ctx.lineTo(-1, y);
this.ctx.lineTo(i, y);
if (i == bins.length - 1)
this.ctx.lineTo(this.wf_size + 1, y);
}
this.ctx.lineTo(this.wf_size + 1, this.spectrumHeight + 1);
this.ctx.strokeStyle = "#fefefe";
this.ctx.stroke();
}
Spectrum.prototype.drawSpectrum = function(bins) {
var width = this.ctx.canvas.width;
var height = this.ctx.canvas.height;
// Fill with black
this.ctx.fillStyle = "black";
this.ctx.fillRect(0, 0, width, height);
// FFT averaging
if (this.averaging > 0) {
if (!this.binsAverage || this.binsAverage.length != bins.length) {
this.binsAverage = Array.from(bins);
} else {
for (var i = 0; i < bins.length; i++) {
this.binsAverage[i] += this.alpha * (bins[i] - this.binsAverage[i]);
}
}
bins = this.binsAverage;
}
// Max hold
if (this.maxHold) {
if (!this.binsMax || this.binsMax.length != bins.length) {
this.binsMax = Array.from(bins);
} else {
for (var i = 0; i < bins.length; i++) {
if (bins[i] > this.binsMax[i]) {
this.binsMax[i] = bins[i];
} else {
// Decay
this.binsMax[i] = 1.0025 * this.binsMax[i];
}
}
}
}
// Do not draw anything if spectrum is not visible
if (this.ctx_axes.canvas.height < 1)
return;
// Scale for FFT
this.ctx.save();
this.ctx.scale(width / this.wf_size, 1);
// Draw maxhold
if (this.maxHold)
this.drawFFT(this.binsMax);
// Draw FFT bins
this.drawFFT(bins);
// Restore scale
this.ctx.restore();
// Fill scaled path
this.ctx.fillStyle = this.gradient;
this.ctx.fill();
// Copy axes from offscreen canvas
this.ctx.drawImage(this.ctx_axes.canvas, 0, 0);
}
Spectrum.prototype.updateAxes = function() {
var width = this.ctx_axes.canvas.width;
var height = this.ctx_axes.canvas.height;
// Clear axes canvas
this.ctx_axes.clearRect(0, 0, width, height);
// Draw axes
this.ctx_axes.font = "12px sans-serif";
this.ctx_axes.fillStyle = "white";
this.ctx_axes.textBaseline = "middle";
this.ctx_axes.textAlign = "left";
var step = 10;
for (var i = this.min_db + 10; i <= this.max_db - 10; i += step) {
var y = height - this.squeeze(i, 0, height);
this.ctx_axes.fillText(i, 5, y);
this.ctx_axes.beginPath();
this.ctx_axes.moveTo(20, y);
this.ctx_axes.lineTo(width, y);
this.ctx_axes.strokeStyle = "rgba(200, 200, 200, 0.10)";
this.ctx_axes.stroke();
}
this.ctx_axes.textBaseline = "bottom";
for (var i = 0; i < 11; i++) {
var x = Math.round(width / 10) * i;
if (this.spanHz > 0) {
var adjust = 0;
if (i == 0) {
this.ctx_axes.textAlign = "left";
adjust = 3;
} else if (i == 10) {
this.ctx_axes.textAlign = "right";
adjust = -3;
} else {
this.ctx_axes.textAlign = "center";
}
var freq = this.centerHz + this.spanHz / 10 * (i - 5);
if (this.centerHz + this.spanHz > 1e6)
freq = freq / 1e6 + "M";
else if (this.centerHz + this.spanHz > 1e3)
freq = freq / 1e3 + "k";
this.ctx_axes.fillText(freq, x + adjust, height - 3);
}
this.ctx_axes.beginPath();
this.ctx_axes.moveTo(x, 0);
this.ctx_axes.lineTo(x, height);
this.ctx_axes.strokeStyle = "rgba(200, 200, 200, 0.10)";
this.ctx_axes.stroke();
}
}
Spectrum.prototype.addData = function(data) {
if (!this.paused) {
if (data.length != this.wf_size) {
this.wf_size = data.length;
this.ctx_wf.canvas.width = data.length;
this.ctx_wf.fillStyle = "black";
this.ctx_wf.fillRect(0, 0, this.wf.width, this.wf.height);
this.imagedata = this.ctx_wf.createImageData(data.length, 1);
}
this.drawSpectrum(data);
this.addWaterfallRow(data);
this.resize();
}
}
Spectrum.prototype.updateSpectrumRatio = function() {
this.spectrumHeight = Math.round(this.canvas.height * this.spectrumPercent / 100.0);
this.gradient = this.ctx.createLinearGradient(0, 0, 0, this.spectrumHeight);
for (var i = 0; i < this.colormap.length; i++) {
var c = this.colormap[this.colormap.length - 1 - i];
this.gradient.addColorStop(i / this.colormap.length,
"rgba(" + c[0] + "," + c[1] + "," + c[2] + ", 1.0)");
}
}
Spectrum.prototype.resize = function() {
var width = this.canvas.clientWidth;
var height = this.canvas.clientHeight;
if (this.canvas.width != width ||
this.canvas.height != height) {
this.canvas.width = width;
this.canvas.height = height;
this.updateSpectrumRatio();
}
if (this.axes.width != width ||
this.axes.height != this.spectrumHeight) {
this.axes.width = width;
this.axes.height = this.spectrumHeight;
this.updateAxes();
}
}
Spectrum.prototype.setSpectrumPercent = function(percent) {
if (percent >= 0 && percent <= 100) {
this.spectrumPercent = percent;
this.updateSpectrumRatio();
}
}
Spectrum.prototype.incrementSpectrumPercent = function() {
if (this.spectrumPercent + this.spectrumPercentStep <= 100) {
this.setSpectrumPercent(this.spectrumPercent + this.spectrumPercentStep);
}
}
Spectrum.prototype.decrementSpectrumPercent = function() {
if (this.spectrumPercent - this.spectrumPercentStep >= 0) {
this.setSpectrumPercent(this.spectrumPercent - this.spectrumPercentStep);
}
}
Spectrum.prototype.toggleColor = function() {
this.colorindex++;
if (this.colorindex >= colormaps.length)
this.colorindex = 0;
this.colormap = colormaps[this.colorindex];
this.updateSpectrumRatio();
}
Spectrum.prototype.setRange = function(min_db, max_db) {
this.min_db = min_db;
this.max_db = max_db;
this.updateAxes();
}
Spectrum.prototype.rangeUp = function() {
this.setRange(this.min_db - 5, this.max_db - 5);
}
Spectrum.prototype.rangeDown = function() {
this.setRange(this.min_db + 5, this.max_db + 5);
}
Spectrum.prototype.rangeIncrease = function() {
this.setRange(this.min_db - 5, this.max_db + 5);
}
Spectrum.prototype.rangeDecrease = function() {
if (this.max_db - this.min_db > 10)
this.setRange(this.min_db + 5, this.max_db - 5);
}
Spectrum.prototype.setCenterHz = function(hz) {
this.centerHz = hz;
this.updateAxes();
}
Spectrum.prototype.setSpanHz = function(hz) {
this.spanHz = hz;
this.updateAxes();
}
Spectrum.prototype.setAveraging = function(num) {
if (num >= 0) {
this.averaging = num;
this.alpha = 2 / (this.averaging + 1)
}
}
Spectrum.prototype.incrementAveraging = function() {
this.setAveraging(this.averaging + 1);
}
Spectrum.prototype.decrementAveraging = function() {
if (this.averaging > 0) {
this.setAveraging(this.averaging - 1);
}
}
Spectrum.prototype.setPaused = function(paused) {
this.paused = paused;
}
Spectrum.prototype.togglePaused = function() {
this.setPaused(!this.paused);
}
Spectrum.prototype.setMaxHold = function(maxhold) {
this.maxHold = maxhold;
this.binsMax = undefined;
}
Spectrum.prototype.toggleMaxHold = function() {
this.setMaxHold(!this.maxHold);
}
Spectrum.prototype.toggleFullscreen = function() {
if (!this.fullscreen) {
if (this.canvas.requestFullscreen) {
this.canvas.requestFullscreen();
} else if (this.canvas.mozRequestFullScreen) {
this.canvas.mozRequestFullScreen();
} else if (this.canvas.webkitRequestFullscreen) {
this.canvas.webkitRequestFullscreen();
} else if (this.canvas.msRequestFullscreen) {
this.canvas.msRequestFullscreen();
}
this.fullscreen = true;
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
this.fullscreen = false;
}
}
Spectrum.prototype.onKeypress = function(e) {
if (e.key == " ") {
this.togglePaused();
} else if (e.key == "f") {
this.toggleFullscreen();
} else if (e.key == "c") {
this.toggleColor();
} else if (e.key == "ArrowUp") {
this.rangeUp();
} else if (e.key == "ArrowDown") {
this.rangeDown();
} else if (e.key == "ArrowLeft") {
this.rangeDecrease();
} else if (e.key == "ArrowRight") {
this.rangeIncrease();
} else if (e.key == "s") {
this.incrementSpectrumPercent();
} else if (e.key == "w") {
this.decrementSpectrumPercent();
} else if (e.key == "+") {
this.incrementAveraging();
} else if (e.key == "-") {
this.decrementAveraging();
} else if (e.key == "m") {
this.toggleMaxHold();
}
}
function Spectrum(id, options) {
// Handle options
this.centerHz = (options && options.centerHz) ? options.centerHz : 0;
this.spanHz = (options && options.spanHz) ? options.spanHz : 0;
this.wf_size = (options && options.wf_size) ? options.wf_size : 0;
this.wf_rows = (options && options.wf_rows) ? options.wf_rows : 1024;
this.spectrumPercent = (options && options.spectrumPercent) ? options.spectrumPercent : 25;
this.spectrumPercentStep = (options && options.spectrumPercentStep) ? options.spectrumPercentStep : 5;
this.averaging = (options && options.averaging) ? options.averaging : 2;
this.maxHold = (options && options.maxHold) ? options.maxHold : false;
// Setup state
this.paused = false;
this.fullscreen = false;
this.min_db = -30;
this.max_db = 50;
this.spectrumHeight = 0;
// Colors
this.colorindex = 0;
this.colormap = colormaps[2];
// Create main canvas and adjust dimensions to match actual
this.canvas = document.getElementById(id);
this.canvas.height = this.canvas.clientHeight;
this.canvas.width = this.canvas.clientWidth;
this.ctx = this.canvas.getContext("2d");
this.ctx.fillStyle = "black";
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// Create offscreen canvas for axes
this.axes = document.createElement("canvas");
this.axes.height = 1; // Updated later
this.axes.width = this.canvas.width;
this.ctx_axes = this.axes.getContext("2d");
// Create offscreen canvas for waterfall
this.wf = document.createElement("canvas");
this.wf.height = this.wf_rows;
this.wf.width = this.wf_size;
this.ctx_wf = this.wf.getContext("2d");
// Trigger first render
this.setAveraging(this.averaging);
this.updateSpectrumRatio();
this.resize();
}

View file

@ -1 +0,0 @@

View file

@ -1,11 +0,0 @@
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
#waterfall {
display: block;
width: 100%;
height: 350px;
}