Setup packetization and available fks pairs
This commit is contained in:
11
Humanize.js
11
Humanize.js
@@ -9,6 +9,17 @@ export function byteSize(count) {
|
|||||||
count = Math.floor(count * 10) * 0.1
|
count = Math.floor(count * 10) * 0.1
|
||||||
return `${count.toLocaleString()} ${units[unitIndex]}`
|
return `${count.toLocaleString()} ${units[unitIndex]}`
|
||||||
}
|
}
|
||||||
|
export function hertz(hz) {
|
||||||
|
let unitIndex = 0;
|
||||||
|
const units = ['Hz', 'kHz', 'mHz', 'gHz', 'tHz', 'pHz'];
|
||||||
|
while(hz >= 1000) {
|
||||||
|
hz /= 1000;
|
||||||
|
unitIndex++;
|
||||||
|
if(unitIndex === units.length - 1) break;
|
||||||
|
}
|
||||||
|
hz = Math.floor(hz * 1000) * 0.001
|
||||||
|
return `${hz.toLocaleString()} ${units[unitIndex]}`
|
||||||
|
}
|
||||||
export function bitsPerSecond(bps) {
|
export function bitsPerSecond(bps) {
|
||||||
let unitIndex = 0;
|
let unitIndex = 0;
|
||||||
const units = ['baud', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps'];
|
const units = ['baud', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbps'];
|
||||||
|
|||||||
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);
|
this.append(select);
|
||||||
}
|
}
|
||||||
addCheckedInputs = (type, name, items, value) => {
|
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'})=> {
|
items.forEach(({id, text, checked = false, eventName = 'change'})=> {
|
||||||
const label = document.createElement('label');
|
const label = document.createElement('label');
|
||||||
label.for = this.childId(id);
|
label.for = this.childId(id);
|
||||||
@@ -72,9 +86,10 @@ class BasePanel {
|
|||||||
label.appendChild(input);
|
label.appendChild(input);
|
||||||
const textNode = document.createTextNode(text);
|
const textNode = document.createTextNode(text);
|
||||||
label.append(textNode);
|
label.append(textNode);
|
||||||
this.append(label);
|
elements.push(label);
|
||||||
this.addNewLine();
|
elements.push(document.createElement('br'));
|
||||||
});
|
});
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
addInputText = (id, value, options = {}) => {
|
addInputText = (id, value, options = {}) => {
|
||||||
this.append(this.createInput(id, value, {...options, type: 'text'}));
|
this.append(this.createInput(id, value, {...options, type: 'text'}));
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import BasePanel from './BasePanel';
|
import BasePanel from './BasePanel';
|
||||||
|
|
||||||
class FrequencyPanel extends BasePanel {
|
class FrequencyPanel extends BasePanel {
|
||||||
constructor(sampleRate = 48000) {
|
constructor() {
|
||||||
super('Frequencies');
|
super('Frequencies');
|
||||||
|
|
||||||
this.sampleRate = sampleRate;
|
this.sampleRate = 48000;
|
||||||
const ultimateFrequency = sampleRate / 2;
|
const ultimateFrequency = this.sampleRate / 2;
|
||||||
|
|
||||||
|
this.addCanvas('frequency-spectrum', 200, 32);
|
||||||
|
this.addNewLine();
|
||||||
|
|
||||||
this.openField('Minimum');
|
this.openField('Minimum');
|
||||||
this.addInputNumber('minimum-frequency', 0, {min: 0, max: ultimateFrequency, eventName: 'minimumFrequencyChange'});
|
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.addInputNumber('multi-fsk-padding', 0, {min: 0, max: 20, eventName: 'multiFskPaddingChange'});
|
||||||
this.closeField();
|
this.closeField();
|
||||||
|
|
||||||
this.addCanvas('frequency-spectrum', 200, 32);
|
|
||||||
this.addNewLine();
|
|
||||||
|
|
||||||
this.openField('FSK Pairs Available');
|
this.openField('FSK Pairs Available');
|
||||||
this.addDynamicText('fsk-count', 'N/A');
|
this.addDynamicText('fsk-count', 'N/A');
|
||||||
this.closeField();
|
this.closeField();
|
||||||
@@ -51,6 +51,11 @@ class FrequencyPanel extends BasePanel {
|
|||||||
this.originalFskPairs = this.getFskPairs();
|
this.originalFskPairs = this.getFskPairs();
|
||||||
this.drawFrequencySpectrum();
|
this.drawFrequencySpectrum();
|
||||||
};
|
};
|
||||||
|
setSampleRate = (value) => {
|
||||||
|
this.sampleRate = value;
|
||||||
|
this.checkFskPairsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
getMinimumFrequency = () => parseInt(this.getValueById('minimum-frequency'));
|
getMinimumFrequency = () => parseInt(this.getValueById('minimum-frequency'));
|
||||||
setMinimumFrequency = value => {
|
setMinimumFrequency = value => {
|
||||||
this.setValueById('minimum-frequency', value);
|
this.setValueById('minimum-frequency', value);
|
||||||
@@ -96,10 +101,8 @@ class FrequencyPanel extends BasePanel {
|
|||||||
if(original.length !== current.length) {
|
if(original.length !== current.length) {
|
||||||
changed = true;
|
changed = true;
|
||||||
} else {
|
} else {
|
||||||
changed = original.some(
|
const currentHz = current.flat();
|
||||||
(fsk, fskIndex) => {
|
changed = original.flat().some((hz, i) => hz !== currentHz[i]);
|
||||||
return fsk.some((hz, hzIndex) => hz !== original[fskIndex][hzIndex]);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if(changed) {
|
if(changed) {
|
||||||
this.originalFskPairs = current;
|
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;
|
||||||
22
index.html
22
index.html
@@ -10,28 +10,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>Data Over Audio</h1>
|
<h1>Data Over Audio</h1>
|
||||||
<div class="panels" id="panel-container">
|
<div class="panels" id="panel-container">
|
||||||
<div>
|
|
||||||
<h2>Packetizaton</h2>
|
|
||||||
<div>
|
|
||||||
Packet Size:
|
|
||||||
2^<input id="packet-size-power" type="number" min="0" max="16">
|
|
||||||
<span id="packet-size"></span>
|
|
||||||
<br>
|
|
||||||
<h4>Encoding</h4>
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="periodic-interleaving" checked>Interleaving
|
|
||||||
</label><br />
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="error-correction-hamming" checked>Error Correction
|
|
||||||
</label><br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Channels</h2>
|
|
||||||
<div>
|
|
||||||
<ol id="channel-list" start="0"></ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
<h2>Frequency Graph</h2>
|
<h2>Frequency Graph</h2>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
102
index.js
102
index.js
@@ -12,6 +12,8 @@ import MessagePanel from "./Panels/MessagePanel";
|
|||||||
import CodePanel from "./Panels/CodePanel";
|
import CodePanel from "./Panels/CodePanel";
|
||||||
import FrequencyPanel from "./Panels/FrequencyPanel";
|
import FrequencyPanel from "./Panels/FrequencyPanel";
|
||||||
import SignalPanel from "./Panels/SignalPanel";
|
import SignalPanel from "./Panels/SignalPanel";
|
||||||
|
import PacketizationPanel from "./Panels/PacketizationPanel";
|
||||||
|
import AvailableFskPairsPanel from "./Panels/AvailableFskPairsPanel";
|
||||||
|
|
||||||
var audioContext;
|
var audioContext;
|
||||||
var microphoneStream;
|
var microphoneStream;
|
||||||
@@ -32,8 +34,6 @@ let SENT_TRANSFER_BITS = []; // bits sent in the transfer
|
|||||||
let EXCLUDED_CHANNELS = [];
|
let EXCLUDED_CHANNELS = [];
|
||||||
|
|
||||||
var MAX_BITS_DISPLAYED_ON_GRAPH = 79;
|
var MAX_BITS_DISPLAYED_ON_GRAPH = 79;
|
||||||
var HAMMING_ERROR_CORRECTION = true;
|
|
||||||
let PERIODIC_INTERLEAVING = true;
|
|
||||||
|
|
||||||
const ERROR_CORRECTION_BLOCK_SIZE = 7;
|
const ERROR_CORRECTION_BLOCK_SIZE = 7;
|
||||||
const ERROR_CORRECTION_DATA_SIZE = 4;
|
const ERROR_CORRECTION_DATA_SIZE = 4;
|
||||||
@@ -49,7 +49,6 @@ let SAMPLES = [];
|
|||||||
var bitStart = [];
|
var bitStart = [];
|
||||||
var PAUSE = false;
|
var PAUSE = false;
|
||||||
var PAUSE_AFTER_END = true;
|
var PAUSE_AFTER_END = true;
|
||||||
var PACKET_SIZE_BITS = 5; // 32 bytes, 256 bits
|
|
||||||
|
|
||||||
let USED_FSK = [];
|
let USED_FSK = [];
|
||||||
let AVAILABLE_FSK = [];
|
let AVAILABLE_FSK = [];
|
||||||
@@ -60,9 +59,13 @@ const bitsSentPanel = new CodePanel('Bits Sent');
|
|||||||
const bitsReceivedPanel = new CodePanel('Bits Received');
|
const bitsReceivedPanel = new CodePanel('Bits Received');
|
||||||
const frequencyPanel = new FrequencyPanel();
|
const frequencyPanel = new FrequencyPanel();
|
||||||
const signalPanel = new SignalPanel();
|
const signalPanel = new SignalPanel();
|
||||||
|
const packetizationPanel = new PacketizationPanel();
|
||||||
|
const availableFskPairsPanel = new AvailableFskPairsPanel();
|
||||||
|
|
||||||
function handleWindowLoad() {
|
function handleWindowLoad() {
|
||||||
const panelContainer = document.getElementById('panel-container');
|
const panelContainer = document.getElementById('panel-container');
|
||||||
|
panelContainer.prepend(availableFskPairsPanel.getDomElement());
|
||||||
|
panelContainer.prepend(packetizationPanel.getDomElement());
|
||||||
panelContainer.prepend(signalPanel.getDomElement());
|
panelContainer.prepend(signalPanel.getDomElement());
|
||||||
panelContainer.prepend(frequencyPanel.getDomElement());
|
panelContainer.prepend(frequencyPanel.getDomElement());
|
||||||
panelContainer.prepend(bitsReceivedPanel.getDomElement());
|
panelContainer.prepend(bitsReceivedPanel.getDomElement());
|
||||||
@@ -94,6 +97,12 @@ function handleWindowLoad() {
|
|||||||
signalPanel.setAmplitudeThreshold(0.78);
|
signalPanel.setAmplitudeThreshold(0.78);
|
||||||
signalPanel.setSmoothingTimeConstant(0);
|
signalPanel.setSmoothingTimeConstant(0);
|
||||||
|
|
||||||
|
packetizationPanel.setSizePower(5);
|
||||||
|
packetizationPanel.setErrorCorrection(true);
|
||||||
|
packetizationPanel.setInterleaving(true);
|
||||||
|
|
||||||
|
availableFskPairsPanel.setFskPairs(frequencyPanel.getFskPairs());
|
||||||
|
|
||||||
// Communications Events
|
// Communications Events
|
||||||
communicationsPanel.addEventListener('listeningChange', handleChangeListening);
|
communicationsPanel.addEventListener('listeningChange', handleChangeListening);
|
||||||
communicationsPanel.addEventListener('sendSpeakersChange', handleChangeSendSpeakers);
|
communicationsPanel.addEventListener('sendSpeakersChange', handleChangeSendSpeakers);
|
||||||
@@ -110,12 +119,24 @@ function handleWindowLoad() {
|
|||||||
});
|
});
|
||||||
frequencyPanel.addEventListener('fskPaddingChange', configurationChanged);
|
frequencyPanel.addEventListener('fskPaddingChange', configurationChanged);
|
||||||
frequencyPanel.addEventListener('multiFskPaddingChange', configurationChanged);
|
frequencyPanel.addEventListener('multiFskPaddingChange', configurationChanged);
|
||||||
|
frequencyPanel.addEventListener('fskPairsChange', ({value}) => {
|
||||||
|
availableFskPairsPanel.setFskPairs(value);
|
||||||
|
});
|
||||||
|
|
||||||
signalPanel.addEventListener('waveformChange', updateAudioSender);
|
signalPanel.addEventListener('waveformChange', updateAudioSender);
|
||||||
signalPanel.addEventListener('segmentDurationChange', configurationChanged);
|
signalPanel.addEventListener('segmentDurationChange', configurationChanged);
|
||||||
signalPanel.addEventListener('amplitudeThresholdChange', configurationChanged);
|
signalPanel.addEventListener('amplitudeThresholdChange', configurationChanged);
|
||||||
signalPanel.addEventListener('smoothingConstantChange', configurationChanged);
|
signalPanel.addEventListener('smoothingConstantChange', configurationChanged);
|
||||||
|
|
||||||
|
packetizationPanel.addEventListener('sizePowerChange', configurationChanged);
|
||||||
|
packetizationPanel.addEventListener('interleavingChange', () => {
|
||||||
|
StreamManager.setSegmentEncoding(
|
||||||
|
packetizationPanel.getInterleaving() ? InterleaverEncoding : undefined
|
||||||
|
);
|
||||||
|
configurationChanged();
|
||||||
|
});
|
||||||
|
packetizationPanel.addEventListener('errorCorrectionChange', configurationChanged);
|
||||||
|
|
||||||
// Setup audio sender
|
// Setup audio sender
|
||||||
AudioSender.addEventListener('begin', () => messagePanel.setSendButtonText('Stop'));
|
AudioSender.addEventListener('begin', () => messagePanel.setSendButtonText('Stop'));
|
||||||
AudioSender.addEventListener('send', handleAudioSenderSend);
|
AudioSender.addEventListener('send', handleAudioSenderSend);
|
||||||
@@ -135,27 +156,7 @@ function handleWindowLoad() {
|
|||||||
receivedChannelGraph.addEventListener('mouseout', handleReceivedChannelGraphMouseout);
|
receivedChannelGraph.addEventListener('mouseout', handleReceivedChannelGraphMouseout);
|
||||||
receivedChannelGraph.addEventListener('mousemove', handleReceivedChannelGraphMousemove);
|
receivedChannelGraph.addEventListener('mousemove', handleReceivedChannelGraphMousemove);
|
||||||
receivedChannelGraph.addEventListener('click', handleReceivedChannelGraphClick);
|
receivedChannelGraph.addEventListener('click', handleReceivedChannelGraphClick);
|
||||||
document.getElementById('packet-size-power').value = PACKET_SIZE_BITS;
|
|
||||||
document.getElementById('packet-size').innerText = Humanize.byteSize(2 ** PACKET_SIZE_BITS);
|
|
||||||
document.getElementById('packet-size-power').addEventListener('input', event => {
|
|
||||||
PACKET_SIZE_BITS = parseInt(event.target.value);
|
|
||||||
document.getElementById('packet-size').innerText = Humanize.byteSize(2 ** PACKET_SIZE_BITS);
|
|
||||||
configurationChanged();
|
|
||||||
});
|
|
||||||
document.getElementById('pause-after-end').checked = PAUSE_AFTER_END;
|
document.getElementById('pause-after-end').checked = PAUSE_AFTER_END;
|
||||||
document.getElementById('error-correction-hamming').checked = HAMMING_ERROR_CORRECTION;
|
|
||||||
document.getElementById('error-correction-hamming').addEventListener('change', event => {
|
|
||||||
HAMMING_ERROR_CORRECTION = event.target.checked;
|
|
||||||
configurationChanged();
|
|
||||||
})
|
|
||||||
document.getElementById('periodic-interleaving').checked = PERIODIC_INTERLEAVING;
|
|
||||||
document.getElementById('periodic-interleaving').addEventListener('change', event => {
|
|
||||||
PERIODIC_INTERLEAVING = event.target.checked;
|
|
||||||
configurationChanged();
|
|
||||||
StreamManager.setSegmentEncoding(
|
|
||||||
PERIODIC_INTERLEAVING ? InterleaverEncoding : undefined
|
|
||||||
);
|
|
||||||
});
|
|
||||||
document.getElementById('pause-after-end').addEventListener('change', event => {
|
document.getElementById('pause-after-end').addEventListener('change', event => {
|
||||||
PAUSE_AFTER_END = event.target.checked;
|
PAUSE_AFTER_END = event.target.checked;
|
||||||
if(!PAUSE_AFTER_END) resumeGraph();
|
if(!PAUSE_AFTER_END) resumeGraph();
|
||||||
@@ -178,33 +179,6 @@ function updateFrequencyResolution() {
|
|||||||
document.getElementById('frequency-count').innerText = frequencyCount.toFixed(2);
|
document.getElementById('frequency-count').innerText = frequencyCount.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showChannelList() {
|
|
||||||
const allChannels = AVAILABLE_FSK;
|
|
||||||
const channelList = document.getElementById('channel-list');
|
|
||||||
channelList.innerHTML = "";
|
|
||||||
allChannels.forEach(([low, high], i) => {
|
|
||||||
const li = document.createElement('li');
|
|
||||||
const label = document.createElement('label');
|
|
||||||
li.appendChild(label);
|
|
||||||
const checkbox = document.createElement('input');
|
|
||||||
checkbox.type = 'checkbox';
|
|
||||||
checkbox.checked = !EXCLUDED_CHANNELS.includes(i);
|
|
||||||
checkbox.addEventListener('input', event => {
|
|
||||||
if(event.target.checked) {
|
|
||||||
EXCLUDED_CHANNELS = EXCLUDED_CHANNELS.filter(channel => channel !== i)
|
|
||||||
} else {
|
|
||||||
EXCLUDED_CHANNELS.push(i);
|
|
||||||
}
|
|
||||||
configurationChanged();
|
|
||||||
})
|
|
||||||
label.append(checkbox);
|
|
||||||
const text = document.createTextNode(`Low: ${low} Hz High: ${high} Hz`);
|
|
||||||
label.append(text);
|
|
||||||
channelList.appendChild(li);
|
|
||||||
})
|
|
||||||
drawChannels();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleAudioSenderSend({bits}) {
|
function handleAudioSenderSend({bits}) {
|
||||||
SENT_TRANSFER_BITS.push(...bits);
|
SENT_TRANSFER_BITS.push(...bits);
|
||||||
showSentBits();
|
showSentBits();
|
||||||
@@ -217,7 +191,7 @@ function configurationChanged() {
|
|||||||
updateStreamManager();
|
updateStreamManager();
|
||||||
updateAudioSender();
|
updateAudioSender();
|
||||||
updateAudioReceiver();
|
updateAudioReceiver();
|
||||||
showChannelList();
|
drawChannels();
|
||||||
updateFrequencyResolution();
|
updateFrequencyResolution();
|
||||||
updatePacketStats();
|
updatePacketStats();
|
||||||
}
|
}
|
||||||
@@ -259,7 +233,7 @@ function updateAudioReceiver() {
|
|||||||
}
|
}
|
||||||
function updateStreamManager() {
|
function updateStreamManager() {
|
||||||
StreamManager.setPacketEncoding(
|
StreamManager.setPacketEncoding(
|
||||||
HAMMING_ERROR_CORRECTION ? HammingEncoding : undefined
|
packetizationPanel.getErrorCorrection() ? HammingEncoding : undefined
|
||||||
);
|
);
|
||||||
StreamManager.changeConfiguration({
|
StreamManager.changeConfiguration({
|
||||||
bitsPerPacket: PacketUtils.getPacketMaxBitCount(),
|
bitsPerPacket: PacketUtils.getPacketMaxBitCount(),
|
||||||
@@ -279,16 +253,16 @@ function updateStreamManager() {
|
|||||||
}
|
}
|
||||||
function updatePacketUtils() {
|
function updatePacketUtils() {
|
||||||
PacketUtils.setEncoding(
|
PacketUtils.setEncoding(
|
||||||
HAMMING_ERROR_CORRECTION ? HammingEncoding : undefined
|
packetizationPanel.getErrorCorrection() ? HammingEncoding : undefined
|
||||||
);
|
);
|
||||||
const bitsPerSegment = USED_FSK.length;
|
const bitsPerSegment = USED_FSK.length;
|
||||||
PacketUtils.changeConfiguration({
|
PacketUtils.changeConfiguration({
|
||||||
segmentDurationMilliseconds: signalPanel.getSegmentDuration(),
|
segmentDurationMilliseconds: signalPanel.getSegmentDuration(),
|
||||||
packetSizeBitCount: PACKET_SIZE_BITS,
|
packetSizeBitCount: packetizationPanel.getSizePower(),
|
||||||
dataSizeBitCount: MAXIMUM_PACKETIZATION_SIZE_BITS,
|
dataSizeBitCount: MAXIMUM_PACKETIZATION_SIZE_BITS,
|
||||||
dataSizeCrcBitCount: CRC_BIT_COUNT,
|
dataSizeCrcBitCount: CRC_BIT_COUNT,
|
||||||
bitsPerSegment,
|
bitsPerSegment,
|
||||||
packetEncoding: HAMMING_ERROR_CORRECTION,
|
packetEncoding: packetizationPanel.getErrorCorrection(),
|
||||||
packetEncodingBitCount: ERROR_CORRECTION_BLOCK_SIZE,
|
packetEncodingBitCount: ERROR_CORRECTION_BLOCK_SIZE,
|
||||||
packetDecodingBitCount: ERROR_CORRECTION_DATA_SIZE,
|
packetDecodingBitCount: ERROR_CORRECTION_DATA_SIZE,
|
||||||
});
|
});
|
||||||
@@ -479,11 +453,11 @@ function showSentBits() {
|
|||||||
document.getElementById('sent-data').innerHTML =
|
document.getElementById('sent-data').innerHTML =
|
||||||
SENT_ORIGINAL_BITS.reduce(bitReducer(
|
SENT_ORIGINAL_BITS.reduce(bitReducer(
|
||||||
PacketUtils.getPacketMaxBitCount(),
|
PacketUtils.getPacketMaxBitCount(),
|
||||||
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
|
packetizationPanel.getErrorCorrection() ? ERROR_CORRECTION_DATA_SIZE : 8
|
||||||
), '');
|
), '');
|
||||||
|
|
||||||
// error correcting bits
|
// error correcting bits
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(packetizationPanel.getErrorCorrection()) {
|
||||||
document.getElementById('error-correcting-data').innerHTML =
|
document.getElementById('error-correcting-data').innerHTML =
|
||||||
SENT_ENCODED_BITS.reduce(bitReducer(
|
SENT_ENCODED_BITS.reduce(bitReducer(
|
||||||
PacketUtils.getPacketDataBitCount(),
|
PacketUtils.getPacketDataBitCount(),
|
||||||
@@ -506,7 +480,7 @@ function sendPacket(bits, packetStartSeconds) {
|
|||||||
const segmentDurationSeconds = PacketUtils.getSegmentDurationSeconds();
|
const segmentDurationSeconds = PacketUtils.getSegmentDurationSeconds();
|
||||||
for(let i = 0; i < bitCount; i += channelCount) {
|
for(let i = 0; i < bitCount; i += channelCount) {
|
||||||
let segmentBits = bits.slice(i, i + channelCount);
|
let segmentBits = bits.slice(i, i + channelCount);
|
||||||
if(PERIODIC_INTERLEAVING) {
|
if(packetizationPanel.getInterleaving()) {
|
||||||
segmentBits = InterleaverEncoding.encode(segmentBits);
|
segmentBits = InterleaverEncoding.encode(segmentBits);
|
||||||
}
|
}
|
||||||
const segmentIndex = Math.floor(i / channelCount);
|
const segmentIndex = Math.floor(i / channelCount);
|
||||||
@@ -558,7 +532,7 @@ function getTransferredCorrectedBits() {
|
|||||||
const packetCount = StreamManager.getPacketReceivedCount();
|
const packetCount = StreamManager.getPacketReceivedCount();
|
||||||
for(let packetIndex = 0; packetIndex < packetCount; packetIndex++) {
|
for(let packetIndex = 0; packetIndex < packetCount; packetIndex++) {
|
||||||
let packetBits = StreamManager.getPacketBits(packetIndex);
|
let packetBits = StreamManager.getPacketBits(packetIndex);
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(packetizationPanel.getErrorCorrection()) {
|
||||||
bits.push(...HammingEncoding.decode(packetBits));
|
bits.push(...HammingEncoding.decode(packetBits));
|
||||||
} else {
|
} else {
|
||||||
bits.push(...packetBits);
|
bits.push(...packetBits);
|
||||||
@@ -613,7 +587,7 @@ function handleStreamManagerChange() {
|
|||||||
(packetIndex, blockIndex) => `${blockIndex === 0 ? '' : '<br>'}Segment ${blockIndex}: `
|
(packetIndex, blockIndex) => `${blockIndex === 0 ? '' : '<br>'}Segment ${blockIndex}: `
|
||||||
),
|
),
|
||||||
''));
|
''));
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(packetizationPanel.getErrorCorrection()) {
|
||||||
document.getElementById('received-encoded-bits').innerHTML = allEncodedBits
|
document.getElementById('received-encoded-bits').innerHTML = allEncodedBits
|
||||||
.reduce(
|
.reduce(
|
||||||
bitExpectorReducer(
|
bitExpectorReducer(
|
||||||
@@ -630,7 +604,7 @@ function handleStreamManagerChange() {
|
|||||||
bitExpectorReducer(
|
bitExpectorReducer(
|
||||||
SENT_ORIGINAL_BITS,
|
SENT_ORIGINAL_BITS,
|
||||||
PacketUtils.getPacketDataBitCount(),
|
PacketUtils.getPacketDataBitCount(),
|
||||||
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
|
packetizationPanel.getErrorCorrection() ? ERROR_CORRECTION_DATA_SIZE : 8
|
||||||
),
|
),
|
||||||
'');
|
'');
|
||||||
document.getElementById('received-packet-original-bytes').innerText = transmissionByteCount.toLocaleString();
|
document.getElementById('received-packet-original-bytes').innerText = transmissionByteCount.toLocaleString();
|
||||||
@@ -693,7 +667,7 @@ function removeEncodedPadding(bits) {
|
|||||||
let bitsNeeded = sizeBits;
|
let bitsNeeded = sizeBits;
|
||||||
let blocksNeeded = sizeBits;
|
let blocksNeeded = sizeBits;
|
||||||
// need to calc max bits
|
// need to calc max bits
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(packetizationPanel.getErrorCorrection()) {
|
||||||
blocksNeeded = Math.ceil(sizeBits / dataSize);
|
blocksNeeded = Math.ceil(sizeBits / dataSize);
|
||||||
bitsNeeded = blocksNeeded * blockSize;
|
bitsNeeded = blocksNeeded * blockSize;
|
||||||
}
|
}
|
||||||
@@ -708,7 +682,7 @@ function removeEncodedPadding(bits) {
|
|||||||
// determine how many decoded bits need to be sent (including the size)
|
// determine how many decoded bits need to be sent (including the size)
|
||||||
const totalBits = (dataByteCount * 8) + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
|
const totalBits = (dataByteCount * 8) + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
|
||||||
let encodingBitCount = totalBits;
|
let encodingBitCount = totalBits;
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(packetizationPanel.getErrorCorrection()) {
|
||||||
const blocks = Math.ceil(encodingBitCount / dataSize);
|
const blocks = Math.ceil(encodingBitCount / dataSize);
|
||||||
encodingBitCount = blocks * blockSize;
|
encodingBitCount = blocks * blockSize;
|
||||||
}
|
}
|
||||||
@@ -803,6 +777,8 @@ function resetGraphData() {
|
|||||||
function getAudioContext() {
|
function getAudioContext() {
|
||||||
if(!audioContext) {
|
if(!audioContext) {
|
||||||
audioContext = new (window.AudioContext || webkitAudioContext)();
|
audioContext = new (window.AudioContext || webkitAudioContext)();
|
||||||
|
frequencyPanel.setSampleRate(audioContext.sampleRate);
|
||||||
|
availableFskPairsPanel.setSampleRate(audioContext.sampleRate);
|
||||||
}
|
}
|
||||||
if(audioContext.state === 'suspended') {
|
if(audioContext.state === 'suspended') {
|
||||||
audioContext.resume();
|
audioContext.resume();
|
||||||
|
|||||||
Reference in New Issue
Block a user