show packet error stats
This commit is contained in:
@@ -10,7 +10,7 @@ import * as CRC from './CRC';
|
||||
|
||||
let SEGMENT_DURATION = 30;
|
||||
let PACKET_SIZE_BITS = 8;
|
||||
let DATA_SIZE_BITS = 8;
|
||||
let DATA_SIZE_BIT_COUNT = 8;
|
||||
let DATA_SIZE_CRC_BITS = 8;
|
||||
let DATA_CRC_BITS = 8;
|
||||
let BITS_PER_SAMPLE = 1;
|
||||
@@ -37,7 +37,7 @@ export const changeConfiguration = (config) => {
|
||||
} = config;
|
||||
SEGMENT_DURATION = segmentDurationMilliseconds;
|
||||
PACKET_SIZE_BITS = packetSizeBitCount;
|
||||
DATA_SIZE_BITS = dataSizeBitCount;
|
||||
DATA_SIZE_BIT_COUNT = dataSizeBitCount;
|
||||
DATA_SIZE_CRC_BITS = dataSizeCrcBitCount;
|
||||
DATA_CRC_BITS = dataCrcBitCount;
|
||||
BITS_PER_SAMPLE = bitsPerSegment;
|
||||
@@ -60,7 +60,7 @@ const decodePacket = (packetBits) => IS_ENCODED ? ENCODING.decode(packetBits) :
|
||||
export const getSegmentDurationMilliseconds = () => SEGMENT_DURATION;
|
||||
export const getPacketMaxByteCount = () => 2 ** PACKET_SIZE_BITS;
|
||||
export const getPacketMaxBitCount = () => (2 ** PACKET_SIZE_BITS) * 8;
|
||||
export const getDataMaxByteCount = () => 2 ** DATA_SIZE_BITS;
|
||||
export const getDataMaxByteCount = () => 2 ** DATA_SIZE_BIT_COUNT;
|
||||
export const getPacketEncodedBitCount = () => getPacketEncodingBlockCount() * PACKET_ENCODED_BLOCK_SIZE;
|
||||
export const getPacketEncodingBlockCount = () =>
|
||||
IS_ENCODED ? Math.floor(getPacketMaxBitCount() / PACKET_ENCODED_BLOCK_SIZE) : getPacketMaxBitCount();
|
||||
@@ -113,7 +113,7 @@ export const canSendPacket = () => {
|
||||
return IS_ENCODED ? maxBits >= PACKET_ENCODED_BLOCK_SIZE : true;
|
||||
}
|
||||
export const getPacketizationHeaderBitCount = (padUnusedBits = true) => {
|
||||
let count = DATA_SIZE_BITS + DATA_SIZE_CRC_BITS + DATA_CRC_BITS;
|
||||
let count = DATA_SIZE_BIT_COUNT + DATA_SIZE_CRC_BITS + DATA_CRC_BITS;
|
||||
if(padUnusedBits && count % 8 !== 0) {
|
||||
count += 8 - (count % 8);
|
||||
}
|
||||
@@ -196,8 +196,8 @@ export const pack = (bytes) => {
|
||||
let dataLengthBits = [];
|
||||
let dataLengthCrcBits = [];
|
||||
let dataSizeCrcNumber = 0;
|
||||
if(DATA_SIZE_BITS !== 0) {
|
||||
dataLengthBits = numberToBits(bytes.length, DATA_SIZE_BITS);
|
||||
if(DATA_SIZE_BIT_COUNT !== 0) {
|
||||
dataLengthBits = numberToBits(bytes.length, DATA_SIZE_BIT_COUNT);
|
||||
|
||||
// crc on data length
|
||||
if(DATA_SIZE_CRC_BITS !== 0) {
|
||||
@@ -217,7 +217,7 @@ export const pack = (bytes) => {
|
||||
const headers = [
|
||||
...dataLengthBits,
|
||||
...dataLengthCrcBits,
|
||||
...dataCrcBits
|
||||
...dataCrcBits,
|
||||
];
|
||||
// pad headers to take full bytes
|
||||
while(headers.length % 8 !== 0) {
|
||||
|
||||
@@ -162,20 +162,32 @@ class BasePanel {
|
||||
canvas.height = height;
|
||||
return this.append(canvas);
|
||||
}
|
||||
addProgressBar = (id, percent) => {
|
||||
addProgressBar = (id, ...percents) => {
|
||||
const progressBar = document.createElement('div');
|
||||
progressBar.className = 'progress-container';
|
||||
const bar = document.createElement('div');
|
||||
bar.id = this.childId(id);
|
||||
bar.className = 'progress-bar';
|
||||
bar.style.width = `${clamp(percent, 0, 1) * 100}%`;
|
||||
progressBar.append(bar);
|
||||
let sum = 0;
|
||||
for(let i = 0; i < percents.length; i++) {
|
||||
let percent = percents[i];
|
||||
percent = clamp(percent, 0, 1 - sum);
|
||||
sum += percent;
|
||||
const bar = document.createElement('div');
|
||||
bar.id = this.childId(`${id}-${i}`);
|
||||
bar.className = 'progress-bar';
|
||||
bar.style.width = `${clamp(percent, 0, 1) * 100}%`;
|
||||
progressBar.append(bar);
|
||||
}
|
||||
this.append(progressBar);
|
||||
}
|
||||
setProgressById = (id, percent) => {
|
||||
const element = document.getElementById(this.childId(id));
|
||||
if(!element) throw new Error(`Unable to find ${id}`);
|
||||
element.style.width = `${clamp(percent, 0, 1) * 100}%`;
|
||||
setProgressById = (id, ...percents) => {
|
||||
let sum = 0;
|
||||
for(let i = 0; i < percents.length; i++) {
|
||||
let percent = percents[i];
|
||||
percent = clamp(percent, 0, 1 - sum);
|
||||
sum += percent;
|
||||
const element = document.getElementById(this.childId(`${id}-${i}`));
|
||||
if(!element) throw new Error(`Unable to find ${id}`);
|
||||
element.style.width = `${clamp(percent, 0, 1) * 100}%`;
|
||||
}
|
||||
}
|
||||
childId = id => `${this.id}-${id}`;
|
||||
|
||||
|
||||
52
Panels/PacketErrorPanel.js
Normal file
52
Panels/PacketErrorPanel.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import BasePanel from './BasePanel';
|
||||
|
||||
class PacketErrorPanel extends BasePanel {
|
||||
constructor() {
|
||||
super('Packet Errors');
|
||||
|
||||
this.openField('CRC Check');
|
||||
this.addDynamicText('crc', 'N/A');
|
||||
this.closeField();
|
||||
|
||||
this.openField('CRC Size Check');
|
||||
this.addDynamicText('crc-size', 'N/A');
|
||||
this.closeField();
|
||||
|
||||
this.openField('Failed Packets');
|
||||
this.addDynamicText('failed-packet-count', 'N/A');
|
||||
this.addDynamicText('failed-packet-count-percent', '');
|
||||
this.closeField();
|
||||
|
||||
this.addSection('Packet Retransmission')
|
||||
|
||||
this.addRadios('repeat', [
|
||||
{ text: 'Automatic Repeat Request', value: 'arq', checked: true, eventName: 'hi' },
|
||||
{ text: 'Manual Repeat Request', value: 'manual', checked: true, eventName: 'hi' }
|
||||
]);
|
||||
|
||||
this.openField('Packets');
|
||||
this.addInputText('request-packet-indexes', '');
|
||||
this.closeField();
|
||||
|
||||
this.addButton('request-button', 'Request', 'requestPackets');
|
||||
}
|
||||
reset = () => {
|
||||
this.setFailedPacketIndeces([]);
|
||||
this.setSizeCrcUnavailable();
|
||||
this.setCrcUnavailable();
|
||||
}
|
||||
setFailedPacketIndeces = (packetIndexes) => {
|
||||
this.setValueById('request-packet-indexes', packetIndexes.join(', '));
|
||||
this.setValueById('failed-packet-count', packetIndexes.length.toLocaleString());
|
||||
}
|
||||
getFailedPacketIndeces = () => {
|
||||
let text = this.getValueById('request-packet-indexes');
|
||||
return text.replace(/\s+/g, '').split(',').map(Number);
|
||||
}
|
||||
setCrcPassed = (passed) => this.setValueById('crc', passed ? 'Pass' : 'Fail');
|
||||
setCrcUnavailable = () => this.setValueById('crc', 'N/A');
|
||||
setSizeCrcPassed = (passed) => this.setValueById('crc-size', passed ? 'Pass' : 'Fail');
|
||||
setSizeCrcUnavailable = () => this.setValueById('crc-size', 'N/A');
|
||||
}
|
||||
|
||||
export default PacketErrorPanel;
|
||||
@@ -15,7 +15,7 @@ class ReceivePanel extends BasePanel {
|
||||
this.addNewLine();
|
||||
this.addDynamicText('id-state', 'Offline.');
|
||||
|
||||
this.addProgressBar('progress', .50);
|
||||
this.addProgressBar('progress', .50, .25);
|
||||
|
||||
this.addCode('text', '', 'small');
|
||||
this.addImage('image', undefined, {width: 32, height: 32});
|
||||
@@ -69,7 +69,9 @@ class ReceivePanel extends BasePanel {
|
||||
// stopWaitingForSignal = () => {
|
||||
// AudioReceiver.stop();
|
||||
// }
|
||||
setProgress = percent => this.setProgressById('progress', percent);
|
||||
setProgress = (percent, percent2 = 0) => {
|
||||
this.setProgressById('progress', percent, percent2);
|
||||
}
|
||||
setReceivedHtml = (html) => this.setHtmlById('text', html);
|
||||
setReceivedBytes = bytes => {
|
||||
if(this.dataType === 'text') {
|
||||
@@ -84,6 +86,30 @@ class ReceivePanel extends BasePanel {
|
||||
this.display('text', value === 'text');
|
||||
this.display('image', value === 'image');
|
||||
}
|
||||
|
||||
setSuccessfulPacketCount = (count) => {
|
||||
this.successfulPacketCount = count;
|
||||
this.updateProgressBar();
|
||||
}
|
||||
setExpectedPacketCount = (count) => {
|
||||
this.expectedPacketCount = count;
|
||||
this.updateProgressBar();
|
||||
}
|
||||
setFailedPacketCount = (count) => {
|
||||
this.failedPacketCount = count;
|
||||
this.updateProgressBar();
|
||||
}
|
||||
updateProgressBar = () => {
|
||||
const total = this.expectedPacketCount;
|
||||
if(total === 0) {
|
||||
this.setProgress(0, 0);
|
||||
}
|
||||
this.setProgress(
|
||||
this.successfulPacketCount/total,
|
||||
this.failedPacketCount/total
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ReceivePanel;
|
||||
187
StreamManager.js
187
StreamManager.js
@@ -7,14 +7,24 @@ import {
|
||||
bytesToBits,
|
||||
numberToBytes,
|
||||
numberToHex,
|
||||
numberToAscii
|
||||
numberToAscii,
|
||||
bytesToNumber
|
||||
} from "./converters";
|
||||
|
||||
const dispatcher = new Dispatcher('StreamManager', ['change']);
|
||||
const dispatcher = new Dispatcher('StreamManager', [
|
||||
'change',
|
||||
'packetReceived',
|
||||
'packetFailed',
|
||||
'sizeReceived'
|
||||
]);
|
||||
let DATA = new Uint8ClampedArray();
|
||||
const FAILED_SEQUENCES = [];
|
||||
let FAILED_SEQUENCES = [];
|
||||
let SUCCESS_SEQUENCES = [];
|
||||
let SAMPLES_EXPECTED = 0;
|
||||
let SAMPLES_RECEIVED = 0;
|
||||
let DATA_CRC_BIT_COUNT = 0;
|
||||
let DATA_SIZE_BIT_COUNT = 0;
|
||||
let DATA_SIZE_CRC_BIT_COUNT = 0;
|
||||
|
||||
const BITS = [];
|
||||
let BITS_PER_PACKET = 0;
|
||||
@@ -29,10 +39,20 @@ let PACKET_ENCODING = {
|
||||
export const addEventListener = dispatcher.addListener;
|
||||
export const removeEventListener = dispatcher.removeListener;
|
||||
|
||||
const isPacketInRange = (packetIndex) => {
|
||||
// Blindly accept. We can't do anything about it for now
|
||||
if(!isSizeTrusted()) return true;
|
||||
const { packetCount } = PacketUtils.packetStats(getSize());
|
||||
return packetIndex < packetCount;
|
||||
}
|
||||
export const reset = () => {
|
||||
let changed = false;
|
||||
SAMPLES_RECEIVED = 0;
|
||||
SAMPLES_EXPECTED = 0;
|
||||
if(SUCCESS_SEQUENCES.length !== 0) {
|
||||
SUCCESS_SEQUENCES.length = 0;
|
||||
changed = true;
|
||||
}
|
||||
if(FAILED_SEQUENCES.length !== 0) {
|
||||
FAILED_SEQUENCES.length = 0;
|
||||
changed = true;
|
||||
@@ -66,6 +86,9 @@ export const applyPacket = ({
|
||||
bytes,
|
||||
size
|
||||
}) => {
|
||||
let trustedSize = isSizeTrusted();
|
||||
if(!isPacketInRange(sequence)) return;
|
||||
|
||||
const dataSize = PacketUtils.getPacketDataByteCount();
|
||||
const offset = sequence * dataSize;
|
||||
const length = offset + dataSize;
|
||||
@@ -73,39 +96,179 @@ export const applyPacket = ({
|
||||
if(FAILED_SEQUENCES.includes(sequence)) {
|
||||
FAILED_SEQUENCES.splice(FAILED_SEQUENCES.indexOf(sequence), 1);
|
||||
}
|
||||
if(!SUCCESS_SEQUENCES.includes(sequence)) {
|
||||
SUCCESS_SEQUENCES.push(sequence);
|
||||
}
|
||||
if(DATA.length < length) {
|
||||
const copy = new Uint8ClampedArray(length);
|
||||
copy.set(DATA.subarray(0, DATA.length), 0);
|
||||
DATA = copy;
|
||||
}
|
||||
DATA.set(bytes, offset);
|
||||
delete BITS[packetIndex];
|
||||
|
||||
if(!trustedSize && isSizeTrusted()) {
|
||||
// We may now have a trusted size. update prior failures.
|
||||
FAILED_SEQUENCES = FAILED_SEQUENCES.filter(isPacketInRange);
|
||||
dispatcher.emit('sizeReceived');
|
||||
}
|
||||
|
||||
dispatcher.emit('packetReceived');
|
||||
} else {
|
||||
console.log("Failed", sequence);
|
||||
if(!FAILED_SEQUENCES.includes(sequence))
|
||||
FAILED_SEQUENCES.push(sequence);
|
||||
// do nothing if previously successful
|
||||
if(!SUCCESS_SEQUENCES.includes(sequence)) {
|
||||
// NOTE: Can we trust the sequence?
|
||||
// Check if sequence out of range
|
||||
if(!FAILED_SEQUENCES.includes(sequence))
|
||||
FAILED_SEQUENCES.push(sequence);
|
||||
dispatcher.emit('packetFailed', {sequence});
|
||||
}
|
||||
}
|
||||
delete BITS[packetIndex]
|
||||
}
|
||||
export const getPercentReceived = () => {
|
||||
if(SAMPLES_EXPECTED === 0) return 0;
|
||||
return SAMPLES_RECEIVED / SAMPLES_EXPECTED;
|
||||
export const getFailedPacketIndeces = () => FAILED_SEQUENCES;
|
||||
export const countFailedPackets = () => FAILED_SEQUENCES.length;
|
||||
export const countSuccessfulPackets = () => SUCCESS_SEQUENCES.length;
|
||||
export const countExpectedPackets = () => {
|
||||
if(!isSizeTrusted()) return 0;
|
||||
return PacketUtils.packetStats(getSize()).packetCount;
|
||||
}
|
||||
export const setPacketsExpected = packetCount => {
|
||||
if(packetCount < 0 || packetCount === Infinity) packetCount = 0;
|
||||
// used when requesting individual packets out of sequence
|
||||
SAMPLES_EXPECTED = packetCount * PacketUtils.getPacketSegmentCount();
|
||||
}
|
||||
|
||||
export const getSizeAvailable = () => {
|
||||
if(DATA_SIZE_BIT_COUNT === 0) return 1;
|
||||
let lastBit = DATA_SIZE_BIT_COUNT;
|
||||
let lastByte = Math.ceil(lastBit / 8);
|
||||
if(DATA.length < lastByte) return false;
|
||||
|
||||
// Do we have a crc check on the size?
|
||||
if(DATA_SIZE_CRC_BIT_COUNT !== 0) {
|
||||
return getSizeCrcAvailable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export const isSizeTrusted = () => {
|
||||
if(!getSizeAvailable()) return false;
|
||||
if(DATA_SIZE_CRC_BIT_COUNT !== 0) return getSizeCrcPassed();
|
||||
return true;
|
||||
}
|
||||
export const getSize = () => {
|
||||
if(DATA_SIZE_BIT_COUNT === 0) return 1;
|
||||
if(!getSizeAvailable()) return -1;
|
||||
let firstBit = 0;
|
||||
let lastBit = DATA_SIZE_BIT_COUNT;
|
||||
|
||||
// Do we have the data?
|
||||
let firstByte = Math.floor(firstBit / 8);
|
||||
let lastByte = Math.ceil(lastBit / 8);
|
||||
if(DATA.length < lastByte) return -1;
|
||||
|
||||
// Grab the data
|
||||
let bits = bytesToBits(DATA.subarray(firstByte, lastByte));
|
||||
if(firstBit % 8 !== 0) {
|
||||
bits.splice(firstBit % 8);
|
||||
}
|
||||
bits.length = DATA_SIZE_BIT_COUNT
|
||||
|
||||
return bitsToInt(bits, DATA_SIZE_BIT_COUNT);
|
||||
}
|
||||
export const getSizeCrc = () => {
|
||||
if(!getSizeCrcAvailable()) return CRC.INVALID;
|
||||
|
||||
let startBitIndex = DATA_SIZE_BIT_COUNT;
|
||||
let endBitIndex = startBitIndex + DATA_SIZE_CRC_BIT_COUNT;
|
||||
|
||||
let startByte = Math.floor(startBitIndex / 8);
|
||||
let endByte = Math.ceil(endBitIndex / 8);
|
||||
if(DATA.length < endByte) return CRC.INVALID;
|
||||
|
||||
let bits = bytesToBits(DATA.subarray(startByte, endByte));
|
||||
if(startBitIndex % 8 !== 0) bits.splice(0, startBitIndex);
|
||||
bits.length = DATA_SIZE_CRC_BIT_COUNT;
|
||||
return bitsToInt(bits, DATA_SIZE_CRC_BIT_COUNT);
|
||||
}
|
||||
export const getCrc = () => {
|
||||
if(!getCrcAvailable()) return CRC.INVALID;
|
||||
|
||||
let startBitIndex = DATA_SIZE_BIT_COUNT + DATA_SIZE_CRC_BIT_COUNT;
|
||||
let endBitIndex = startBitIndex + DATA_CRC_BIT_COUNT;
|
||||
|
||||
let startByte = Math.floor(startBitIndex / 8);
|
||||
let endByte = Math.ceil(endBitIndex / 8);
|
||||
if(DATA.length < endByte) return CRC.INVALID;
|
||||
|
||||
let bits = bytesToBits(DATA.subarray(startByte, endByte));
|
||||
if(startBitIndex % 8 !== 0) bits.splice(0, startBitIndex);
|
||||
bits.length = DATA_CRC_BIT_COUNT;
|
||||
return bitsToInt(bits, DATA_CRC_BIT_COUNT);
|
||||
}
|
||||
export const getSizeCrcAvailable = () => {
|
||||
if (DATA_SIZE_BIT_COUNT === 0) return false;
|
||||
if (DATA_SIZE_CRC_BIT_COUNT === 0) return false;
|
||||
const bitsNeeded = DATA_SIZE_BIT_COUNT + DATA_SIZE_CRC_BIT_COUNT;
|
||||
return DATA.length >= Math.ceil(bitsNeeded / 8);
|
||||
}
|
||||
export const getCrcAvailable = () => {
|
||||
if(DATA_CRC_BIT_COUNT === 0) return false;
|
||||
if(!getSizeAvailable()) return false;
|
||||
let byteCount = getSize();
|
||||
if(DATA.length < byteCount) return false;
|
||||
// Do we have enough bytes for the headers and underlying data?
|
||||
let headerBitCount = DATA_SIZE_BIT_COUNT + DATA_CRC_BIT_COUNT + DATA_SIZE_CRC_BIT_COUNT;
|
||||
if(headerBitCount % 8 !== 0)
|
||||
headerBitCount += 8 - (headerBitCount % 8);
|
||||
const headerByteCount = headerBitCount / 8;
|
||||
byteCount += headerByteCount;
|
||||
|
||||
return DATA.length >= byteCount;
|
||||
}
|
||||
export const getSizeCrcPassed = () => {
|
||||
if(!getSizeCrcAvailable()) return false;
|
||||
const size = getSize();
|
||||
const sizeCrc = getSizeCrc();
|
||||
if(sizeCrc === CRC.INVALID) return false;
|
||||
const crc = CRC.check(numberToBytes(size, DATA_SIZE_BIT_COUNT), DATA_SIZE_CRC_BIT_COUNT);
|
||||
return crc === sizeCrc;
|
||||
}
|
||||
export const getCrcPassed = () => {
|
||||
if(!getCrcAvailable()) return false;
|
||||
if(!isSizeTrusted()) return false;
|
||||
|
||||
const size = getSize();
|
||||
const crc = getCrc();
|
||||
if(crc === CRC.INVALID) return false;
|
||||
// Get Data
|
||||
|
||||
// How large is our header?
|
||||
let headerBitCount = DATA_CRC_BIT_COUNT + DATA_SIZE_BIT_COUNT + DATA_SIZE_CRC_BIT_COUNT;
|
||||
if(headerBitCount % 8 !== 0) headerBitCount += 8 - (headerBitCount % 8);
|
||||
let headerByteCount = headerBitCount / 8;
|
||||
|
||||
// Get bytes needed to perform CRC check on
|
||||
const data = DATA.subarray(headerByteCount, headerByteCount + size);
|
||||
|
||||
// Do the check
|
||||
return crc === CRC.check(data, DATA_CRC_BIT_COUNT);
|
||||
}
|
||||
export const changeConfiguration = ({
|
||||
segmentsPerPacket,
|
||||
bitsPerPacket,
|
||||
bitsPerSegment,
|
||||
streamHeaders
|
||||
streamHeaders,
|
||||
dataCrcBitLength,
|
||||
dataSizeBitCount,
|
||||
dataSizeCrcBitCount
|
||||
}) => {
|
||||
BITS_PER_PACKET = bitsPerPacket;
|
||||
SEGMENTS_PER_PACKET = segmentsPerPacket;
|
||||
BITS_PER_SEGMENT = bitsPerSegment;
|
||||
STREAM_HEADERS = streamHeaders;
|
||||
DATA_CRC_BIT_COUNT = dataCrcBitLength;
|
||||
DATA_SIZE_BIT_COUNT = dataSizeBitCount;
|
||||
DATA_SIZE_CRC_BIT_COUNT = dataSizeCrcBitCount;
|
||||
}
|
||||
const noEncoding = bits => bits;
|
||||
export const setPacketEncoding = ({ encode, decode } = {}) => {
|
||||
@@ -118,6 +281,8 @@ export const addSample = (
|
||||
bits
|
||||
) => {
|
||||
SAMPLES_RECEIVED++;
|
||||
|
||||
|
||||
if(BITS[packetIndex] === undefined) {
|
||||
BITS[packetIndex] = [];
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@ export function numberToBits(number, bitLength) {
|
||||
bits.push((number >> i) & 1);
|
||||
return bits;
|
||||
}
|
||||
export function bytesToNumber(bytes) {
|
||||
let number = 0;
|
||||
for(let i = 0; i < bytes.length; i++) {
|
||||
number += bytes[i] << (8 * i);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
export function bytesToText(bytes) {
|
||||
if(!(bytes instanceof ArrayBuffer || ArrayBuffer.isView(bytes))) {
|
||||
bytes = new Uint8Array(bytes).buffer;
|
||||
@@ -25,6 +32,9 @@ export function bytesToText(bytes) {
|
||||
return new TextDecoder().decode(bytes);
|
||||
}
|
||||
export function bytesToBits(bytes) {
|
||||
if(ArrayBuffer.isView(bytes)) {
|
||||
bytes = Array.from(bytes);
|
||||
}
|
||||
if(!Array.isArray(bytes)) return [];
|
||||
return bytes.reduce((bits, byte) => [
|
||||
...bits,
|
||||
|
||||
47
index.js
47
index.js
@@ -15,27 +15,19 @@ import SignalPanel from "./Panels/SignalPanel";
|
||||
import PacketizationPanel from "./Panels/PacketizationPanel";
|
||||
import AvailableFskPairsPanel from "./Panels/AvailableFskPairsPanel";
|
||||
import FrequencyGraphPanel from "./Panels/FrequencyGraphPanel";
|
||||
import GraphConfigurationPanel from './Panels/GraphConfigurationPanel'
|
||||
import GraphConfigurationPanel from './Panels/GraphConfigurationPanel';
|
||||
import PacketErrorPanel from './Panels/PacketErrorPanel';
|
||||
import SpeedPanel from './Panels/SpeedPanel';
|
||||
import {
|
||||
bitsToInt,
|
||||
bitsToBytes,
|
||||
bitsToText,
|
||||
bytesToBits,
|
||||
bytesToText,
|
||||
numberToBytes,
|
||||
numberToBits,
|
||||
numberToHex,
|
||||
textToBits,
|
||||
textToBytes,
|
||||
} from './converters';
|
||||
import MicrophonePanel from "./Panels/MicrophonePanel";
|
||||
import ReceivePanel from "./Panels/ReceivePanel";
|
||||
var audioContext;
|
||||
var microphoneStream;
|
||||
var microphoneNode;
|
||||
var analyser;
|
||||
var sentDataTextArea;
|
||||
|
||||
// bits as they are sent
|
||||
let SENT_ORIGINAL_TEXT = '';
|
||||
@@ -72,6 +64,7 @@ const graphConfigurationPanel = new GraphConfigurationPanel();
|
||||
const speedPanel = new SpeedPanel();
|
||||
const microphonePanel = new MicrophonePanel();
|
||||
const receivePanel = new ReceivePanel();
|
||||
const packetErrorPanel = new PacketErrorPanel();
|
||||
|
||||
function handleWindowLoad() {
|
||||
const panelContainer = document.getElementById('panel-container');
|
||||
@@ -84,6 +77,7 @@ function handleWindowLoad() {
|
||||
panelContainer.prepend(signalPanel.getDomElement());
|
||||
panelContainer.prepend(bitsReceivedPanel.getDomElement());
|
||||
panelContainer.prepend(bitsSentPanel.getDomElement());
|
||||
panelContainer.prepend(packetErrorPanel.getDomElement());
|
||||
panelContainer.prepend(receivePanel.getDomElement());
|
||||
panelContainer.prepend(microphonePanel.getDomElement());
|
||||
panelContainer.prepend(communicationsPanel.getDomElement());
|
||||
@@ -103,9 +97,14 @@ function handleWindowLoad() {
|
||||
receivePanel.setDataType(dataType);
|
||||
})
|
||||
receivePanel.setDataType(messagePanel.getDataType());
|
||||
receivePanel.setProgress(0);
|
||||
receivePanel.setExpectedPacketCount(100);
|
||||
receivePanel.setFailedPacketCount(25);
|
||||
receivePanel.setSuccessfulPacketCount(50);
|
||||
|
||||
receivePanel.setReceivedHtml('Ready.');
|
||||
|
||||
packetErrorPanel.reset();
|
||||
|
||||
bitsSentPanel.setCode('');
|
||||
bitsReceivedPanel.setCode('');
|
||||
|
||||
@@ -222,9 +221,25 @@ function handleWindowLoad() {
|
||||
AudioSender.addEventListener('end', () => messagePanel.setSendButtonText('Send'));
|
||||
// Setup stream manager
|
||||
StreamManager.addEventListener('change', handleStreamManagerChange);
|
||||
StreamManager.addEventListener('packetFailed', () => {
|
||||
packetErrorPanel.setFailedPacketIndeces(StreamManager.getFailedPacketIndeces());
|
||||
});
|
||||
StreamManager.addEventListener('packetReceived', () => {
|
||||
// Failed indices changed?
|
||||
packetErrorPanel.setFailedPacketIndeces(StreamManager.getFailedPacketIndeces());
|
||||
if(StreamManager.getSizeCrcAvailable()) {
|
||||
packetErrorPanel.setSizeCrcPassed(StreamManager.getSizeCrcPassed());
|
||||
} else {
|
||||
packetErrorPanel.setSizeCrcUnavailable();
|
||||
}
|
||||
if(StreamManager.getCrcAvailable()) {
|
||||
packetErrorPanel.setCrcPassed(StreamManager.getCrcPassed());
|
||||
} else {
|
||||
packetErrorPanel.setCrcUnavailable();
|
||||
}
|
||||
});
|
||||
|
||||
// grab dom elements
|
||||
sentDataTextArea = document.getElementById('sent-data');
|
||||
const receivedChannelGraph = document.getElementById('received-channel-graph');
|
||||
receivedChannelGraph.addEventListener('mouseover', handleReceivedChannelGraphMouseover);
|
||||
receivedChannelGraph.addEventListener('mouseout', handleReceivedChannelGraphMouseout);
|
||||
@@ -303,6 +318,9 @@ function updateStreamManager() {
|
||||
bitsPerPacket: PacketUtils.getPacketMaxBitCount(),
|
||||
segmentsPerPacket: PacketUtils.getPacketSegmentCount(),
|
||||
bitsPerSegment: availableFskPairsPanel.getSelectedFskPairs().length,
|
||||
dataCrcBitLength: packetizationPanel.getDataCrc(),
|
||||
dataSizeBitCount: packetizationPanel.getDataSizePower(),
|
||||
dataSizeCrcBitCount: packetizationPanel.getDataSizeCrc(),
|
||||
streamHeaders: {
|
||||
'transfer byte count': {
|
||||
index: 0,
|
||||
@@ -549,8 +567,9 @@ function resumeGraph() {
|
||||
}
|
||||
|
||||
function handleStreamManagerChange() {
|
||||
|
||||
receivePanel.setProgress(StreamManager.getPercentReceived());
|
||||
receivePanel.setSuccessfulPacketCount(StreamManager.countSuccessfulPackets());
|
||||
receivePanel.setExpectedPacketCount(StreamManager.countExpectedPackets());
|
||||
receivePanel.setFailedPacketCount(StreamManager.countFailedPackets());
|
||||
|
||||
const bytes = StreamManager.getDataBytes();
|
||||
const receivedText = bytesToText(bytes);
|
||||
|
||||
@@ -66,10 +66,12 @@ canvas {
|
||||
min-height: 14px;
|
||||
background-color: yellow;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
left: 0;
|
||||
width: 0;
|
||||
/* transition: width 0.3s ease; */
|
||||
display: inline-block;
|
||||
transition: width 1s ease;
|
||||
}
|
||||
.progress-bar:nth-child(2) {
|
||||
background-color: red;
|
||||
}
|
||||
.xprogress-container::after {
|
||||
content: attr(data-percent) '%';
|
||||
|
||||
Reference in New Issue
Block a user