separate bits into blocks & packets
This commit is contained in:
12
index.html
12
index.html
@@ -17,7 +17,7 @@
|
|||||||
</label><br />
|
</label><br />
|
||||||
<input type="text" id="text-to-send">
|
<input type="text" id="text-to-send">
|
||||||
<button id="send-button">Send</button><br />
|
<button id="send-button">Send</button><br />
|
||||||
<textarea id="sent-data" rows="10" cols="40"></textarea><br />
|
<div class="raw-data" id="sent-data"></div><br />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Data</h2>
|
<h2>Data</h2>
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
Data Bits per Packet: <span id="packet-data-bit-count"></span><br>
|
Data Bits per Packet: <span id="packet-data-bit-count"></span><br>
|
||||||
Error Correction: <span id="packet-error-correction"></span><br>
|
Error Correction: <span id="packet-error-correction"></span><br>
|
||||||
Error Blocks per packet: <span id="packet-error-block-count"></span><br>
|
Error Blocks per packet: <span id="packet-error-block-count"></span><br>
|
||||||
|
Error Bits per block: <span id="packet-error-bits-per-block"></span><br>
|
||||||
|
Error Correcting Bits per Packet: <span id="packet-error-bit-count"></span><br>
|
||||||
Unused bits per packet: <span id="packet-unused-bit-count"></span><br>
|
Unused bits per packet: <span id="packet-unused-bit-count"></span><br>
|
||||||
Unused bits in last packet: <span id="last-packet-unused-bit-count"></span><br>
|
Unused bits in last packet: <span id="last-packet-unused-bit-count"></span><br>
|
||||||
Last segment unused channels in packet: <span id="last-segment-unused-channel-count"></span><br>
|
Last segment unused channels in packet: <span id="last-segment-unused-channel-count"></span><br>
|
||||||
@@ -38,8 +40,12 @@
|
|||||||
Total Duration: <span id="data-transfer-duration"></span><br>
|
Total Duration: <span id="data-transfer-duration"></span><br>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Encoded</h2>
|
<h2>Error Correcting</h2>
|
||||||
<textarea id="encoded-data" rows="10" cols="40"></textarea><br />
|
<div class="raw-data" id="error-correcting-data"></div><br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 >Bits Sent</h2>
|
||||||
|
<div class="raw-data" id="actual-bits-to-send"></div><br />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
229
index.js
229
index.js
@@ -12,6 +12,11 @@ var receivedGraph;
|
|||||||
var receivedData = [];
|
var receivedData = [];
|
||||||
var MAX_AMPLITUDE = 300; // Higher than 255 to give us space
|
var MAX_AMPLITUDE = 300; // Higher than 255 to give us space
|
||||||
|
|
||||||
|
let RECEIVED_STREAM_DECODED_BITS = [];
|
||||||
|
let RECEIVED_PACKET_DECODED_BITS = [];
|
||||||
|
let RECEIVED_PACKET_BITS = [];
|
||||||
|
let RECEIVED_STREAM_BITS = [];
|
||||||
|
|
||||||
const CHANNEL_OSCILLATORS = [];
|
const CHANNEL_OSCILLATORS = [];
|
||||||
|
|
||||||
// bit stream
|
// bit stream
|
||||||
@@ -301,6 +306,8 @@ function updatePacketStats() {
|
|||||||
document.getElementById('data-transfer-duration').innerText = getDataTransferDurationSeconds(bitCount).toLocaleString() + 's';
|
document.getElementById('data-transfer-duration').innerText = getDataTransferDurationSeconds(bitCount).toLocaleString() + 's';
|
||||||
document.getElementById('segments-per-packet').innerText = getPacketSegmentCount().toLocaleString();
|
document.getElementById('segments-per-packet').innerText = getPacketSegmentCount().toLocaleString();
|
||||||
document.getElementById('total-segments').innerText = getTotalSegmentCount(bitCount).toLocaleString();
|
document.getElementById('total-segments').innerText = getTotalSegmentCount(bitCount).toLocaleString();
|
||||||
|
document.getElementById('packet-error-bits-per-block').innerText = (HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_BLOCK_SIZE : 0).toLocaleString();
|
||||||
|
document.getElementById('packet-error-bit-count').innerText = getPacketErrorBitCount();
|
||||||
}
|
}
|
||||||
function drawChannels() {
|
function drawChannels() {
|
||||||
const sampleRate = getAudioContext().sampleRate;
|
const sampleRate = getAudioContext().sampleRate;
|
||||||
@@ -343,14 +350,6 @@ function drawChannels() {
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
const binWidth = (1 / frequencySegments) * width;
|
|
||||||
for(let x = 0; x < width; x+= binWidth * 2) {
|
|
||||||
console.log(x);
|
|
||||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
|
|
||||||
ctx.fillRect(x, 0, binWidth, height);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function percentInFrequency(hz, frequencyResolution) {
|
function percentInFrequency(hz, frequencyResolution) {
|
||||||
@@ -505,16 +504,23 @@ function sendBits(bits) {
|
|||||||
const totalDurationSeconds = getDataTransferDurationSeconds(bitCount);
|
const totalDurationSeconds = getDataTransferDurationSeconds(bitCount);
|
||||||
const totalDurationMilliseconds = getDataTransferDurationMilliseconds(bitCount);
|
const totalDurationMilliseconds = getDataTransferDurationMilliseconds(bitCount);
|
||||||
|
|
||||||
|
const channelCount = getChannels().length;
|
||||||
|
const errorCorrectionBits = [];
|
||||||
|
const interleavingBits = [];
|
||||||
|
|
||||||
createOscillators(startSeconds);
|
createOscillators(startSeconds);
|
||||||
// send all packets
|
// send all packets
|
||||||
for(let i = 0; i < packetCount; i++) {
|
for(let i = 0; i < packetCount; i++) {
|
||||||
let packet = getPacketBits(bits, i);
|
let packet = getPacketBits(bits, i);
|
||||||
|
errorCorrectionBits.push(...packet);
|
||||||
if(packet.length > packetBitCount) {
|
if(packet.length > packetBitCount) {
|
||||||
console.error('Too many bits in the packet.');
|
console.error('Too many bits in the packet.');
|
||||||
disconnectOscillators();
|
disconnectOscillators();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
packet = padArray(packet, packetBitCount, 0);
|
||||||
packet = applyInterleaving(packet);
|
packet = applyInterleaving(packet);
|
||||||
|
interleavingBits.push(...packet);
|
||||||
EXPECTED_ENCODED_BITS.push(...packet);
|
EXPECTED_ENCODED_BITS.push(...packet);
|
||||||
sendPacket(packet, startSeconds + (i * packetDurationSeconds));
|
sendPacket(packet, startSeconds + (i * packetDurationSeconds));
|
||||||
}
|
}
|
||||||
@@ -524,10 +530,31 @@ function sendBits(bits) {
|
|||||||
startMilliseconds + totalDurationMilliseconds
|
startMilliseconds + totalDurationMilliseconds
|
||||||
);
|
);
|
||||||
// show what was sent
|
// show what was sent
|
||||||
document.getElementById('sent-data').value =
|
|
||||||
EXPECTED_BITS.reduce(bitReducer, '');
|
// original bits
|
||||||
document.getElementById('encoded-data').value =
|
document.getElementById('sent-data').innerHTML =
|
||||||
EXPECTED_ENCODED_BITS.reduce(bitReducer, '');
|
EXPECTED_BITS.reduce(bitReducer(
|
||||||
|
getPacketDataBitCount(),
|
||||||
|
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
|
||||||
|
), '');
|
||||||
|
|
||||||
|
// error correcting bits
|
||||||
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
|
document.getElementById('error-correcting-data').innerHTML =
|
||||||
|
errorCorrectionBits.reduce(bitReducer(
|
||||||
|
getPacketErrorBitCount(),
|
||||||
|
ERROR_CORRECTION_BLOCK_SIZE
|
||||||
|
), '');
|
||||||
|
} else {
|
||||||
|
document.getElementById('error-correcting-data').innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('actual-bits-to-send').innerHTML =
|
||||||
|
interleavingBits.reduce(bitReducer(
|
||||||
|
getPacketBitCount() + getPacketLastSegmentUnusedChannelCount(),
|
||||||
|
channelCount,
|
||||||
|
(packetIndex, blockIndex) => `${blockIndex === 0 ? '' : '<br>'}Segment ${blockIndex}: `
|
||||||
|
), '');
|
||||||
|
|
||||||
// start the graph moving again
|
// start the graph moving again
|
||||||
resumeGraph();
|
resumeGraph();
|
||||||
@@ -583,13 +610,7 @@ function getPacketCount(bitCount) {
|
|||||||
}
|
}
|
||||||
function getPacketBits(bits, packetIndex) {
|
function getPacketBits(bits, packetIndex) {
|
||||||
if(!canSendPacket()) return [];
|
if(!canSendPacket()) return [];
|
||||||
const packetBits = getPacketUsedBits(bits, packetIndex);
|
return getPacketUsedBits(bits, packetIndex);
|
||||||
|
|
||||||
// How many bits expected in our packet?
|
|
||||||
const packetBitCount = getPacketBitCount();
|
|
||||||
|
|
||||||
// pad the array to the entire packet size
|
|
||||||
return padArray(packetBits, packetBitCount, 0);
|
|
||||||
}
|
}
|
||||||
function getPacketUsedBits(bits, packetIndex) {
|
function getPacketUsedBits(bits, packetIndex) {
|
||||||
if(!canSendPacket()) return [];
|
if(!canSendPacket()) return [];
|
||||||
@@ -622,6 +643,9 @@ function getPacketErrorBlockCount() {
|
|||||||
ERROR_CORRECTION_BLOCK_SIZE
|
ERROR_CORRECTION_BLOCK_SIZE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function getPacketErrorBitCount() {
|
||||||
|
return getPacketErrorBlockCount() * ERROR_CORRECTION_BLOCK_SIZE;
|
||||||
|
}
|
||||||
function canSendPacket() {
|
function canSendPacket() {
|
||||||
const max = getPacketBitCount();
|
const max = getPacketBitCount();
|
||||||
// Need at least 1 bit to send
|
// Need at least 1 bit to send
|
||||||
@@ -639,7 +663,12 @@ function getPacketLastSegmentUnusedChannelCount() {
|
|||||||
return (channelCount - (getPacketBitCount() % channelCount));
|
return (channelCount - (getPacketBitCount() % channelCount));
|
||||||
}
|
}
|
||||||
function getPacketUnusedBitCount() {
|
function getPacketUnusedBitCount() {
|
||||||
return getPacketBitCount() - getPacketDataBitCount();
|
const bitsAvailable = getPacketBitCount();
|
||||||
|
let bitsUsed = bitsAvailable;
|
||||||
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
|
bitsUsed = getPacketErrorBitCount();
|
||||||
|
}
|
||||||
|
return bitsAvailable - bitsUsed;
|
||||||
}
|
}
|
||||||
function getPacketLastUnusedBitCount(bitCount) {
|
function getPacketLastUnusedBitCount(bitCount) {
|
||||||
const availableBits = getPacketBitCount();
|
const availableBits = getPacketBitCount();
|
||||||
@@ -764,7 +793,8 @@ function collectSample() {
|
|||||||
hasSignal: hadPriorSignal,
|
hasSignal: hadPriorSignal,
|
||||||
streamStarted: initialStreamStart = -1,
|
streamStarted: initialStreamStart = -1,
|
||||||
streamEnded: priorStreamEnded = -1,
|
streamEnded: priorStreamEnded = -1,
|
||||||
segmentIndex: priorSegmentIndex = -1
|
segmentIndex: priorSegmentIndex = -1,
|
||||||
|
packetIndex: priorPacketIndex = -1
|
||||||
} = frequencyOverTime[0] ?? {}
|
} = frequencyOverTime[0] ?? {}
|
||||||
const data = {
|
const data = {
|
||||||
time,
|
time,
|
||||||
@@ -775,43 +805,51 @@ function collectSample() {
|
|||||||
// Get amplitude of each channels set of frequencies
|
// Get amplitude of each channels set of frequencies
|
||||||
data.pairs = getChannels().map(hzSet => hzSet.map(hz => frequencies[Math.round(hz / length)]));
|
data.pairs = getChannels().map(hzSet => hzSet.map(hz => frequencies[Math.round(hz / length)]));
|
||||||
const hasSignal = data.hasSignal = data.pairs.some(amps => amps.some(amp => amp > AMPLITUDE_THRESHOLD));
|
const hasSignal = data.hasSignal = data.pairs.some(amps => amps.some(amp => amp > AMPLITUDE_THRESHOLD));
|
||||||
|
let processPacket = false;
|
||||||
if(hasSignal) {
|
if(hasSignal) {
|
||||||
if(hadPriorSignal) {
|
if(hadPriorSignal) {
|
||||||
// continued bit stream
|
// continued bit stream
|
||||||
data.streamStarted = initialStreamStart;
|
data.streamStarted = initialStreamStart;
|
||||||
|
|
||||||
// proposed end
|
|
||||||
data.streamEnded = priorStreamEnded;
|
data.streamEnded = priorStreamEnded;
|
||||||
|
data.packetIndex = priorPacketIndex;
|
||||||
|
|
||||||
|
if(time > priorStreamEnded) {
|
||||||
|
processPacketReceived(priorPacketIndex, initialStreamStart, priorStreamEnded);
|
||||||
|
// new packet
|
||||||
|
data.streamStarted = priorStreamEnded;
|
||||||
|
data.streamEnded = initialStreamStart + getPacketDurationMilliseconds();
|
||||||
|
data.packetIndex = priorPacketIndex + 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const totalBits = 2 ** PACKET_SIZE_BITS;
|
|
||||||
const segments = Math.ceil(totalBits / channelCount);
|
|
||||||
const duration = segments * SEGMENT_DURATION;
|
|
||||||
if(pauseGraphId) {
|
if(pauseGraphId) {
|
||||||
window.clearTimeout(pauseGraphId);
|
window.clearTimeout(pauseGraphId);
|
||||||
pauseGraphId = undefined;
|
pauseGraphId = undefined;
|
||||||
// recover prior bit stream
|
// recover prior bit stream
|
||||||
data.streamStarted = LAST_STREAM_STARTED;
|
data.streamStarted = LAST_STREAM_STARTED;
|
||||||
data.streamEnded = LAST_STREAM_STARTED + duration;
|
data.streamEnded = LAST_STREAM_STARTED + getPacketDurationMilliseconds();
|
||||||
} else {
|
} else {
|
||||||
// new bit stream
|
// new bit stream
|
||||||
data.streamStarted = time;
|
data.streamStarted = time;
|
||||||
LAST_STREAM_STARTED = time;
|
LAST_STREAM_STARTED = time;
|
||||||
|
data.packetIndex = 0;
|
||||||
// clear last packet
|
// clear last packet
|
||||||
packetReceivedBits.length = 0;
|
packetReceivedBits.length = 0;
|
||||||
packetUninterlievedBits.length = 0;
|
packetUninterlievedBits.length = 0;
|
||||||
packetDataByteCount = 0;
|
packetDataByteCount = 0;
|
||||||
data.streamEnded = time + duration;
|
data.streamEnded = time + getPacketDurationMilliseconds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// number of bit in the stream
|
// number of bit in the packet
|
||||||
const segmentIndex = data.segmentIndex = Math.floor((time - data.streamStarted) / SEGMENT_DURATION);
|
const segmentIndex = data.segmentIndex = Math.floor((time - data.streamStarted) / SEGMENT_DURATION);
|
||||||
if(priorSegmentIndex !== segmentIndex && priorSegmentIndex > -1) {
|
if(priorPacketIndex !== data.packetIndex ||
|
||||||
|
(priorSegmentIndex !== segmentIndex && priorSegmentIndex > -1)
|
||||||
|
) {
|
||||||
processSegment = true;
|
processSegment = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data.segmentIndex = -1;
|
data.segmentIndex = -1;
|
||||||
|
data.packetIndex = -1;
|
||||||
if(hadPriorSignal) {
|
if(hadPriorSignal) {
|
||||||
// just stopped
|
// just stopped
|
||||||
data.streamStarted = -1;
|
data.streamStarted = -1;
|
||||||
@@ -828,6 +866,7 @@ function collectSample() {
|
|||||||
pauseGraphId = window.setTimeout(() => {
|
pauseGraphId = window.setTimeout(() => {
|
||||||
pauseGraphId = undefined;
|
pauseGraphId = undefined;
|
||||||
if(PAUSE_AFTER_END) stopGraph();
|
if(PAUSE_AFTER_END) stopGraph();
|
||||||
|
processPacketReceived(priorPacketIndex, initialStreamStart, priorStreamEnded);
|
||||||
}, SEGMENT_DURATION * 2);
|
}, SEGMENT_DURATION * 2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -863,72 +902,140 @@ function GET_SEGMENT_BITS(streamStarted, segmentIndex, originalOrder = false) {
|
|||||||
const bitValues = sums.map((amps) => amps[0] > amps[1] ? 0 : 1);
|
const bitValues = sums.map((amps) => amps[0] > amps[1] ? 0 : 1);
|
||||||
return originalOrder ? bitValues : removeInterleaving(bitValues);
|
return originalOrder ? bitValues : removeInterleaving(bitValues);
|
||||||
}
|
}
|
||||||
function processSegmentReceived(streamStarted, segmentIndex) {
|
|
||||||
const {
|
function processPacketReceived(packetIndex, startMs, endMs) {
|
||||||
pairs: {
|
if(packetIndex === 0) {
|
||||||
length: channelCount
|
// Reset received data from last stream
|
||||||
}
|
RECEIVED_STREAM_BITS.length = 0;
|
||||||
} = frequencyOverTime[0];
|
RECEIVED_STREAM_DECODED_BITS.length = 0;
|
||||||
|
}
|
||||||
|
// append to the stream
|
||||||
|
RECEIVED_STREAM_BITS.push(...RECEIVED_PACKET_BITS);
|
||||||
|
RECEIVED_STREAM_DECODED_BITS.push(...RECEIVED_PACKET_DECODED_BITS);
|
||||||
|
|
||||||
|
// reset the packet
|
||||||
|
RECEIVED_PACKET_BITS.length = 0;
|
||||||
|
RECEIVED_PACKET_DECODED_BITS.length = 0;
|
||||||
|
packetReceivedBits.length = 0;
|
||||||
|
packetUninterlievedBits.length = 0;
|
||||||
|
packetDecodedBits.length = 0;
|
||||||
|
// display what was received
|
||||||
|
updateReceivedData();
|
||||||
|
}
|
||||||
|
function processSegmentReceived(packetStarted, segmentIndex) {
|
||||||
// is our segment long enough?
|
// is our segment long enough?
|
||||||
|
|
||||||
const samples = frequencyOverTime.filter(
|
const samples = frequencyOverTime.filter(
|
||||||
fot => fot.streamStarted === streamStarted &&
|
fot => fot.streamStarted === packetStarted &&
|
||||||
fot.segmentIndex === segmentIndex
|
fot.segmentIndex === segmentIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
let bitValues;
|
let bitValues;
|
||||||
if(samples.length === 0) {
|
if(samples.length === 0) {
|
||||||
// nothing collected
|
// nothing collected
|
||||||
// bitValues = new Array(channelCount).fill(0);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const sampleEnd = samples[0].time;
|
const sampleEnd = samples[0].time;
|
||||||
const sampleStart = streamStarted + (segmentIndex * SEGMENT_DURATION);
|
const sampleStart = packetStarted + (segmentIndex * SEGMENT_DURATION);
|
||||||
const sampleDuration = (sampleEnd - sampleStart) + MINIMUM_INTERVAL_MS;
|
const sampleDuration = (sampleEnd - sampleStart) + MINIMUM_INTERVAL_MS;
|
||||||
|
|
||||||
// not long enough to qualify as a segment
|
// not long enough to qualify as a segment
|
||||||
if((sampleDuration / SEGMENT_DURATION) < LAST_SEGMENT_PERCENT) return;
|
if((sampleDuration / SEGMENT_DURATION) < LAST_SEGMENT_PERCENT) return;
|
||||||
|
|
||||||
bitValues = GET_SEGMENT_BITS(streamStarted, segmentIndex, true);
|
bitValues = GET_SEGMENT_BITS(packetStarted, segmentIndex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
packetReceivedBits.push(...bitValues);
|
packetReceivedBits.push(...bitValues);
|
||||||
|
|
||||||
packetUninterlievedBits.push(...removeInterleaving(bitValues));
|
packetUninterlievedBits.push(...removeInterleaving(bitValues));
|
||||||
|
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
|
const errorBitCount = getPacketErrorBitCount();
|
||||||
|
const errorBits = packetUninterlievedBits.slice(0, errorBitCount);
|
||||||
packetDecodedBits.length = 0;
|
packetDecodedBits.length = 0;
|
||||||
for(let i = 0; i < packetUninterlievedBits.length; i += ERROR_CORRECTION_BLOCK_SIZE) {
|
for(let i = 0; i < errorBits.length; i += ERROR_CORRECTION_BLOCK_SIZE) {
|
||||||
const hamming = packetUninterlievedBits.slice(i, i + ERROR_CORRECTION_BLOCK_SIZE);
|
const blockBits = errorBits.slice(i, i + ERROR_CORRECTION_BLOCK_SIZE);
|
||||||
const nibble = hammingToNibble(hamming);
|
if(blockBits.length === ERROR_CORRECTION_BLOCK_SIZE) {
|
||||||
packetDecodedBits.push(...nibble);
|
const nibble = hammingToNibble(blockBits);
|
||||||
|
packetDecodedBits.push(...nibble);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
packetDecodedBits.length = 0;
|
packetDecodedBits.length = 0;
|
||||||
packetDecodedBits.push(...packetUninterlievedBits);
|
packetDecodedBits.push(...packetUninterlievedBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('decoded-data').innerHTML = packetDecodedBits.reduce(bitExpectorReducer(EXPECTED_BITS), '');
|
const maxPacketBits = getPacketBitCount();
|
||||||
document.getElementById('received-data').innerHTML = packetReceivedBits.reduce(bitExpectorReducer(EXPECTED_ENCODED_BITS), '');
|
const maxDataBits = getPacketDataBitCount();
|
||||||
|
|
||||||
|
RECEIVED_PACKET_DECODED_BITS = packetDecodedBits.slice(0, maxDataBits);
|
||||||
|
RECEIVED_PACKET_BITS = packetReceivedBits.slice(0, maxPacketBits);
|
||||||
|
|
||||||
|
updateReceivedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateReceivedData() {
|
||||||
|
const allReceivedBits = [
|
||||||
|
...RECEIVED_STREAM_DECODED_BITS,
|
||||||
|
...RECEIVED_PACKET_DECODED_BITS
|
||||||
|
];
|
||||||
|
const allDecodedBits = [
|
||||||
|
...RECEIVED_STREAM_BITS,
|
||||||
|
...RECEIVED_PACKET_BITS
|
||||||
|
]
|
||||||
const encodedBitCount = EXPECTED_ENCODED_BITS.length;
|
const encodedBitCount = EXPECTED_ENCODED_BITS.length;
|
||||||
const decodedBitCount = EXPECTED_BITS.length;
|
const decodedBitCount = EXPECTED_BITS.length;
|
||||||
const correctEncodedBits = packetReceivedBits.filter((b, i) => i < encodedBitCount && b === EXPECTED_ENCODED_BITS[i]).length;
|
const correctEncodedBits = allReceivedBits.filter((b, i) => i < encodedBitCount && b === EXPECTED_ENCODED_BITS[i]).length;
|
||||||
const correctedDecodedBits = packetDecodedBits.filter((b, i) => i < decodedBitCount && b === EXPECTED_BITS[i]).length;
|
const correctedDecodedBits = allDecodedBits.filter((b, i) => i < decodedBitCount && b === EXPECTED_BITS[i]).length;
|
||||||
|
|
||||||
|
document.getElementById('received-data').innerHTML = allReceivedBits
|
||||||
|
.reduce(
|
||||||
|
bitExpectorReducer(
|
||||||
|
EXPECTED_BITS,
|
||||||
|
getPacketBitCount(),
|
||||||
|
HAMMING_ERROR_CORRECTION ? 7 : 8
|
||||||
|
),
|
||||||
|
'');
|
||||||
|
document.getElementById('decoded-data').innerHTML = allDecodedBits
|
||||||
|
.reduce(
|
||||||
|
bitExpectorReducer(
|
||||||
|
EXPECTED_ENCODED_BITS,
|
||||||
|
getPacketDataBitCount(),
|
||||||
|
8
|
||||||
|
),
|
||||||
|
'');
|
||||||
|
|
||||||
document.getElementById('received-data-error-percent').innerText = (
|
document.getElementById('received-data-error-percent').innerText = (
|
||||||
Math.floor((1 - (correctEncodedBits / packetReceivedBits.length)) * 1000) * 0.1
|
Math.floor((1 - (correctEncodedBits / allReceivedBits.length)) * 10000) * 0.01
|
||||||
).toLocaleString();
|
).toLocaleString();
|
||||||
document.getElementById('decoded-data-error-percent').innerText = (
|
document.getElementById('decoded-data-error-percent').innerText = (
|
||||||
Math.floor((1 - (correctedDecodedBits / packetDecodedBits.length)) * 1000) * 0.1
|
Math.floor((1 - (correctedDecodedBits / allDecodedBits.length)) * 10000) * 0.01
|
||||||
).toLocaleString();
|
).toLocaleString();
|
||||||
document.getElementById('decoded-text').innerHTML = packetDecodedBits.reduce(textExpectorReducer(EXPECTED_TEXT), '');
|
document.getElementById('decoded-text').innerHTML = allDecodedBits.reduce(textExpectorReducer(EXPECTED_TEXT), '');
|
||||||
}
|
}
|
||||||
function bitReducer(all, bit, i) {
|
const bitReducer = (packetBitSize, blockSize, blockCallback) => (all, bit, i) => {
|
||||||
if(i !== 0 && i % 8 === 0) return all + ' ' + bit;
|
const packetIndex = Math.floor(i / packetBitSize);
|
||||||
|
if(i % packetBitSize === 0) {
|
||||||
|
all += `<span class="bit-packet">Packet ${packetIndex}</span>`;
|
||||||
|
}
|
||||||
|
const packetBitIndex = i % packetBitSize;
|
||||||
|
if(packetBitIndex % blockSize === 0) {
|
||||||
|
if(blockCallback) {
|
||||||
|
const blockIndex = Math.floor(packetBitIndex / blockSize);
|
||||||
|
return all + blockCallback(packetIndex, blockIndex) + bit;
|
||||||
|
}
|
||||||
|
return all + ' ' + bit;
|
||||||
|
}
|
||||||
return all + bit;
|
return all + bit;
|
||||||
}
|
}
|
||||||
const bitExpectorReducer = expected => (all, bit, i) => {
|
const bitExpectorReducer = (expected, packetBitSize, blockSize) => (all, bit, i) => {
|
||||||
// if(i === 0) console.log(expected.slice(), all, bit, i);
|
const packetIndex = Math.floor(i / packetBitSize);
|
||||||
|
if(i % packetBitSize === 0) {
|
||||||
|
all += `<span class="bit-packet">Packet ${packetIndex}</span>`;
|
||||||
|
}
|
||||||
|
const packetBitIndex = i % packetBitSize;
|
||||||
|
|
||||||
if(i !== 0 && i % 8 === 0) all += ' ';
|
if(packetBitIndex !== 0 && packetBitIndex % blockSize === 0) all += ' ';
|
||||||
if(i >= expected.length) {
|
if(i >= expected.length) {
|
||||||
all += '<span class="bit-unexpected">';
|
all += '<span class="bit-unexpected">';
|
||||||
} else if(expected[i] !== bit) {
|
} else if(expected[i] !== bit) {
|
||||||
|
|||||||
10
style.css
10
style.css
@@ -21,16 +21,22 @@ body {
|
|||||||
canvas {
|
canvas {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
textarea, .raw-data {
|
.raw-data {
|
||||||
background-color: rgb(41, 59, 10);
|
background-color: rgb(41, 59, 10);
|
||||||
color: rgb(75, 185, 75);
|
color: rgb(75, 185, 75);
|
||||||
width: 250px;
|
width: 250px;
|
||||||
height: 75px;
|
height: 300px;
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
border: 1px solid grey;
|
border: 1px solid grey;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
.bit-packet {
|
||||||
|
display: block;
|
||||||
|
color: yellow;
|
||||||
|
text-decoration: underline;
|
||||||
|
padding: 5px 0 5px 10px
|
||||||
|
}
|
||||||
.bit-wrong {
|
.bit-wrong {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
color: red;
|
color: red;
|
||||||
|
|||||||
Reference in New Issue
Block a user