decode crc-8 on packetization length
This commit is contained in:
@@ -67,7 +67,10 @@
|
|||||||
Error Percent: <span id="received-decoded-bits-error-percent">N/A</span>%<br />
|
Error Percent: <span id="received-decoded-bits-error-percent">N/A</span>%<br />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Decoded Text</h2>
|
<h2>Decoded</h2>
|
||||||
|
Bytes: <span id="received-packet-original-bytes">N/A</span><br>
|
||||||
|
Length CRC-8: <span id="received-packet-original-bytes-crc">N/A</span><br>
|
||||||
|
Text:
|
||||||
<div class="raw-data" id="decoded-text"></div><br />
|
<div class="raw-data" id="decoded-text"></div><br />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
91
index.js
91
index.js
@@ -12,6 +12,7 @@ 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
|
||||||
const MAXIMUM_PACKETIZATION_SIZE_BITS = 16;
|
const MAXIMUM_PACKETIZATION_SIZE_BITS = 16;
|
||||||
|
const CRC_BIT_COUNT = 8;
|
||||||
|
|
||||||
// bits after error correction is applied
|
// bits after error correction is applied
|
||||||
let RECEIVED_STREAM_DECODED_BITS = [];
|
let RECEIVED_STREAM_DECODED_BITS = [];
|
||||||
@@ -391,6 +392,14 @@ function calcCrc(
|
|||||||
}
|
}
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
function crc(bytes, bitCount) {
|
||||||
|
switch(bitCount) {
|
||||||
|
case 8: return crc8(bytes);
|
||||||
|
case 16: return crc16(bytes);
|
||||||
|
case 32: return crc32(bytes);
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
function crc8(bytes) { return calcCrc(bytes, 8, 0x07); }
|
function crc8(bytes) { return calcCrc(bytes, 8, 0x07); }
|
||||||
function crc16(bytes) {
|
function crc16(bytes) {
|
||||||
return calcCrc(
|
return calcCrc(
|
||||||
@@ -598,6 +607,7 @@ function logSent(text) {
|
|||||||
sentDataTextArea.value += text + '\n';
|
sentDataTextArea.value += text + '\n';
|
||||||
sentDataTextArea.scrollTop = sentDataTextArea.scrollHeight;
|
sentDataTextArea.scrollTop = sentDataTextArea.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendBytes(bytes) {
|
function sendBytes(bytes) {
|
||||||
const byteCount = bytes.length;
|
const byteCount = bytes.length;
|
||||||
if(byteCount === 0) {
|
if(byteCount === 0) {
|
||||||
@@ -616,7 +626,13 @@ function sendBytes(bytes) {
|
|||||||
|
|
||||||
// packetization headers
|
// packetization headers
|
||||||
// data length
|
// data length
|
||||||
bits.unshift(...intToBits(bytes.length, MAXIMUM_PACKETIZATION_SIZE_BITS));
|
const dataLengthBits = numberToBits(bytes.length, MAXIMUM_PACKETIZATION_SIZE_BITS);
|
||||||
|
// crc on data length
|
||||||
|
const dataLengthCrcBits = numberToBits(crc(bitsToBytes(dataLengthBits), CRC_BIT_COUNT), CRC_BIT_COUNT);
|
||||||
|
|
||||||
|
// prefix with headers
|
||||||
|
bits.unshift(...dataLengthBits, ...dataLengthCrcBits);
|
||||||
|
|
||||||
const bitCount = bits.length;
|
const bitCount = bits.length;
|
||||||
|
|
||||||
SENT_TRANSFER_BITS.length = 0;
|
SENT_TRANSFER_BITS.length = 0;
|
||||||
@@ -725,7 +741,7 @@ function getPacketByteCount() {
|
|||||||
return 2 ** PACKET_SIZE_BITS;
|
return 2 ** PACKET_SIZE_BITS;
|
||||||
}
|
}
|
||||||
function getPacketizationBitCount(bitCount) {
|
function getPacketizationBitCount(bitCount) {
|
||||||
return bitCount + MAXIMUM_PACKETIZATION_SIZE_BITS;
|
return bitCount + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
|
||||||
}
|
}
|
||||||
function getPacketBitCount() {
|
function getPacketBitCount() {
|
||||||
return getPacketByteCount() * 8;
|
return getPacketByteCount() * 8;
|
||||||
@@ -1141,6 +1157,19 @@ function updateReceivedData() {
|
|||||||
...RECEIVED_PACKET_DECODED_BITS
|
...RECEIVED_PACKET_DECODED_BITS
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// get packet data before removing decoded bits
|
||||||
|
const transmissionByteCount = parseTransmissionByteCount(allDecodedBits);
|
||||||
|
const transmissionByteCountCrc = parseTransmissionByteCountCrc(allDecodedBits)
|
||||||
|
const transmissionByteCountActualCrc = crc(
|
||||||
|
bitsToBytes(
|
||||||
|
numberToBits(
|
||||||
|
transmissionByteCount,
|
||||||
|
MAXIMUM_PACKETIZATION_SIZE_BITS
|
||||||
|
)
|
||||||
|
), CRC_BIT_COUNT
|
||||||
|
);
|
||||||
|
const trustedLength = transmissionByteCountCrc === transmissionByteCountActualCrc;
|
||||||
|
|
||||||
// reduce all decoded bits based on original data sent
|
// reduce all decoded bits based on original data sent
|
||||||
allDecodedBits = removeDecodedHeadersAndPadding(allDecodedBits);
|
allDecodedBits = removeDecodedHeadersAndPadding(allDecodedBits);
|
||||||
|
|
||||||
@@ -1184,6 +1213,13 @@ function updateReceivedData() {
|
|||||||
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
|
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
|
||||||
),
|
),
|
||||||
'');
|
'');
|
||||||
|
document.getElementById('received-packet-original-bytes').innerText = transmissionByteCount.toLocaleString();
|
||||||
|
const packetCrc = document.getElementById('received-packet-original-bytes-crc');
|
||||||
|
packetCrc.innerText = '0x' + asHex(2)(transmissionByteCountCrc);
|
||||||
|
packetCrc.className = trustedLength ? 'bit-correct' : 'bit-wrong';
|
||||||
|
if(!trustedLength) {
|
||||||
|
packetCrc.innerText += ' (Expected 0x' + asHex(2)(transmissionByteCountActualCrc) + ')';
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('received-encoded-bits-error-percent').innerText = (
|
document.getElementById('received-encoded-bits-error-percent').innerText = (
|
||||||
Math.floor((1 - (correctEncodedBits / allEncodedBits.length)) * 10000) * 0.01
|
Math.floor((1 - (correctEncodedBits / allEncodedBits.length)) * 10000) * 0.01
|
||||||
@@ -1196,6 +1232,18 @@ function updateReceivedData() {
|
|||||||
).toLocaleString();
|
).toLocaleString();
|
||||||
document.getElementById('decoded-text').innerHTML = allDecodedBits.reduce(textExpectorReducer(SENT_ORIGINAL_TEXT), '');
|
document.getElementById('decoded-text').innerHTML = allDecodedBits.reduce(textExpectorReducer(SENT_ORIGINAL_TEXT), '');
|
||||||
}
|
}
|
||||||
|
function asHex(length) {
|
||||||
|
return (number) => number.toString(16).padStart(length, '0').toUpperCase();
|
||||||
|
}
|
||||||
|
function parseTransmissionByteCountCrc(bits) {
|
||||||
|
const offset = MAXIMUM_PACKETIZATION_SIZE_BITS;
|
||||||
|
bits = bits.slice(offset, offset+8);
|
||||||
|
return bitsToInt(bits, 8);
|
||||||
|
}
|
||||||
|
function parseTransmissionByteCount(bits) {
|
||||||
|
bits = bits.slice(0, MAXIMUM_PACKETIZATION_SIZE_BITS);
|
||||||
|
return bitsToInt(bits, MAXIMUM_PACKETIZATION_SIZE_BITS);
|
||||||
|
}
|
||||||
function removeEncodedPadding(bits) {
|
function removeEncodedPadding(bits) {
|
||||||
const sizeBits = MAXIMUM_PACKETIZATION_SIZE_BITS;
|
const sizeBits = MAXIMUM_PACKETIZATION_SIZE_BITS;
|
||||||
const dataSize = ERROR_CORRECTION_DATA_SIZE;
|
const dataSize = ERROR_CORRECTION_DATA_SIZE;
|
||||||
@@ -1212,14 +1260,17 @@ function removeEncodedPadding(bits) {
|
|||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get bits representing the size
|
// get header bits representing the size
|
||||||
let dataSizeBits = [];
|
let dataSizeBits = [];
|
||||||
|
let headerBitCount = MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
|
||||||
|
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
for(i = 0; i < blocksNeeded; i++) {
|
for(i = 0; i < blocksNeeded; i++) {
|
||||||
const block = bits.slice(i * blockSize, (i + 1) * blockSize);
|
const block = bits.slice(i * blockSize, (i + 1) * blockSize);
|
||||||
dataSizeBits.push(...hammingToNibble(block));
|
dataSizeBits.push(...hammingToNibble(block));
|
||||||
}
|
}
|
||||||
dataSizeBits.length = sizeBits;
|
dataSizeBits.length = sizeBits;
|
||||||
|
headerBitCount = Math.ceil(headerBitCount / ERROR_CORRECTION_DATA_SIZE) * ERROR_CORRECTION_BLOCK_SIZE;
|
||||||
} else {
|
} else {
|
||||||
dataSizeBits = bits.slice(0, sizeBits);
|
dataSizeBits = bits.slice(0, sizeBits);
|
||||||
}
|
}
|
||||||
@@ -1227,7 +1278,7 @@ function removeEncodedPadding(bits) {
|
|||||||
const dataByteCount = bitsToInt(dataSizeBits, sizeBits);
|
const dataByteCount = bitsToInt(dataSizeBits, sizeBits);
|
||||||
|
|
||||||
// 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) + sizeBits;
|
const totalBits = (dataByteCount * 8) + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
|
||||||
let encodingBitCount = totalBits;
|
let encodingBitCount = totalBits;
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
const blocks = Math.ceil(encodingBitCount / dataSize);
|
const blocks = Math.ceil(encodingBitCount / dataSize);
|
||||||
@@ -1248,8 +1299,9 @@ function removeDecodedHeadersAndPadding(bits) {
|
|||||||
if(bits.length >= sizeBits) {
|
if(bits.length >= sizeBits) {
|
||||||
bitCount = bitsToInt(bits.slice(0, sizeBits), sizeBits);
|
bitCount = bitsToInt(bits.slice(0, sizeBits), sizeBits);
|
||||||
}
|
}
|
||||||
// remove size header
|
// remove size and crc header
|
||||||
bits.splice(0, sizeBits);
|
bits.splice(0, sizeBits + CRC_BIT_COUNT);
|
||||||
|
|
||||||
// remove excessive bits
|
// remove excessive bits
|
||||||
bits.splice(bitCount * 8);
|
bits.splice(bitCount * 8);
|
||||||
return bits;
|
return bits;
|
||||||
@@ -1361,20 +1413,19 @@ function bitsToInt(bits, bitLength) {
|
|||||||
// parse as int
|
// parse as int
|
||||||
return parseInt(bitString, 2);
|
return parseInt(bitString, 2);
|
||||||
}
|
}
|
||||||
function intToBits(int, bitLength) {
|
function intToBytes(int, bitLength) {
|
||||||
// max number for bit length
|
const byteCount = Math.ceil(bitLength/8);
|
||||||
const max = Math.pow(2, bitLength) - 1;
|
const bytes = [];
|
||||||
// overflow numbers too high
|
for(let i = 0; i < byteCount; i++) {
|
||||||
const value = (int & max);
|
bytes.push((int >> (8 * (byteCount - 1 - i))) & 0xFF);
|
||||||
return value
|
}
|
||||||
// convert to bit string
|
return bytes;
|
||||||
.toString(2)
|
}
|
||||||
// prefix with zeros to fill bit length
|
function numberToBits(number, bitLength) {
|
||||||
.padStart(bitLength, '0')
|
const bits = [];
|
||||||
// convert to array
|
for(let i = bitLength - 1; i >= 0; i--)
|
||||||
.split('')
|
bits.push((number >> i) & 1);
|
||||||
// convert strings to numbers
|
return bits;
|
||||||
.map(Number);
|
|
||||||
}
|
}
|
||||||
function bytesToText(bytes, encoding='utf-8') {
|
function bytesToText(bytes, encoding='utf-8') {
|
||||||
return new TextDecoder(encoding).decode(bytes);
|
return new TextDecoder(encoding).decode(bytes);
|
||||||
|
|||||||
Reference in New Issue
Block a user