improve demodulator initalization, part 2: refactor js classes
This commit is contained in:
parent
f1dc9af651
commit
33762574c3
@ -27,6 +27,7 @@
|
|||||||
<script src="static/openwebrx.js"></script>
|
<script src="static/openwebrx.js"></script>
|
||||||
<script src="static/lib/jquery-3.2.1.min.js"></script>
|
<script src="static/lib/jquery-3.2.1.min.js"></script>
|
||||||
<script src="static/lib/jquery.nanoscroller.js"></script>
|
<script src="static/lib/jquery.nanoscroller.js"></script>
|
||||||
|
<script src="static/lib/Demodulator.js"></script>
|
||||||
<script src="static/lib/BookmarkBar.js"></script>
|
<script src="static/lib/BookmarkBar.js"></script>
|
||||||
<script src="static/lib/AudioEngine.js"></script>
|
<script src="static/lib/AudioEngine.js"></script>
|
||||||
<script src="static/lib/ProgressBar.js"></script>
|
<script src="static/lib/ProgressBar.js"></script>
|
||||||
|
217
htdocs/lib/Demodulator.js
Normal file
217
htdocs/lib/Demodulator.js
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
function Filter() {
|
||||||
|
this.min_passband = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
Filter.prototype.getLimits = function() {
|
||||||
|
var max_bw;
|
||||||
|
if (secondary_demod === 'pocsag') {
|
||||||
|
max_bw = 12500;
|
||||||
|
} else {
|
||||||
|
max_bw = (audioEngine.getOutputRate() / 2) - 1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
high: max_bw,
|
||||||
|
low: -max_bw
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function Envelope(parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.dragged_range = Demodulator.draggable_ranges.none;
|
||||||
|
}
|
||||||
|
|
||||||
|
Envelope.prototype.draw = function(visible_range){
|
||||||
|
this.visible_range = visible_range;
|
||||||
|
this.drag_ranges = demod_envelope_draw(
|
||||||
|
range,
|
||||||
|
center_freq + this.parent.offset_frequency + this.parent.low_cut,
|
||||||
|
center_freq + this.parent.offset_frequency + this.parent.high_cut,
|
||||||
|
this.color, center_freq + this.parent.offset_frequency
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Envelope.prototype.drag_start = function(x, key_modifiers){
|
||||||
|
this.key_modifiers = key_modifiers;
|
||||||
|
this.dragged_range = demod_envelope_where_clicked(x, this.drag_ranges, key_modifiers);
|
||||||
|
this.drag_origin = {
|
||||||
|
x: x,
|
||||||
|
low_cut: this.parent.low_cut,
|
||||||
|
high_cut: this.parent.high_cut,
|
||||||
|
offset_frequency: this.parent.offset_frequency
|
||||||
|
};
|
||||||
|
return this.dragged_range !== Demodulator.draggable_ranges.none;
|
||||||
|
};
|
||||||
|
|
||||||
|
Envelope.prototype.drag_move = function(x) {
|
||||||
|
var dr = Demodulator.draggable_ranges;
|
||||||
|
var new_value;
|
||||||
|
if (this.dragged_range === dr.none) return false; // we return if user is not dragging (us) at all
|
||||||
|
var freq_change = Math.round(this.visible_range.hps * (x - this.drag_origin.x));
|
||||||
|
|
||||||
|
//dragging the line in the middle of the filter envelope while holding Shift does emulate
|
||||||
|
//the BFO knob on radio equipment: moving offset frequency, while passband remains unchanged
|
||||||
|
//Filter passband moves in the opposite direction than dragged, hence the minus below.
|
||||||
|
var minus = (this.dragged_range === dr.bfo) ? -1 : 1;
|
||||||
|
//dragging any other parts of the filter envelope while holding Shift does emulate the PBS knob
|
||||||
|
//(PassBand Shift) on radio equipment: PBS does move the whole passband without moving the offset
|
||||||
|
//frequency.
|
||||||
|
if (this.dragged_range === dr.beginning || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) {
|
||||||
|
//we don't let low_cut go beyond its limits
|
||||||
|
if ((new_value = this.drag_origin.low_cut + minus * freq_change) < this.parent.filter.getLimits().low) return true;
|
||||||
|
//nor the filter passband be too small
|
||||||
|
if (this.parent.high_cut - new_value < this.parent.filter.min_passband) return true;
|
||||||
|
//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
|
||||||
|
if (new_value >= this.parent.high_cut) return true;
|
||||||
|
this.parent.low_cut = new_value;
|
||||||
|
}
|
||||||
|
if (this.dragged_range === dr.ending || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) {
|
||||||
|
//we don't let high_cut go beyond its limits
|
||||||
|
if ((new_value = this.drag_origin.high_cut + minus * freq_change) > this.parent.filter.getLimits().high) return true;
|
||||||
|
//nor the filter passband be too small
|
||||||
|
if (new_value - this.parent.low_cut < this.parent.filter.min_passband) return true;
|
||||||
|
//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
|
||||||
|
if (new_value <= this.parent.low_cut) return true;
|
||||||
|
this.parent.high_cut = new_value;
|
||||||
|
}
|
||||||
|
if (this.dragged_range === dr.anything_else || this.dragged_range === dr.bfo) {
|
||||||
|
//when any other part of the envelope is dragged, the offset frequency is changed (whole passband also moves with it)
|
||||||
|
new_value = this.drag_origin.offset_frequency + freq_change;
|
||||||
|
if (new_value > bandwidth / 2 || new_value < -bandwidth / 2) return true; //we don't allow tuning above Nyquist frequency :-)
|
||||||
|
this.parent.offset_frequency = new_value;
|
||||||
|
}
|
||||||
|
//now do the actual modifications:
|
||||||
|
mkenvelopes(this.visible_range);
|
||||||
|
this.parent.set();
|
||||||
|
//will have to change this when changing to multi-demodulator mode:
|
||||||
|
tunedFrequencyDisplay.setFrequency(center_freq + this.parent.offset_frequency);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Envelope.prototype.drag_end = function(){
|
||||||
|
demodulator_buttons_update();
|
||||||
|
var to_return = this.dragged_range !== Demodulator.draggable_ranges.none; //this part is required for cliking anywhere on the scale to set offset
|
||||||
|
this.dragged_range = Demodulator.draggable_ranges.none;
|
||||||
|
return to_return;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//******* class Demodulator_default_analog *******
|
||||||
|
// This can be used as a base for basic audio demodulators.
|
||||||
|
// It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB
|
||||||
|
|
||||||
|
function Demodulator(offset_frequency, modulation) {
|
||||||
|
this.offset_frequency = offset_frequency;
|
||||||
|
this.envelope = new Envelope(this);
|
||||||
|
this.color = Demodulator.get_next_color();
|
||||||
|
this.modulation = modulation;
|
||||||
|
this.filter = new Filter();
|
||||||
|
this.squelch_level = -150;
|
||||||
|
this.dmr_filter = 3;
|
||||||
|
this.state = {};
|
||||||
|
var mode = Modes.findByModulation(modulation);
|
||||||
|
if (mode) {
|
||||||
|
this.low_cut = mode.bandpass.low_cut;
|
||||||
|
this.high_cut = mode.bandpass.high_cut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ranges on filter envelope that can be dragged:
|
||||||
|
Demodulator.draggable_ranges = {
|
||||||
|
none: 0,
|
||||||
|
beginning: 1 /*from*/,
|
||||||
|
ending: 2 /*to*/,
|
||||||
|
anything_else: 3,
|
||||||
|
bfo: 4 /*line (while holding shift)*/,
|
||||||
|
pbs: 5
|
||||||
|
}; //to which parameter these correspond in demod_envelope_draw()
|
||||||
|
|
||||||
|
Demodulator.color_index = 0;
|
||||||
|
Demodulator.colors = ["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"];
|
||||||
|
|
||||||
|
Demodulator.get_next_color = function() {
|
||||||
|
if (this.color_index >= this.colors.length) this.color_index = 0;
|
||||||
|
return (this.colors[this.color_index++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Demodulator.prototype.set_offset_frequency = function(to_what) {
|
||||||
|
if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return;
|
||||||
|
this.offset_frequency = Math.round(to_what);
|
||||||
|
this.set();
|
||||||
|
mkenvelopes(get_visible_freq_range());
|
||||||
|
tunedFrequencyDisplay.setFrequency(center_freq + to_what);
|
||||||
|
updateHash();
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.get_offset_frequency = function() {
|
||||||
|
return this.offset_frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.get_modulation = function() {
|
||||||
|
return this.modulation;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.start = function() {
|
||||||
|
this.set();
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
"type": "dspcontrol",
|
||||||
|
"action": "start"
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO check if this is actually used
|
||||||
|
Demodulator.prototype.stop = function() {
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.send = function(params) {
|
||||||
|
ws.send(JSON.stringify({"type": "dspcontrol", "params": params}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Demodulator.prototype.set = function () { //this function sends demodulator parameters to the server
|
||||||
|
var params = {
|
||||||
|
"low_cut": this.low_cut,
|
||||||
|
"high_cut": this.high_cut,
|
||||||
|
"offset_freq": this.offset_frequency,
|
||||||
|
"mod": this.modulation,
|
||||||
|
"dmr_filter": this.dmr_filter,
|
||||||
|
"squelch_level": this.squelch_level
|
||||||
|
};
|
||||||
|
var to_send = {};
|
||||||
|
for (var key in params) {
|
||||||
|
if (!(key in this.state) || params[key] !== this.state[key]) {
|
||||||
|
to_send[key] = params[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(to_send).length > 0) {
|
||||||
|
this.send(to_send);
|
||||||
|
for (var key in to_send) {
|
||||||
|
this.state[key] = to_send[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mkenvelopes(get_visible_freq_range());
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.setSquelch = function(squelch) {
|
||||||
|
this.squelch_level = squelch;
|
||||||
|
this.set();
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.setDmrFilter = function(dmr_filter) {
|
||||||
|
this.dmr_filter = dmr_filter;
|
||||||
|
this.set();
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.setBandpass = function(bandpass) {
|
||||||
|
this.bandpass = bandpass;
|
||||||
|
this.low_cut = bandpass.low_cut;
|
||||||
|
this.high_cut = bandpass.high_cut;
|
||||||
|
this.set();
|
||||||
|
};
|
||||||
|
|
||||||
|
Demodulator.prototype.getBandpass = function() {
|
||||||
|
return {
|
||||||
|
low_cut: this.low_cut,
|
||||||
|
high_cut: this.high_cut
|
||||||
|
};
|
||||||
|
};
|
@ -142,7 +142,7 @@ function setSquelchToAuto() {
|
|||||||
|
|
||||||
function updateSquelch() {
|
function updateSquelch() {
|
||||||
var sliderValue = parseInt($("#openwebrx-panel-squelch").val());
|
var sliderValue = parseInt($("#openwebrx-panel-squelch").val());
|
||||||
ws.send(JSON.stringify({"type": "dspcontrol", "params": {"squelch_level": sliderValue}}));
|
if (demodulators[0]) demodulators[0].setSquelch(sliderValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
var waterfall_min_level;
|
var waterfall_min_level;
|
||||||
@ -238,14 +238,6 @@ function typeInAnimation(element, timeout, what, onFinish) {
|
|||||||
|
|
||||||
demodulators = [];
|
demodulators = [];
|
||||||
|
|
||||||
var demodulator_color_index = 0;
|
|
||||||
var demodulator_colors = ["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"];
|
|
||||||
|
|
||||||
function demodulators_get_next_color() {
|
|
||||||
if (demodulator_color_index >= demodulator_colors.length) demodulator_color_index = 0;
|
|
||||||
return (demodulator_colors[demodulator_color_index++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function demod_envelope_draw(range, from, to, color, line) { // ____
|
function demod_envelope_draw(range, from, to, color, line) { // ____
|
||||||
// Draws a standard filter envelope like this: _/ \_
|
// Draws a standard filter envelope like this: _/ \_
|
||||||
// Parameters are given in offset frequency (Hz).
|
// Parameters are given in offset frequency (Hz).
|
||||||
@ -331,166 +323,6 @@ function demod_envelope_where_clicked(x, drag_ranges, key_modifiers) { // Check
|
|||||||
return dr.none; //User doesn't drag the envelope for this demodulator
|
return dr.none; //User doesn't drag the envelope for this demodulator
|
||||||
}
|
}
|
||||||
|
|
||||||
//******* class Demodulator *******
|
|
||||||
// this can be used as a base class for ANY demodulator
|
|
||||||
Demodulator = function (offset_frequency) {
|
|
||||||
this.offset_frequency = offset_frequency;
|
|
||||||
this.envelope = {};
|
|
||||||
this.color = demodulators_get_next_color();
|
|
||||||
this.stop = function () {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
//ranges on filter envelope that can be dragged:
|
|
||||||
Demodulator.draggable_ranges = {
|
|
||||||
none: 0,
|
|
||||||
beginning: 1 /*from*/,
|
|
||||||
ending: 2 /*to*/,
|
|
||||||
anything_else: 3,
|
|
||||||
bfo: 4 /*line (while holding shift)*/,
|
|
||||||
pbs: 5
|
|
||||||
}; //to which parameter these correspond in demod_envelope_draw()
|
|
||||||
|
|
||||||
//******* class Demodulator_default_analog *******
|
|
||||||
// This can be used as a base for basic audio demodulators.
|
|
||||||
// It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB
|
|
||||||
|
|
||||||
demodulator_response_time = 50;
|
|
||||||
|
|
||||||
function Demodulator_default_analog(offset_frequency, subtype) {
|
|
||||||
Demodulator.call(this, offset_frequency);
|
|
||||||
this.subtype = subtype;
|
|
||||||
this.filter = {
|
|
||||||
min_passband: 100,
|
|
||||||
getLimits: function() {
|
|
||||||
var max_bw;
|
|
||||||
if (secondary_demod === 'pocsag') {
|
|
||||||
max_bw = 12500;
|
|
||||||
} else {
|
|
||||||
max_bw = (audioEngine.getOutputRate() / 2) - 1;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
high: max_bw,
|
|
||||||
low: -max_bw
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var mode = Modes.findByModulation(subtype);
|
|
||||||
if (mode) {
|
|
||||||
this.low_cut = mode.bandpass.low_cut;
|
|
||||||
this.high_cut = mode.bandpass.high_cut;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.wait_for_timer = false;
|
|
||||||
this.set_after = false;
|
|
||||||
this.set = function () { //set() is a wrapper to call doset(), but it ensures that doset won't execute more frequently than demodulator_response_time.
|
|
||||||
if (!this.wait_for_timer) {
|
|
||||||
this.doset(false);
|
|
||||||
this.set_after = false;
|
|
||||||
this.wait_for_timer = true;
|
|
||||||
var timeout_this = this; //http://stackoverflow.com/a/2130411
|
|
||||||
window.setTimeout(function () {
|
|
||||||
timeout_this.wait_for_timer = false;
|
|
||||||
if (timeout_this.set_after) timeout_this.set();
|
|
||||||
}, demodulator_response_time);
|
|
||||||
} else {
|
|
||||||
this.set_after = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.doset = function (first_time) { //this function sends demodulator parameters to the server
|
|
||||||
var params = {
|
|
||||||
"low_cut": this.low_cut,
|
|
||||||
"high_cut": this.high_cut,
|
|
||||||
"offset_freq": this.offset_frequency
|
|
||||||
};
|
|
||||||
if (first_time) params.mod = this.subtype;
|
|
||||||
ws.send(JSON.stringify({"type": "dspcontrol", "params": params}));
|
|
||||||
mkenvelopes(get_visible_freq_range());
|
|
||||||
};
|
|
||||||
this.doset(true); //we set parameters on object creation
|
|
||||||
|
|
||||||
//******* envelope object *******
|
|
||||||
// for drawing the filter envelope above scale
|
|
||||||
this.envelope.parent = this;
|
|
||||||
|
|
||||||
this.envelope.draw = function (visible_range) {
|
|
||||||
this.visible_range = visible_range;
|
|
||||||
this.drag_ranges = demod_envelope_draw(range,
|
|
||||||
center_freq + this.parent.offset_frequency + this.parent.low_cut,
|
|
||||||
center_freq + this.parent.offset_frequency + this.parent.high_cut,
|
|
||||||
this.color, center_freq + this.parent.offset_frequency);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.envelope.dragged_range = Demodulator.draggable_ranges.none;
|
|
||||||
|
|
||||||
// event handlers
|
|
||||||
this.envelope.drag_start = function (x, key_modifiers) {
|
|
||||||
this.key_modifiers = key_modifiers;
|
|
||||||
this.dragged_range = demod_envelope_where_clicked(x, this.drag_ranges, key_modifiers);
|
|
||||||
this.drag_origin = {
|
|
||||||
x: x,
|
|
||||||
low_cut: this.parent.low_cut,
|
|
||||||
high_cut: this.parent.high_cut,
|
|
||||||
offset_frequency: this.parent.offset_frequency
|
|
||||||
};
|
|
||||||
return this.dragged_range !== Demodulator.draggable_ranges.none;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.envelope.drag_move = function (x) {
|
|
||||||
var dr = Demodulator.draggable_ranges;
|
|
||||||
var new_value;
|
|
||||||
if (this.dragged_range === dr.none) return false; // we return if user is not dragging (us) at all
|
|
||||||
var freq_change = Math.round(this.visible_range.hps * (x - this.drag_origin.x));
|
|
||||||
|
|
||||||
//dragging the line in the middle of the filter envelope while holding Shift does emulate
|
|
||||||
//the BFO knob on radio equipment: moving offset frequency, while passband remains unchanged
|
|
||||||
//Filter passband moves in the opposite direction than dragged, hence the minus below.
|
|
||||||
var minus = (this.dragged_range === dr.bfo) ? -1 : 1;
|
|
||||||
//dragging any other parts of the filter envelope while holding Shift does emulate the PBS knob
|
|
||||||
//(PassBand Shift) on radio equipment: PBS does move the whole passband without moving the offset
|
|
||||||
//frequency.
|
|
||||||
if (this.dragged_range === dr.beginning || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) {
|
|
||||||
//we don't let low_cut go beyond its limits
|
|
||||||
if ((new_value = this.drag_origin.low_cut + minus * freq_change) < this.parent.filter.getLimits().low) return true;
|
|
||||||
//nor the filter passband be too small
|
|
||||||
if (this.parent.high_cut - new_value < this.parent.filter.min_passband) return true;
|
|
||||||
//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
|
|
||||||
if (new_value >= this.parent.high_cut) return true;
|
|
||||||
this.parent.low_cut = new_value;
|
|
||||||
}
|
|
||||||
if (this.dragged_range === dr.ending || this.dragged_range === dr.bfo || this.dragged_range === dr.pbs) {
|
|
||||||
//we don't let high_cut go beyond its limits
|
|
||||||
if ((new_value = this.drag_origin.high_cut + minus * freq_change) > this.parent.filter.getLimits().high) return true;
|
|
||||||
//nor the filter passband be too small
|
|
||||||
if (new_value - this.parent.low_cut < this.parent.filter.min_passband) return true;
|
|
||||||
//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
|
|
||||||
if (new_value <= this.parent.low_cut) return true;
|
|
||||||
this.parent.high_cut = new_value;
|
|
||||||
}
|
|
||||||
if (this.dragged_range === dr.anything_else || this.dragged_range === dr.bfo) {
|
|
||||||
//when any other part of the envelope is dragged, the offset frequency is changed (whole passband also moves with it)
|
|
||||||
new_value = this.drag_origin.offset_frequency + freq_change;
|
|
||||||
if (new_value > bandwidth / 2 || new_value < -bandwidth / 2) return true; //we don't allow tuning above Nyquist frequency :-)
|
|
||||||
this.parent.offset_frequency = new_value;
|
|
||||||
}
|
|
||||||
//now do the actual modifications:
|
|
||||||
mkenvelopes(this.visible_range);
|
|
||||||
this.parent.set();
|
|
||||||
//will have to change this when changing to multi-demodulator mode:
|
|
||||||
tunedFrequencyDisplay.setFrequency(center_freq + this.parent.offset_frequency);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.envelope.drag_end = function () { //in this demodulator we've already changed values in the drag_move() function so we shouldn't do too much here.
|
|
||||||
demodulator_buttons_update();
|
|
||||||
var to_return = this.dragged_range !== Demodulator.draggable_ranges.none; //this part is required for cliking anywhere on the scale to set offset
|
|
||||||
this.dragged_range = Demodulator.draggable_ranges.none;
|
|
||||||
return to_return;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Demodulator_default_analog.prototype = new Demodulator();
|
|
||||||
|
|
||||||
function mkenvelopes(visible_range) //called from mkscale
|
function mkenvelopes(visible_range) //called from mkscale
|
||||||
{
|
{
|
||||||
@ -498,7 +330,10 @@ function mkenvelopes(visible_range) //called from mkscale
|
|||||||
for (var i = 0; i < demodulators.length; i++) {
|
for (var i = 0; i < demodulators.length; i++) {
|
||||||
demodulators[i].envelope.draw(visible_range);
|
demodulators[i].envelope.draw(visible_range);
|
||||||
}
|
}
|
||||||
if (demodulators.length) secondary_demod_waterfall_set_zoom(demodulators[0].low_cut, demodulators[0].high_cut);
|
if (demodulators.length) {
|
||||||
|
var bandpass = demodulators[0].getBandpass()
|
||||||
|
secondary_demod_waterfall_set_zoom(bandpass.low_cut, bandpass.high_cut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function demodulator_remove(which) {
|
function demodulator_remove(which) {
|
||||||
@ -519,33 +354,22 @@ function demodulator_analog_replace(subtype, for_digital) { //this function shou
|
|||||||
secondary_demod_close_window();
|
secondary_demod_close_window();
|
||||||
secondary_demod_listbox_update();
|
secondary_demod_listbox_update();
|
||||||
}
|
}
|
||||||
if (!demodulators || !demodulators[0] || demodulators[0].subtype !== subtype) {
|
if (!demodulators || !demodulators[0] || demodulators[0].get_modulation() !== subtype) {
|
||||||
last_analog_demodulator_subtype = subtype;
|
last_analog_demodulator_subtype = subtype;
|
||||||
var temp_offset = 0;
|
var temp_offset = 0;
|
||||||
if (demodulators.length) {
|
if (demodulators.length) {
|
||||||
temp_offset = demodulators[0].offset_frequency;
|
temp_offset = demodulators[0].get_offset_frequency();
|
||||||
demodulator_remove(0);
|
demodulator_remove(0);
|
||||||
}
|
}
|
||||||
demodulator_add(new Demodulator_default_analog(temp_offset, subtype));
|
var demod = new Demodulator(temp_offset, subtype);
|
||||||
|
demod.start();
|
||||||
|
demodulator_add(demod);
|
||||||
}
|
}
|
||||||
demodulator_buttons_update();
|
demodulator_buttons_update();
|
||||||
update_digitalvoice_panels("openwebrx-panel-metadata-" + subtype);
|
update_digitalvoice_panels("openwebrx-panel-metadata-" + subtype);
|
||||||
updateHash();
|
updateHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
Demodulator.prototype.set_offset_frequency = function(to_what) {
|
|
||||||
if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return;
|
|
||||||
this.offset_frequency = Math.round(to_what);
|
|
||||||
this.set();
|
|
||||||
mkenvelopes(get_visible_freq_range());
|
|
||||||
tunedFrequencyDisplay.setFrequency(center_freq + to_what);
|
|
||||||
updateHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
Demodulator.prototype.get_offset_frequency = function() {
|
|
||||||
return this.offset_frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
function waterfallWidth() {
|
function waterfallWidth() {
|
||||||
return $('body').width();
|
return $('body').width();
|
||||||
}
|
}
|
||||||
@ -988,7 +812,7 @@ function zoom_set(level) {
|
|||||||
level = parseInt(level);
|
level = parseInt(level);
|
||||||
zoom_level = level;
|
zoom_level = level;
|
||||||
//zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+waterfallWidth()/2); //zoom to screen center instead of demod envelope
|
//zoom_center_rel=canvas_get_freq_offset(-canvases[0].offsetLeft+waterfallWidth()/2); //zoom to screen center instead of demod envelope
|
||||||
zoom_center_rel = demodulators[0].offset_frequency;
|
zoom_center_rel = demodulators[0].get_offset_frequency();
|
||||||
zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack
|
zoom_center_where = 0.5 + (zoom_center_rel / bandwidth); //this is a kind of hack
|
||||||
resize_canvases(true);
|
resize_canvases(true);
|
||||||
mkscale();
|
mkscale();
|
||||||
@ -1468,12 +1292,6 @@ var mute = false;
|
|||||||
// Optimalise these if audio lags or is choppy:
|
// Optimalise these if audio lags or is choppy:
|
||||||
var audio_buffer_maximal_length_sec = 1; //actual number of samples are calculated from sample rate
|
var audio_buffer_maximal_length_sec = 1; //actual number of samples are calculated from sample rate
|
||||||
|
|
||||||
function webrx_set_param(what, value) {
|
|
||||||
var params = {};
|
|
||||||
params[what] = value;
|
|
||||||
ws.send(JSON.stringify({"type": "dspcontrol", "params": params}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseHash() {
|
function parseHash() {
|
||||||
if (!window.location.hash) {
|
if (!window.location.hash) {
|
||||||
return {};
|
return {};
|
||||||
@ -1512,7 +1330,7 @@ function updateHash() {
|
|||||||
if (!demod) return;
|
if (!demod) return;
|
||||||
window.location.hash = $.map({
|
window.location.hash = $.map({
|
||||||
freq: demod.get_offset_frequency() + center_freq,
|
freq: demod.get_offset_frequency() + center_freq,
|
||||||
mod: demod.subtype,
|
mod: demod.get_modulation(),
|
||||||
secondary_mod: secondary_demod
|
secondary_mod: secondary_demod
|
||||||
}, function(value, key){
|
}, function(value, key){
|
||||||
if (!value) return undefined;
|
if (!value) return undefined;
|
||||||
@ -1543,6 +1361,7 @@ function synchronize_demodulator_init(params) {
|
|||||||
sync_params = $.extend(sync_params, params || {});
|
sync_params = $.extend(sync_params, params || {});
|
||||||
if (sync_params.initialParams && sync_params.modes && sync_params.features) {
|
if (sync_params.initialParams && sync_params.modes && sync_params.features) {
|
||||||
initialize_demodulator(sync_params.initialParams);
|
initialize_demodulator(sync_params.initialParams);
|
||||||
|
delete sync_params.initialParams;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1557,10 +1376,7 @@ function initialize_demodulator(initialParams) {
|
|||||||
if (params.offset_frequency) {
|
if (params.offset_frequency) {
|
||||||
demodulators[0].set_offset_frequency(params.offset_frequency);
|
demodulators[0].set_offset_frequency(params.offset_frequency);
|
||||||
}
|
}
|
||||||
ws.send(JSON.stringify({
|
demodulators[0].start()
|
||||||
"type": "dspcontrol",
|
|
||||||
"action": "start"
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reconnect_timeout = false;
|
var reconnect_timeout = false;
|
||||||
@ -1836,7 +1652,7 @@ function update_dmr_timeslot_filtering() {
|
|||||||
}).toArray().reduce(function (acc, v) {
|
}).toArray().reduce(function (acc, v) {
|
||||||
return acc | v;
|
return acc | v;
|
||||||
}, 0);
|
}, 0);
|
||||||
webrx_set_param("dmr_filter", filter);
|
demodulators[0].setDmrFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function playButtonClick() {
|
function playButtonClick() {
|
||||||
@ -1932,7 +1748,7 @@ function demodulator_buttons_update() {
|
|||||||
var $buttons = $(".openwebrx-demodulator-button");
|
var $buttons = $(".openwebrx-demodulator-button");
|
||||||
$buttons.removeClass("highlighted").removeClass('disabled');
|
$buttons.removeClass("highlighted").removeClass('disabled');
|
||||||
if (!demodulators.length) return;
|
if (!demodulators.length) return;
|
||||||
var mod = demodulators[0].subtype;
|
var mod = demodulators[0].get_modulation();
|
||||||
$("#openwebrx-button-" + mod).addClass("highlighted");
|
$("#openwebrx-button-" + mod).addClass("highlighted");
|
||||||
if (secondary_demod) {
|
if (secondary_demod) {
|
||||||
$("#openwebrx-button-dig").addClass("highlighted");
|
$("#openwebrx-button-dig").addClass("highlighted");
|
||||||
@ -1997,9 +1813,7 @@ function demodulator_digital_replace(subtype) {
|
|||||||
secondary_demod_start(subtype);
|
secondary_demod_start(subtype);
|
||||||
demodulator_analog_replace(mode.underlying[0], true);
|
demodulator_analog_replace(mode.underlying[0], true);
|
||||||
if (mode.bandpass) {
|
if (mode.bandpass) {
|
||||||
demodulators[0].low_cut = mode.bandpass.low_cut;
|
demodulators[0].setBandpass(mode.bandpass);
|
||||||
demodulators[0].high_cut = mode.bandpass.high_cut;
|
|
||||||
demodulators[0].set();
|
|
||||||
}
|
}
|
||||||
demodulator_buttons_update();
|
demodulator_buttons_update();
|
||||||
$('#openwebrx-panel-digimodes').attr('data-mode', subtype);
|
$('#openwebrx-panel-digimodes').attr('data-mode', subtype);
|
||||||
|
@ -139,6 +139,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
def handleTextMessage(self, conn, message):
|
def handleTextMessage(self, conn, message):
|
||||||
try:
|
try:
|
||||||
message = json.loads(message)
|
message = json.loads(message)
|
||||||
|
logger.debug(message)
|
||||||
if "type" in message:
|
if "type" in message:
|
||||||
if message["type"] == "dspcontrol":
|
if message["type"] == "dspcontrol":
|
||||||
if "action" in message and message["action"] == "start":
|
if "action" in message and message["action"] == "start":
|
||||||
@ -146,7 +147,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
|
|
||||||
if "params" in message:
|
if "params" in message:
|
||||||
params = message["params"]
|
params = message["params"]
|
||||||
self.setDspProperties(params)
|
self.getDsp().setProperties(params)
|
||||||
|
|
||||||
elif message["type"] == "config":
|
elif message["type"] == "config":
|
||||||
if "params" in message:
|
if "params" in message:
|
||||||
@ -163,7 +164,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
if "params" in message:
|
if "params" in message:
|
||||||
self.connectionProperties = message["params"]
|
self.connectionProperties = message["params"]
|
||||||
if self.dsp:
|
if self.dsp:
|
||||||
self.setDspProperties(self.connectionProperties)
|
self.getDsp().setProperties(self.connectionProperties)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warning("received message without type: {0}".format(message))
|
logger.warning("received message without type: {0}".format(message))
|
||||||
@ -172,39 +173,30 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
logger.warning("message is not json: {0}".format(message))
|
logger.warning("message is not json: {0}".format(message))
|
||||||
|
|
||||||
def setSdr(self, id=None):
|
def setSdr(self, id=None):
|
||||||
while True:
|
next = None
|
||||||
next = None
|
if id is not None:
|
||||||
if id is not None:
|
next = SdrService.getSource(id)
|
||||||
next = SdrService.getSource(id)
|
if next is None:
|
||||||
if next is None:
|
next = SdrService.getFirstSource()
|
||||||
next = SdrService.getFirstSource()
|
if next is None:
|
||||||
if next is None:
|
# exit condition: no sdrs available
|
||||||
# exit condition: no sdrs available
|
self.handleNoSdrsAvailable()
|
||||||
self.handleNoSdrsAvailable()
|
return
|
||||||
return
|
|
||||||
|
|
||||||
# exit condition: no change
|
# exit condition: no change
|
||||||
if next == self.sdr:
|
if next == self.sdr:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.stopDsp()
|
self.stopDsp()
|
||||||
|
|
||||||
if self.configSub is not None:
|
if self.configSub is not None:
|
||||||
self.configSub.cancel()
|
self.configSub.cancel()
|
||||||
self.configSub = None
|
self.configSub = None
|
||||||
|
|
||||||
self.sdr = next
|
self.sdr = next
|
||||||
|
|
||||||
self.startDsp()
|
|
||||||
|
|
||||||
# keep trying until we find a suitable SDR
|
|
||||||
if self.sdr.getState() == SdrSource.STATE_FAILED:
|
|
||||||
self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName()))
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# send initial config
|
# send initial config
|
||||||
self.setDspProperties(self.connectionProperties)
|
self.getDsp().setProperties(self.connectionProperties)
|
||||||
|
|
||||||
stack = PropertyStack()
|
stack = PropertyStack()
|
||||||
stack.addLayer(0, self.sdr.getProps())
|
stack.addLayer(0, self.sdr.getProps())
|
||||||
@ -236,9 +228,14 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
self.write_sdr_error("No SDR Devices available")
|
self.write_sdr_error("No SDR Devices available")
|
||||||
|
|
||||||
def startDsp(self):
|
def startDsp(self):
|
||||||
if self.dsp is None and self.sdr is not None:
|
while True:
|
||||||
self.dsp = DspManager(self, self.sdr)
|
logger.debug("starting dsp...")
|
||||||
self.dsp.start()
|
self.getDsp().start()
|
||||||
|
if self.sdr.getState() == SdrSource.STATE_FAILED:
|
||||||
|
self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName()))
|
||||||
|
self.setSdr()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.stopDsp()
|
self.stopDsp()
|
||||||
@ -250,6 +247,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
super().close()
|
super().close()
|
||||||
|
|
||||||
def stopDsp(self):
|
def stopDsp(self):
|
||||||
|
logger.debug("stopDsp")
|
||||||
if self.dsp is not None:
|
if self.dsp is not None:
|
||||||
self.dsp.stop()
|
self.dsp.stop()
|
||||||
self.dsp = None
|
self.dsp = None
|
||||||
@ -270,9 +268,11 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
for key, value in params.items():
|
for key, value in params.items():
|
||||||
protected[key] = value
|
protected[key] = value
|
||||||
|
|
||||||
def setDspProperties(self, params):
|
def getDsp(self):
|
||||||
for key, value in params.items():
|
if self.dsp is None:
|
||||||
self.dsp.setProperty(key, value)
|
logger.debug("new DSP")
|
||||||
|
self.dsp = DspManager(self, self.sdr)
|
||||||
|
return self.dsp
|
||||||
|
|
||||||
def write_spectrum_data(self, data):
|
def write_spectrum_data(self, data):
|
||||||
self.mp_send(bytes([0x01]) + data)
|
self.mp_send(bytes([0x01]) + data)
|
||||||
|
@ -135,6 +135,7 @@ class DspManager(csdr.output):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
logger.debug(self.sdrSource)
|
||||||
if self.sdrSource.isAvailable():
|
if self.sdrSource.isAvailable():
|
||||||
self.dsp.start()
|
self.dsp.start()
|
||||||
|
|
||||||
@ -160,6 +161,10 @@ class DspManager(csdr.output):
|
|||||||
sub.cancel()
|
sub.cancel()
|
||||||
self.subscriptions = []
|
self.subscriptions = []
|
||||||
|
|
||||||
|
def setProperties(self, props):
|
||||||
|
for k, v in props.items():
|
||||||
|
self.setProperty(k, v)
|
||||||
|
|
||||||
def setProperty(self, prop, value):
|
def setProperty(self, prop, value):
|
||||||
self.props[prop] = value
|
self.props[prop] = value
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user