Setup packetization and available fks pairs
This commit is contained in:
123
Panels/AvailableFskPairsPanel.js
Normal file
123
Panels/AvailableFskPairsPanel.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import BasePanel from './BasePanel';
|
||||
import { hertz } from '../Humanize';
|
||||
class AvailableFskPairsPanel extends BasePanel {
|
||||
constructor() {
|
||||
super('Available FSK Pairs');
|
||||
this.exclude = [];
|
||||
this.fskPairs = [];
|
||||
this.sampleRate = 48000;
|
||||
|
||||
this.addCanvas('fsk-spectrum', 200, 32);
|
||||
this.addNewLine();
|
||||
|
||||
this.addCheckboxes('fsk-pairs', this.fskPairs);
|
||||
this.addDynamicText('fsk-available', 'None');
|
||||
|
||||
this.addEventListener('select', this.handleSelect);
|
||||
|
||||
this.drawFskSpectrum();
|
||||
};
|
||||
setSampleRate = (value) => {
|
||||
this.sampleRate = value;
|
||||
this.drawFskSpectrum();
|
||||
}
|
||||
|
||||
handleSelect = (event) => {
|
||||
if(event.checked) {
|
||||
this.exclude = this.exclude.filter(id => id !== event.id)
|
||||
} else if(!this.exclude.includes(event.id)) {
|
||||
this.exclude.push(event.id);
|
||||
}
|
||||
this.drawFskSpectrum();
|
||||
};
|
||||
|
||||
getSelectedFskPairs = () => this.fskPairs
|
||||
.filter(this.isSelected);
|
||||
|
||||
getSelectedIndexes = () => this.fskPairs.map((_, id) => id).filter(id => !this.exclude.includes(id));
|
||||
setSelectedIndexes = (values) => {
|
||||
this.exclude = values;
|
||||
this.setFskPairs(this.fskPairs);
|
||||
}
|
||||
|
||||
setFskPairs = fskPairs => {
|
||||
this.fskPairs = fskPairs;
|
||||
this.setValueById('fsk-available', fskPairs.length === 0 ? 'None' : '');
|
||||
const items = fskPairs.map(([lowHz, highHz], index) => ({
|
||||
text: `${index}: ${hertz(lowHz)} / ${hertz(highHz)}`,
|
||||
id: index,
|
||||
value: index,
|
||||
checked: !this.exclude.includes(index),
|
||||
eventName: 'select'
|
||||
}));
|
||||
this.replaceCheckedInputs('checkbox', 'fsk-pairs', items);
|
||||
this.drawFskSpectrum();
|
||||
}
|
||||
|
||||
drawFskSpectrum = () => {
|
||||
|
||||
const ultimateFrequency = this.sampleRate / 2;
|
||||
const fskPairs = this.fskPairs;
|
||||
const canvas = this.getElement('fsk-spectrum');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const {height, width} = canvas;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
if(fskPairs.length === 0) return;
|
||||
const minHz = fskPairs.reduce(
|
||||
(min, fsk) => {
|
||||
const lowestHz = fsk.reduce((min, hz) => Math.min(min, hz), Infinity)
|
||||
return Math.min(min, lowestHz)
|
||||
}, Infinity
|
||||
);
|
||||
const maxHz = fskPairs.reduce(
|
||||
(max, fsk) => {
|
||||
const lowestHz = fsk.reduce((max, hz) => Math.max(max, hz), -Infinity)
|
||||
return Math.max(max, lowestHz)
|
||||
}, -Infinity
|
||||
);
|
||||
const range = maxHz - minHz;
|
||||
|
||||
// Human Hearing
|
||||
let x1 = Math.max(0, ((20-minHz)/range) * width);
|
||||
let x2 = Math.min(width, ((20000-minHz)/range) * width);
|
||||
if(x1 !== x2) {
|
||||
ctx.fillStyle = 'hsla(0, 0%, 100%, 20%)';
|
||||
ctx.fillRect(
|
||||
x1,
|
||||
0,
|
||||
x2 - x1,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
// Telephone
|
||||
x1 = Math.max(0, ((300-minHz)/range) * width);
|
||||
x2 = Math.min(width, ((3400-minHz)/range) * width);
|
||||
if(x1 !== x2) {
|
||||
ctx.fillStyle = 'hsla(60, 50%, 50%, 20%)';
|
||||
ctx.fillRect(
|
||||
x1,
|
||||
0,
|
||||
x2 - x1,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
ctx.lineWith = 1;
|
||||
const plotHz = hz => {
|
||||
const hue = Math.floor(hz/ultimateFrequency * 360);
|
||||
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
|
||||
const x = ((hz-minHz) / range) * width;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, 0);
|
||||
ctx.lineTo(x, height);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
fskPairs.filter(this.isSelected).forEach(fsk => fsk.forEach(plotHz));
|
||||
}
|
||||
isSelected = (delude, allude) => !this.exclude.includes(allude);
|
||||
}
|
||||
|
||||
export default AvailableFskPairsPanel;
|
||||
@@ -65,6 +65,20 @@ class BasePanel {
|
||||
this.append(select);
|
||||
}
|
||||
addCheckedInputs = (type, name, items, value) => {
|
||||
const div = document.createElement('div');
|
||||
div.id = this.childId(name);
|
||||
this.createCheckedInputs(type, name, items, value)
|
||||
.forEach(element => div.appendChild(element));
|
||||
this.append(div);
|
||||
}
|
||||
replaceCheckedInputs = (type, name, items, value) => {
|
||||
const div = this.getElement(name);
|
||||
div.innerHTML = '';
|
||||
this.createCheckedInputs(type, name, items, value)
|
||||
.forEach(element => div.appendChild(element));
|
||||
}
|
||||
createCheckedInputs = (type, name, items, value) => {
|
||||
const elements = [];
|
||||
items.forEach(({id, text, checked = false, eventName = 'change'})=> {
|
||||
const label = document.createElement('label');
|
||||
label.for = this.childId(id);
|
||||
@@ -72,9 +86,10 @@ class BasePanel {
|
||||
label.appendChild(input);
|
||||
const textNode = document.createTextNode(text);
|
||||
label.append(textNode);
|
||||
this.append(label);
|
||||
this.addNewLine();
|
||||
elements.push(label);
|
||||
elements.push(document.createElement('br'));
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
addInputText = (id, value, options = {}) => {
|
||||
this.append(this.createInput(id, value, {...options, type: 'text'}));
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import BasePanel from './BasePanel';
|
||||
|
||||
class FrequencyPanel extends BasePanel {
|
||||
constructor(sampleRate = 48000) {
|
||||
constructor() {
|
||||
super('Frequencies');
|
||||
|
||||
this.sampleRate = sampleRate;
|
||||
const ultimateFrequency = sampleRate / 2;
|
||||
this.sampleRate = 48000;
|
||||
const ultimateFrequency = this.sampleRate / 2;
|
||||
|
||||
this.addCanvas('frequency-spectrum', 200, 32);
|
||||
this.addNewLine();
|
||||
|
||||
this.openField('Minimum');
|
||||
this.addInputNumber('minimum-frequency', 0, {min: 0, max: ultimateFrequency, eventName: 'minimumFrequencyChange'});
|
||||
@@ -35,9 +38,6 @@ class FrequencyPanel extends BasePanel {
|
||||
this.addInputNumber('multi-fsk-padding', 0, {min: 0, max: 20, eventName: 'multiFskPaddingChange'});
|
||||
this.closeField();
|
||||
|
||||
this.addCanvas('frequency-spectrum', 200, 32);
|
||||
this.addNewLine();
|
||||
|
||||
this.openField('FSK Pairs Available');
|
||||
this.addDynamicText('fsk-count', 'N/A');
|
||||
this.closeField();
|
||||
@@ -51,6 +51,11 @@ class FrequencyPanel extends BasePanel {
|
||||
this.originalFskPairs = this.getFskPairs();
|
||||
this.drawFrequencySpectrum();
|
||||
};
|
||||
setSampleRate = (value) => {
|
||||
this.sampleRate = value;
|
||||
this.checkFskPairsChanged();
|
||||
}
|
||||
|
||||
getMinimumFrequency = () => parseInt(this.getValueById('minimum-frequency'));
|
||||
setMinimumFrequency = value => {
|
||||
this.setValueById('minimum-frequency', value);
|
||||
@@ -96,10 +101,8 @@ class FrequencyPanel extends BasePanel {
|
||||
if(original.length !== current.length) {
|
||||
changed = true;
|
||||
} else {
|
||||
changed = original.some(
|
||||
(fsk, fskIndex) => {
|
||||
return fsk.some((hz, hzIndex) => hz !== original[fskIndex][hzIndex]);
|
||||
})
|
||||
const currentHz = current.flat();
|
||||
changed = original.flat().some((hz, i) => hz !== currentHz[i]);
|
||||
}
|
||||
if(changed) {
|
||||
this.originalFskPairs = current;
|
||||
|
||||
43
Panels/PacketizationPanel.js
Normal file
43
Panels/PacketizationPanel.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import BasePanel from './BasePanel';
|
||||
import { byteSize } from '../Humanize';
|
||||
|
||||
class PacketizationPanel extends BasePanel {
|
||||
constructor() {
|
||||
super('Packetization');
|
||||
|
||||
this.openField('Packet Size');
|
||||
this.addText('2^');
|
||||
this.addInputNumber('size-power', 5, {min: 0, max: 16, eventName: 'sizePowerChange', translation: 'power of 2'});
|
||||
this.addText(' ');
|
||||
this.addDynamicText('size')
|
||||
this.closeField();
|
||||
|
||||
this.addSection('Encoding');
|
||||
|
||||
this.addCheckboxes('packet-encoding', [
|
||||
{ text: 'Interleaving', id: 'interleaving', checked: true, eventName: 'interleavingChange' },
|
||||
{ text: 'Error Correction', id: 'error-correction', checked: true, eventName: 'errorCorrectionChange' },
|
||||
]);
|
||||
|
||||
this.addEventListener('sizePowerChange', this.handleSizePowerChange);
|
||||
this.dispatcher.emit('sizePowerChange', {value: this.getSize()});
|
||||
};
|
||||
|
||||
getSizePower = () => parseInt(this.getValueById('size-power'));
|
||||
setSizePower = (value) => {
|
||||
this.setValueById('size-power', value);
|
||||
this.handleSizePowerChange({value});
|
||||
}
|
||||
getSize = () => 2 ** this.getSizePower();
|
||||
handleSizePowerChange = () => {
|
||||
this.setValueById('size', byteSize(this.getSize()));
|
||||
}
|
||||
|
||||
getInterleaving = () => this.getCheckedById('interleaving');
|
||||
setInterleaving = (value) => this.setCheckedById('interleaving', value);
|
||||
|
||||
getErrorCorrection = () => this.getCheckedById('error-correction');
|
||||
setErrorCorrection = (value) => this.setCheckedById('error-correction', value);
|
||||
}
|
||||
|
||||
export default PacketizationPanel;
|
||||
Reference in New Issue
Block a user