From d901e76ac1393df8c4f8eb2751dc53f7a2ddbb46 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Sat, 9 Sep 2023 17:32:54 -0400 Subject: [PATCH] Merging htdocs from jketterl development branch. --- htdocs/css/admin.css | 4 ++ htdocs/features.js | 2 +- htdocs/include/header.include.html | 4 +- htdocs/lib/AprsMarker.js | 24 ++++++++++-- htdocs/lib/AudioEngine.js | 59 +++++++++++++++++------------- htdocs/lib/Demodulator.js | 7 ++++ htdocs/lib/DemodulatorPanel.js | 24 ++++++------ htdocs/lib/Modes.js | 1 + htdocs/lib/settings/LogMessages.js | 5 +++ htdocs/settings.js | 1 + openwebrx.conf | 2 + 11 files changed, 91 insertions(+), 42 deletions(-) create mode 100644 htdocs/lib/settings/LogMessages.js diff --git a/htdocs/css/admin.css b/htdocs/css/admin.css index 21e9279c..02e9a8ad 100644 --- a/htdocs/css/admin.css +++ b/htdocs/css/admin.css @@ -160,3 +160,7 @@ h1 { .imageupload.is-invalid ~ .invalid-feedback { display: block; } + +.device-log-messages { + max-height: 500px; +} \ No newline at end of file diff --git a/htdocs/features.js b/htdocs/features.js index fef2817e..0add3b43 100644 --- a/htdocs/features.js +++ b/htdocs/features.js @@ -1,5 +1,5 @@ $(function(){ - var converter = new showdown.Converter(); + var converter = new showdown.Converter({openLinksInNewWindow: true}); $.ajax('api/features').done(function(data){ var $table = $('table.features'); $.each(data, function(name, details) { diff --git a/htdocs/include/header.include.html b/htdocs/include/header.include.html index aa04045d..7953bba7 100644 --- a/htdocs/include/header.include.html +++ b/htdocs/include/header.include.html @@ -30,7 +30,7 @@
${photo_desc}
- - + + diff --git a/htdocs/lib/AprsMarker.js b/htdocs/lib/AprsMarker.js index f6720c10..381c4ea9 100644 --- a/htdocs/lib/AprsMarker.js +++ b/htdocs/lib/AprsMarker.js @@ -2,6 +2,18 @@ function AprsMarker() {} AprsMarker.prototype = new google.maps.OverlayView(); +AprsMarker.prototype.isFacingEast = function(symbol) { + var candidates = '' + if (symbol.table === '/') { + // primary table + candidates = '(*<=>CFPUXYabefghjkpsuv['; + } else { + // alternate table + candidates = 'hkluv'; + } + return candidates.includes(symbol.symbol); +}; + AprsMarker.prototype.draw = function() { var div = this.div; var overlay = this.overlay; @@ -16,9 +28,15 @@ AprsMarker.prototype.draw = function() { } if (this.course) { - if (this.course > 180) { + if (this.symbol && !this.isFacingEast(this.symbol)) { + // assume symbol points to the north + div.style.transform = 'rotate(' + this.course + ' deg)'; + } else if (this.course > 180) { + // symbol is pointing east + // don't rotate more than 180 degrees, rather mirror div.style.transform = 'scalex(-1) rotate(' + (270 - this.course) + 'deg)' } else { + // symbol is pointing east div.style.transform = 'rotate(' + (this.course - 90) + 'deg)'; } } else { @@ -70,7 +88,7 @@ AprsMarker.prototype.onAdd = function() { div.appendChild(overlay); var self = this; - google.maps.event.addDomListener(div, "click", function(event) { + div.addEventListener("click", function(event) { event.stopPropagation(); google.maps.event.trigger(self, "click", event); }); @@ -79,7 +97,7 @@ AprsMarker.prototype.onAdd = function() { panes.overlayImage.appendChild(div); }; -AprsMarker.prototype.remove = function() { +AprsMarker.prototype.onRemove = function() { if (this.div) { this.div.parentNode.removeChild(this.div); this.div = null; diff --git a/htdocs/lib/AudioEngine.js b/htdocs/lib/AudioEngine.js index efdb453c..7bd5d3eb 100644 --- a/htdocs/lib/AudioEngine.js +++ b/htdocs/lib/AudioEngine.js @@ -413,7 +413,9 @@ ImaAdpcmCodec.prototype.reset = function() { this.synchronized = 0; this.syncWord = "SYNC"; this.syncCounter = 0; - this.skip = 0; + this.phase = 0; + this.syncBuffer = new Uint8Array(4); + this.syncBufferIndex = 0; }; ImaAdpcmCodec.imaIndexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 ]; @@ -441,38 +443,45 @@ ImaAdpcmCodec.prototype.decode = function(data) { ImaAdpcmCodec.prototype.decodeWithSync = function(data) { var output = new Int16Array(data.length * 2); - var index = this.skip; var oi = 0; - while (index < data.length) { - while (this.synchronized < 4 && index < data.length) { - if (data[index] === this.syncWord.charCodeAt(this.synchronized)) { - this.synchronized++; - } else { - this.synchronized = 0; - } - index++; - if (this.synchronized === 4) { - if (index + 4 < data.length) { - var syncData = new Int16Array(data.buffer.slice(index, index + 4)); + for (var index = 0; index < data.length; index++) { + switch (this.phase) { + case 0: + // search for sync word + if (data[index] !== this.syncWord.charCodeAt(this.synchronized++)) { + // reset if data is unexpected + this.synchronized = 0; + } + // if sync word has been found pass on to next phase + if (this.synchronized === 4) { + this.syncBufferIndex = 0; + this.phase = 1; + } + break; + case 1: + // read codec runtime data from stream + this.syncBuffer[this.syncBufferIndex++] = data[index]; + // if data is complete, apply and pass on to next phase + if (this.syncBufferIndex === 4) { + var syncData = new Int16Array(this.syncBuffer.buffer); this.stepIndex = syncData[0]; this.predictor = syncData[1]; + this.syncCounter = 1000; + this.phase = 2; } - this.syncCounter = 1000; - index += 4; break; - } - } - while (index < data.length) { - if (this.syncCounter-- < 0) { - this.synchronized = 0; + case 2: + // decode actual audio data + output[oi++] = this.decodeNibble(data[index] & 0x0F); + output[oi++] = this.decodeNibble(data[index] >> 4); + // if the next sync keyword is due, reset and return to phase 0 + if (this.syncCounter-- === 0) { + this.synchronized = 0; + this.phase = 0; + } break; - } - output[oi++] = this.decodeNibble(data[index] & 0x0F); - output[oi++] = this.decodeNibble(data[index] >> 4); - index++; } } - this.skip = index - data.length; return output.slice(0, oi); }; diff --git a/htdocs/lib/Demodulator.js b/htdocs/lib/Demodulator.js index 1b94e5aa..9ba349e2 100644 --- a/htdocs/lib/Demodulator.js +++ b/htdocs/lib/Demodulator.js @@ -347,6 +347,13 @@ Demodulator.prototype.setBandpass = function(bandpass) { this.set(); }; +Demodulator.prototype.disableBandpass = function() { + delete this.bandpass; + this.low_cut = null; + this.high_cut = null; + this.set() +} + Demodulator.prototype.setLowCut = function(low_cut) { this.low_cut = low_cut; this.set(); diff --git a/htdocs/lib/DemodulatorPanel.js b/htdocs/lib/DemodulatorPanel.js index fd4a9add..b0d546d4 100644 --- a/htdocs/lib/DemodulatorPanel.js +++ b/htdocs/lib/DemodulatorPanel.js @@ -91,7 +91,7 @@ DemodulatorPanel.prototype.setMode = function(requestedModulation, underlyingMod return; } - if (this.mode === mode && (!underlyingModulation || this.underlyingModulation === underlyingModulation)) { + if (this.mode === mode && this.underlyingModulation === underlyingModulation) { return; } if (!mode.isAvailable()) { @@ -101,12 +101,9 @@ DemodulatorPanel.prototype.setMode = function(requestedModulation, underlyingMod var modulation; if (mode.type === 'digimode') { - if (underlyingModulation) { - modulation = underlyingModulation - } else { - modulation = mode.underlying[0]; - } + modulation = underlyingModulation = underlyingModulation || mode.underlying[0]; } else { + underlyingModulation = undefined; modulation = mode.modulation; } @@ -138,8 +135,12 @@ DemodulatorPanel.prototype.setMode = function(requestedModulation, underlyingMod if (mode.type === 'digimode') { this.demodulator.set_secondary_demod(mode.modulation); - if (mode.bandpass) { - this.demodulator.setBandpass(mode.bandpass); + var uMode = Modes.findByModulation(underlyingModulation); + var bandpass = mode.bandpass || (uMode && uMode.bandpass); + if (bandpass) { + this.demodulator.setBandpass(bandpass); + } else { + this.demodulator.disableBandpass(); } } else { this.demodulator.set_secondary_demod(false); @@ -147,7 +148,7 @@ DemodulatorPanel.prototype.setMode = function(requestedModulation, underlyingMod this.demodulator.start(); this.mode = mode; - this.underlyingModulation = modulation; + this.underlyingModulation = underlyingModulation; this.updateButtons(); this.updatePanels(); @@ -161,7 +162,8 @@ DemodulatorPanel.prototype.disableDigiMode = function() { DemodulatorPanel.prototype.updatePanels = function() { var modulation = this.getDemodulator().get_secondary_demod(); $('#openwebrx-panel-digimodes').attr('data-mode', modulation); - toggle_panel("openwebrx-panel-digimodes", !!modulation); + var mode = Modes.findByModulation(modulation); + toggle_panel("openwebrx-panel-digimodes", modulation && (!mode || mode.secondaryFft)); toggle_panel("openwebrx-panel-wsjt-message", ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65", "msk144"].indexOf(modulation) >= 0); toggle_panel("openwebrx-panel-js8-message", modulation == "js8"); toggle_panel("openwebrx-panel-packet-message", ["packet", "ais"].indexOf(modulation) >= 0); @@ -393,6 +395,6 @@ DemodulatorPanel.prototype.setTuningPrecision = function(precision) { $.fn.demodulatorPanel = function(){ if (!this.data('panel')) { this.data('panel', new DemodulatorPanel(this)); - }; + } return this.data('panel'); }; diff --git a/htdocs/lib/Modes.js b/htdocs/lib/Modes.js index c68466ae..ee82b7d7 100644 --- a/htdocs/lib/Modes.js +++ b/htdocs/lib/Modes.js @@ -43,6 +43,7 @@ var Mode = function(json){ } if (this.type === 'digimode') { this.underlying = json.underlying; + this.secondaryFft = json.secondaryFft; } }; diff --git a/htdocs/lib/settings/LogMessages.js b/htdocs/lib/settings/LogMessages.js new file mode 100644 index 00000000..ea2683ea --- /dev/null +++ b/htdocs/lib/settings/LogMessages.js @@ -0,0 +1,5 @@ +$.fn.logMessages = function() { + $.each(this, function(){ + $(this).scrollTop(this.scrollHeight); + }); +}; \ No newline at end of file diff --git a/htdocs/settings.js b/htdocs/settings.js index 3a071b5b..b1bc7361 100644 --- a/htdocs/settings.js +++ b/htdocs/settings.js @@ -8,4 +8,5 @@ $(function(){ $('.optional-section').optionalSection(); $('#scheduler').schedulerInput(); $('.exponential-input').exponentialInput(); + $('.device-log-messages').logMessages(); }); \ No newline at end of file diff --git a/openwebrx.conf b/openwebrx.conf index 32a0f77c..9bbfe806 100644 --- a/openwebrx.conf +++ b/openwebrx.conf @@ -1,9 +1,11 @@ [core] data_directory = /var/lib/openwebrx temporary_directory = /tmp +log_level = INFO [web] port = 8073 +ipv6 = true [aprs] # path to the aprs symbols repository (get it here: https://github.com/hessu/aprs-symbols)